使用Spring的BeanFactoryPostProcessor扩展点完成自定义注解扫描

使用Spring的BeanFactoryPostProcessor扩展点完成自定义注解扫描

一、概述

本次实验是上一次https://blog.csdn.net/2301_80749359/article/details/157651601?fromshare=blogdetail&sharetype=blogdetail&sharerId=157651601&sharerefer=PC&sharesource=2301_80749359&sharefrom=from_link的扩展,只是加了自定义注解较为方便。

二、具体步骤

2.1创建自定义注解

java 复制代码
package com.itheima.ano;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

//设定在哪些类型上可以使用
@Target(ElementType.TYPE)
//设定作用的范围
@Retention(RetentionPolicy.RUNTIME)
public @interface MyComponent {
//    配置value属性,以代表bean的名字
    String value();
}

2.2引入扫描注解包的工具类

java 复制代码
package com.itheima.utils;

import com.itheima.ano.MyComponent;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.util.ClassUtils;

import java.lang.annotation.Annotation;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class BaseClassScanUtils {

    //设置资源规则
    private static final String RESOURCE_PATTERN = "/**/*.class";

    public static Map<String, Class> scanMyComponentAnnotation(String basePackage) {

        //创建容器存储使用了指定注解的Bean字节码对象
        Map<String, Class> annotationClassMap = new HashMap<String, Class>();

        //spring工具类,可以获取指定路径下的全部类
        ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
        try {
            String pattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
                    ClassUtils.convertClassNameToResourcePath(basePackage) + RESOURCE_PATTERN;
            Resource[] resources = resourcePatternResolver.getResources(pattern);
            //MetadataReader 的工厂类
            MetadataReaderFactory refractory = new CachingMetadataReaderFactory(resourcePatternResolver);
            for (Resource resource : resources) {
                //用于读取类信息
                MetadataReader reader = refractory.getMetadataReader(resource);
                //扫描到的class
                String classname = reader.getClassMetadata().getClassName();
                Class<?> clazz = Class.forName(classname);
                //判断是否属于指定的注解类型
                if(clazz.isAnnotationPresent(MyComponent.class)){
                    //获得注解对象
                    MyComponent annotation = clazz.getAnnotation(MyComponent.class);
                    //获得属value属性值
                    String beanName = annotation.value();
                    //判断是否为""
                    if(beanName!=null&&!beanName.equals("")){
                        //存储到Map中去
                        annotationClassMap.put(beanName,clazz);
                        continue;
                    }

                    //如果没有为"",那就把当前类的类名作为beanName
                    annotationClassMap.put(clazz.getSimpleName(),clazz);

                }
            }
        } catch (Exception exception) {
        }

        return annotationClassMap;
    }

    public static void main(String[] args) {
        Map<String, Class> stringClassMap = scanMyComponentAnnotation("com.itheima");
        System.out.println(stringClassMap);
    }
}

2.3利用工具类扫描包

利用工具类扫描包(包括该包及其子包下)中带有@MyComponent注释的类,然后遍历Map进行相关的操作(具体见代码注释)

java 复制代码
package com.itheima.processor;

import com.itheima.utils.BaseClassScanUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.beans.factory.support.RootBeanDefinition;

import java.util.Map;

public class MyComponentBeanFactoryPostProcessor implements BeanDefinitionRegistryPostProcessor {
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
//先是使用扫描的工具进行扫描
       Map<String, Class> myComponentAnnotationMap = BaseClassScanUtils.scanMyComponentAnnotation("com.itheima");
//       然后是遍历这个map,得到bbeanDefinition
        myComponentAnnotationMap.forEach((beanName,beanClass)->{
//            先是获取到全限制名(转为String类型的)
            String className = beanClass.getName();
//            然后是定义bbeanDefinition
            BeanDefinition beanDefinition = new RootBeanDefinition();
            beanDefinition.setBeanClassName(className);
//            再是进行注册,这就是放到单例池单中了
            beanDefinitionRegistry.registerBeanDefinition(beanName,beanDefinition);

        });
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {

    }
}

2.4测试:

java 复制代码
package com.itheima.test;

import com.alibaba.druid.pool.DruidDataSource;
import com.itheima.beans.OthrerBean;
import com.itheima.beans.Xxxbean;
import com.itheima.dao.impl.UserDaoImpl;
import com.itheima.dao.personDao;
import com.itheima.service.UserService;
import com.mysql.jdbc.Connection;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import javax.xml.bind.annotation.XmlAccessOrder;
import java.io.IOException;
import java.io.InputStream;
import java.sql.DriverManager;

public class BeanFactoryTest {
    public static void main(String[] args) throws Exception {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext_beanfac.xml");
        OthrerBean othrerBean = (OthrerBean) applicationContext.getBean("otherBean");
        System.out.println(othrerBean);
    }
}

结果:

相关推荐
golang学习记5 小时前
Go 结构化日志新宠:`slog` 入门与实战指南(附避坑秘籍)
后端
Java爱好狂.5 小时前
Redis高级笔记:原理+集群+应用+拓展+源码
java·数据库·redis·spring·java面试·后端开发·java八股文
lee_curry5 小时前
jvm中的内存模型
java·jvm·内存模型
tltwuyulw5 小时前
Java的函数式编程(三)
java·后端
ch.ju5 小时前
Java程序设计(第3版)第二章——嵌套循环
java
直奔標竿5 小时前
Java开发者AI转型第九课!突破知识边界!企业级 RAG (检索增强生成) 核心架构与 ETL 管道初探
java·开发语言·人工智能·后端·spring
skilllite作者5 小时前
SkillLite Rust 沙箱与 AI Agent 自进化实战指南
开发语言·人工智能·后端·架构·rust
Java女侠_9年实战5 小时前
为什么会丢精度?BigDecimal正确用法
后端
程途知微5 小时前
ThreadLocal底层原理
java·后端
宝耶5 小时前
[特殊字符] 操作日志模块复习笔记
java·开发语言·jvm