使用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);
    }
}

结果:

相关推荐
Oneslide3 小时前
机械革命 单系统纯净重装Ubuntu(全盘覆盖,清空原有Windows)
后端
GetcharZp3 小时前
告别OOM!用Go+libvips实现30000×50000超大图片的流式瓦片服务
后端·go
IT_陈寒4 小时前
JavaScript项目实战经验分享
前端·人工智能·后端
用户47949283569154 小时前
6w star,GitHub 趋势第一的 Ponytail,这个agent插件到底在火什么
前端·后端
吃饱了得干活5 小时前
Spring Cloud Gateway 微服务网关:路由、断言、过滤器
java·spring cloud
神奇小汤圆5 小时前
2026一线大厂Java八股文精选(附答案,高质量整理)
后端
Warson_L6 小时前
LangGraph入门学习资料
后端
神奇小汤圆6 小时前
Spring Boot → Solon 注解迁移实战指南:一张对照表说清楚
后端
kfaino7 小时前
码农的AI翻身(四)你好,我叫 Attention
人工智能·后端
lwx572807 小时前
探秘InnoDB:搞懂它的内存、线程、磁盘与日志刷盘策略
java·后端