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

结果:

相关推荐
代码改善世界15 小时前
【matlab初阶】matlab入门知识
android·java·matlab
卓怡学长15 小时前
m315基于java的水果网上商城的开发与设计
java·数据库·spring·tomcat·maven·intellij-idea
小陈工15 小时前
Python Web开发入门(十一):RESTful API设计原则与最佳实践——让你的API既优雅又好用
开发语言·前端·人工智能·后端·python·安全·restful
执笔画流年呀15 小时前
7大排序算法
java·算法·排序算法
小阳哥AI工具15 小时前
Seedance 2.0使用真人参考图生成视频的方法
后端
IeE1QQ3GT15 小时前
使用ASP.NET Abstractions增强ASP.NET应用程序的可测试性
后端·asp.net
zdl68616 小时前
springboot+全局异常处理
java·spring boot·spring
2301_7717172116 小时前
Jackson的使用方法详解
java·服务器·前端
Full Stack Developme16 小时前
SpringBoot多线程池配置
spring boot·后端·firefox
立莹Sir17 小时前
Spring Bean生命周期设计思想与源码深度剖析:从表象到本质的全面升级
java·spring·rpc