高级Spring之BeanFactory 后处理器

    老样子,直接上代码演示,准备一个干净的容器:


        // ⬇️GenericApplicationContext 是一个【干净】的容器
        GenericApplicationContext context = new GenericApplicationContext();
        //注册configBean
        context.registerBean("config", Config.class);

        // ⬇️初始化容器
        context.refresh();

        for (String name : context.getBeanDefinitionNames()) {
            System.out.println(name);
        }

        // ⬇️销毁容器
        context.close();

   config类:

@Configuration
@ComponentScan("com.tangyuan.a05.component")
public class Config {
    @Bean
    public Bean1 bean1() {
        return new Bean1();
    }

    @Bean
    public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource) {
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(dataSource);
        return sqlSessionFactoryBean;
    }

    @Bean(initMethod = "init")
    public DruidDataSource dataSource() {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setUrl("jdbc:mysql://localhost:3306/shopping");
        dataSource.setUsername("root");
        dataSource.setPassword("1234");
        return dataSource;
    }

  
}

       按照代码演示,这里一共有5个Bean,一个Config,一个component包下面的Bean,还有Config类管理的三个bean

     来看输出结果:

     为什么只输出了我们自己编程添加的bean?因为@ComponentScan组件扫描没有生效,@Bean注解也没有生效。

      我们要怎么样才能解析这些注解呢?使用Bean工厂后处理器 

//解析的注解:@ComponentScan @Bean @Import @ImportResource  
context.registerBean(ConfigurationClassPostProcessor.class);

 这时,我们来看输出结果:

 

mapper层接口的扫描: 

 context.registerBean(MapperScannerConfigurer.class, bd -> { // @MapperScanner           
        bd.getPropertyValues().add("basePackage", "com.tangyuan.a05.mapper");
        });

 输出结果如下:

 

模拟@ComponentScan注解的解析:

       //查询类上是否有 ComponentScan注解
            ComponentScan componentScan = AnnotationUtils.findAnnotation(Config.class, ComponentScan.class);
            if (componentScan != null) {
                for (String p : componentScan.basePackages()) {
                   //获取包名
                    System.out.println(p);
                    //转换格式
                    // com.tangyuan.a05.component -> classpath*:com/tangyuan/a05/component/**/*.class
                    String path = "classpath*:" + p.replace(".", "/") + "/**/*.class";
                    System.out.println(path);
                   //读取类上面的源信息
                    CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();
                   //通过通配符获取资源
                    Resource[] resources = new PathMatchingResourcePatternResolver().getResources(path);
                    //分析Component注解,生成bean的名称
                    AnnotationBeanNameGenerator generator = new AnnotationBeanNameGenerator();
                    for (Resource resource : resources) {
                        // System.out.println(resource);
                        //信息存放位置
                        MetadataReader reader = factory.getMetadataReader(resource);
                        // System.out.println("类名:" + reader.getClassMetadata().getClassName());
                       //读取注解信息
                        AnnotationMetadata annotationMetadata = reader.getAnnotationMetadata();
                        // System.out.println("是否加了 @Component:" + annotationMetadata.hasAnnotation(Component.class.getName()));
                        // System.out.println("是否加了 @Component 派生:" + annotationMetadata.hasMetaAnnotation(Component.class.getName()));
                      
                         //如果直接加了 ComponentScan注解或者间接加了 ComponentScan注解
                       if (annotationMetadata.hasAnnotation(Component.class.getName())
                            || annotationMetadata.hasMetaAnnotation(Component.class.getName())) {
                            //创建BeanDefinition
                            AbstractBeanDefinition bd = BeanDefinitionBuilder
                                    .genericBeanDefinition(reader.getClassMetadata().getClassName())
                                    .getBeanDefinition();
                           //生成bean的名称
                            String name = generator.generateBeanName(bd, beanFactory);
                            //添加到bean工厂中
                            beanFactory.registerBeanDefinition(name, bd);
                        }
                    }
                }
            }

输出结果:

     在这里,我们可以将代码抽取出来,整理为一个独立的bean工厂后处理器:

//分析ComponentScan注解,并作Bean定义的补充
public class ComponentScanPostProcessor implements BeanDefinitionRegistryPostProcessor {
    @Override // context.refresh
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {

    }

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanFactory) throws BeansException {
        try {
           //查询类上是否有 ComponentScan注解
            ComponentScan componentScan = AnnotationUtils.findAnnotation(Config.class, ComponentScan.class);
            if (componentScan != null) {
                for (String p : componentScan.basePackages()) {
                   //获取包名
                    System.out.println(p);
                    //转换格式
                    // com.tangyuan.a05.component -> classpath*:com/tangyuan/a05/component/**/*.class
                    String path = "classpath*:" + p.replace(".", "/") + "/**/*.class";
                    System.out.println(path);
                   //读取类上面的源信息
                    CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();
                   //通过通配符获取资源
                    Resource[] resources = new PathMatchingResourcePatternResolver().getResources(path);
                    //分析Component注解,生成bean的名称
                    AnnotationBeanNameGenerator generator = new AnnotationBeanNameGenerator();
                    for (Resource resource : resources) {
                        // System.out.println(resource);
                        //信息存放位置
                        MetadataReader reader = factory.getMetadataReader(resource);
                        // System.out.println("类名:" + reader.getClassMetadata().getClassName());
                       //读取注解信息
                        AnnotationMetadata annotationMetadata = reader.getAnnotationMetadata();
                        // System.out.println("是否加了 @Component:" + annotationMetadata.hasAnnotation(Component.class.getName()));
                        // System.out.println("是否加了 @Component 派生:" + annotationMetadata.hasMetaAnnotation(Component.class.getName()));
                      
                         //如果直接加了 ComponentScan注解或者间接加了 ComponentScan注解
                       if (annotationMetadata.hasAnnotation(Component.class.getName())
                            || annotationMetadata.hasMetaAnnotation(Component.class.getName())) {
                            //创建BeanDefinition
                            AbstractBeanDefinition bd = BeanDefinitionBuilder
                                    .genericBeanDefinition(reader.getClassMetadata().getClassName())
                                    .getBeanDefinition();
                           //生成bean的名称
                            String name = generator.generateBeanName(bd, beanFactory);
                            //添加到bean工厂中
                            beanFactory.registerBeanDefinition(name, bd);
                        }
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

  使用时,将Bean工厂处理器注册即可:

context.registerBean(ComponentScanPostProcessor.class); // 解析 @ComponentScan

   注:配置类充当的是工厂的角色,配置类中用@Bean标记的方法角色工厂方法
 

解析 @Bean

//@Bean注解
public class AtBeanPostProcessor implements BeanDefinitionRegistryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {

    }

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanFactory) throws BeansException {
        try {
            CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();
            //读取配置类的信息
            MetadataReader reader = factory.getMetadataReader(new ClassPathResource("com/tangyuan/a05/Config.class"));
            //获取被注解标注的方法信息
            Set<MethodMetadata> methods = reader.getAnnotationMetadata().getAnnotatedMethods(Bean.class.getName());
            for (MethodMetadata method : methods) {
                System.out.println(method);
                  //获取@Bean注解的属性
                String initMethod = method.getAnnotationAttributes(Bean.class.getName()).get("initMethod").toString();
              //创建  BeanDefinitionBuilder 对象(用工厂方法来创建)
                BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition();
               //工厂方法名字
                builder.setFactoryMethodOnBean(method.getMethodName(), "config");
              //指定装配模式
                builder.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);
                if (initMethod.length() > 0) {
                  //初始化方法名字
                    builder.setInitMethodName(initMethod);
                }
                AbstractBeanDefinition bd = builder.getBeanDefinition();
                   //注册
                beanFactory.registerBeanDefinition(method.getMethodName(), bd);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

  手动添加mapper接口:

@Bean
    public MapperFactoryBean<Mapper1> mapper1(SqlSessionFactory sqlSessionFactory) {
        MapperFactoryBean<Mapper1> factory = new MapperFactoryBean<>(Mapper1.class);
        factory.setSqlSessionFactory(sqlSessionFactory);
        return factory;
    }

    @Bean
    public MapperFactoryBean<Mapper2> mapper2(SqlSessionFactory sqlSessionFactory) {
        MapperFactoryBean<Mapper2> factory = new MapperFactoryBean<>(Mapper2.class);
        factory.setSqlSessionFactory(sqlSessionFactory);
        return factory;
    }

  缺点:不能批量添加

//mapper接口
public class MapperPostProcessor implements BeanDefinitionRegistryPostProcessor {

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanFactory) throws BeansException {
        try {
            //通配符解析器
            PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
            Resource[] resources = resolver.getResources("classpath:com/tangyuan/a05/mapper/**/*.class");
            //读取类的源信息
            AnnotationBeanNameGenerator generator = new AnnotationBeanNameGenerator();
           //名字生成器
            CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();
            for (Resource resource : resources) {
              //读取信息
                MetadataReader reader = factory.getMetadataReader(resource);
               //读取类源信息
                ClassMetadata classMetadata = reader.getClassMetadata();
                //判断是否是接口
                if (classMetadata.isInterface()) {
                //定义BeanDefinition
                    AbstractBeanDefinition bd = BeanDefinitionBuilder.genericBeanDefinition(MapperFactoryBean.class)
                               //给构造方法设置参数值
                            .addConstructorArgValue(classMetadata.getClassName())
                            .setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE)
                            .getBeanDefinition();
                    //根据mapper接口生成BeanDefinition
                    AbstractBeanDefinition bd2 = BeanDefinitionBuilder.genericBeanDefinition(classMetadata.getClassName()).getBeanDefinition();
                  //根据bd2生成名字
                 String name = generator.generateBeanName(bd2, beanFactory);
                 //注册
                    beanFactory.registerBeanDefinition(name, bd);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

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

    }
}

知识点:

  • ConfigurationClassPostProcessor 可以解析

    • @ComponentScan

    • @Bean

    • @Import

    • @ImportResource

  • MapperScannerConfigurer 可以解析

    • Mapper 接口

收获💡

  1. @ComponentScan, @Bean, @Mapper 等注解的解析属于核心容器(即 BeanFactory)的扩展功能

  2. 这些扩展功能由不同的 BeanFactory 后处理器来完成,其实主要就是补充了一些 bean 定义

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值