【第五讲】BeanFactory 后处理器

第五讲 BeanFactory 后处理器

  1. BeanFactory 后处理器的作用:为BeanFactory提供扩展
  2. 常见的BeanFactory后处理器


定义 Bean1Bean2Mapper1Mapper2Config 5个类

  • Bean2上面加上@Component
  • Config上加@Component注解和@ComponentScan注解,Config中通过@Bean注解定义Bean1
  • Mapper1Mapper2上加@Mapper注解

Config

@Component
@ComponentScan("com/example/spring01/com/a05")
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://120.77.215.102:3306/czctest?characterEncoding=utf-8");
        dataSource.setUsername("root");
        dataSource.setPassword("czc521190");
        return dataSource;
    }
}

Bean1和Bean2

@Slf4j
public class Bean1 {

    public Bean1(){
        log.info("我是被 spring 管理啦");
    }
}
-----------------------------------------
@Component
@Slf4j
public class Bean2 {
    public Bean2(){
        log.info("我是被 spring 管理啦");
    }
}

Mapper1和Mapper2

@Mapper
public interface Mapper1 {
}
----------------------------
@Mapper
public interface Mapper2 {
}
    

TestBeanFactoryPostProcessors

public class TestBeanFactoryPostProcessors {

    public static void main(String[] args) {
        // GenericApplicationContext 是一个【干净】的容器,默认不会添加任何后处理器,方便做测试
        GenericApplicationContext context = new GenericApplicationContext();

        context.registerBean("config",Config.class);
        // 解析@ComponentScan、@Bean、@Import、@ImportResource注解
        context.registerBean(ConfigurationClassPostProcessor.class);
        // 添加Bean工厂后处理器MapperScannerConfigurer,解析@MapperScan注解
        context.registerBean(MapperScannerConfigurer.class,db->{
            db.getPropertyValues().add("basePackage","com/example/spring01/com/a05/mapper");
        });

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


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

        // 容器销毁
        context.close();
    }

}

在这里插入图片描述

结论

  1. @Component@Bean对应的Bean工厂后处理器是ConfigurationClassPostProcessor
  2. @MapperScan对应的Bean工厂后处理器是MapperScannerConfigurer
ComponentScan将加了
@Controller,@Repository,@Service,@Component注解的类注册到spring容器中

模拟ComponentScan实现

public static void main(String[] args) throws Exception {
    // GenericApplicationContext 是一个【干净】的容器,默认不会添加任何后处理器,方便做测试
    GenericApplicationContext context = new GenericApplicationContext();
    context.registerBean("config",Config.class);
    // 模拟@ComponentScan
    ComponentScan componentScan = AnnotationUtils.findAnnotation(Config.class, ComponentScan.class);
    if(componentScan != null){
        for (String s : componentScan.basePackages()) {
            System.out.println(s);
            //com.example.spring01.com.a05.component -> classpath*:com/example/spring01/com/a05/component/**/*.class
            String path =  "classpath*:" + s.replace(".","/") + "/**/*.class";
            System.out.println(path);
            CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();
            Resource[] resources = context.getResources(path);
            AnnotationBeanNameGenerator generator = new AnnotationBeanNameGenerator();
            for (Resource resource : resources) {
                System.out.println("resource---"+resource);
                MetadataReader reader = factory.getMetadataReader(resource);
                AnnotationMetadata annotationMetadata = reader.getAnnotationMetadata();
                System.out.println("类名:"+ reader.getClassMetadata().getClassName());
                System.out.println("是否加了 @Component 注解:" + annotationMetadata.hasAnnotation(Component.class.getName()));
                System.out.println("是否加了 @Component派生 注解:" + annotationMetadata.hasMetaAnnotation(Component.class.getName()));
                // 如果加了@Component 注解 或在 @Component派生 注解
                if(annotationMetadata.hasAnnotation(Component.class.getName() ) || annotationMetadata.hasMetaAnnotation(Component.class.getName())){
                    // 生成 beanDefinition
                    AbstractBeanDefinition bd =
                        BeanDefinitionBuilder.genericBeanDefinition(reader.getClassMetadata().getClassName()).getBeanDefinition();
                    DefaultListableBeanFactory beanFactory = context.getDefaultListableBeanFactory();
                    String beanName = generator.generateBeanName(bd, beanFactory);
                    beanFactory.registerBeanDefinition(beanName,bd);
                }
            }
        }
    }
    // 初始化容器
    context.refresh();

    for (String name:context.getBeanDefinitionNames()){
        System.out.println("name--:"+name);
    }
    // 容器销毁
    context.close();
}

自定义一个后处理器ComponentScanPostProcessor, 来解析@Component

实现BeanFactoryPostProcessor两处修改

  1. context.getResources(path) -> new PathMatchingResourcePatternResolver().getResources(path);
    
  2. DefaultListableBeanFactory beanFactory = context.getDefaultListableBeanFactory();
    -------------
    if(configurableListableBeanFactory instanceof DefaultListableBeanFactory){
        DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) configurableListableBeanFactory;
        String beanName = generator.generateBeanName(bd, beanFactory);
        beanFactory.registerBeanDefinition(beanName,bd);
    }
    
public class ComponentScanPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
        try {
            // 模拟@ComponentScan
            ComponentScan componentScan = AnnotationUtils.findAnnotation(Config.class, ComponentScan.class);
            if(componentScan != null){
                for (String s : componentScan.basePackages()) {
                    System.out.println(s);
                    //com.example.spring01.com.a05.component -> classpath*:com/example/spring01/com/a05/component/**/*.class
                    String path =  "classpath*:" + s.replace(".","/") + "/**/*.class";
                    System.out.println(path);
                    CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();
                    Resource[] resources = new PathMatchingResourcePatternResolver().getResources(path);
                    AnnotationBeanNameGenerator generator = new AnnotationBeanNameGenerator();
                    for (Resource resource : resources) {
                        System.out.println("resource---"+resource);
                        MetadataReader reader = factory.getMetadataReader(resource);
                        AnnotationMetadata annotationMetadata = reader.getAnnotationMetadata();
                        System.out.println("类名:"+ reader.getClassMetadata().getClassName());
                        System.out.println("是否加了 @Component 注解:" + annotationMetadata.hasAnnotation(Component.class.getName()));
                        System.out.println("是否加了 @Component派生 注解:" + annotationMetadata.hasMetaAnnotation(Component.class.getName()));
                        // 如果加了@Component 注解 或在 @Component派生 注解
                        if(annotationMetadata.hasAnnotation(Component.class.getName() ) || annotationMetadata.hasMetaAnnotation(Component.class.getName())){
                            // 生成 beanDefinition
                            AbstractBeanDefinition bd =
                                    BeanDefinitionBuilder.genericBeanDefinition(reader.getClassMetadata().getClassName()).getBeanDefinition();

                            if(configurableListableBeanFactory instanceof DefaultListableBeanFactory){
                                DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) configurableListableBeanFactory;
                                String beanName = generator.generateBeanName(bd, beanFactory);
                                beanFactory.registerBeanDefinition(beanName,bd);
                            }

                        }
                    }
                }
            }
        }catch (IOException e) {
            e.printStackTrace();
        }
    }
}

引用自己写的后处理器

public static void main(String[] args) throws Exception {
    // GenericApplicationContext 是一个【干净】的容器,默认不会添加任何后处理器,方便做测试
    GenericApplicationContext context = new GenericApplicationContext();
    context.registerBean("config",Config.class);

    context.registerBean(ComponentScanPostProcessor.class);
    // 初始化容器
    context.refresh();

    for (String name:context.getBeanDefinitionNames()){
        System.out.println("name--:"+name);
    }
    // 容器销毁
    context.close();
}

自定义一个CandyComponentScanPostProcessor 来解析@Component注解

实现BeanDefinitionRegistryPostProcessor

两次修改

  1. context.getResources(path) -> new PathMatchingResourcePatternResolver().getResources(path);
    
  2. 去掉DefaultListableBeanFactory beanFactory = context.getDefaultListableBeanFactory();
    
public class CandyComponentScanPostProcessor implements BeanDefinitionRegistryPostProcessor {
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanFactory) throws BeansException {
       try {
           // 模拟@ComponentScan
           ComponentScan componentScan = AnnotationUtils.findAnnotation(Config.class, ComponentScan.class);
           if(componentScan != null){
               for (String s : componentScan.basePackages()) {
                   System.out.println(s);
                   //com.example.spring01.com.a05.component -> classpath*:com/example/spring01/com/a05/component/**/*.class
                   String path =  "classpath*:" + s.replace(".","/") + "/**/*.class";
                   System.out.println(path);
                   CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();
                   Resource[] resources = new PathMatchingResourcePatternResolver().getResources(path);
                   AnnotationBeanNameGenerator generator = new AnnotationBeanNameGenerator();
                   for (Resource resource : resources) {
                       System.out.println("resource---"+resource);
                       MetadataReader reader = factory.getMetadataReader(resource);
                       AnnotationMetadata annotationMetadata = reader.getAnnotationMetadata();
                       System.out.println("类名:"+ reader.getClassMetadata().getClassName());
                       System.out.println("是否加了 @Component 注解:" + annotationMetadata.hasAnnotation(Component.class.getName()));
                       System.out.println("是否加了 @Component派生 注解:" + annotationMetadata.hasMetaAnnotation(Component.class.getName()));
                       // 如果加了@Component 注解 或在 @Component派生 注解
                       if(annotationMetadata.hasAnnotation(Component.class.getName() ) || annotationMetadata.hasMetaAnnotation(Component.class.getName())){
                           // 生成 beanDefinition
                           AbstractBeanDefinition bd =
                                   BeanDefinitionBuilder.genericBeanDefinition(reader.getClassMetadata().getClassName()).getBeanDefinition();
                           String beanName = generator.generateBeanName(bd, beanFactory);
                           beanFactory.registerBeanDefinition(beanName,bd);
                       }
                   }
               }
           }
       }catch (IOException e) {
           e.printStackTrace();
       }
    }

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

    }
}

工程后处理器模拟实现@Bean

CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();
MetadataReader reader = factory.getMetadataReader(new ClassPathResource("com/example/spring01/com/a05/Config.class"));
Set<MethodMetadata> methods = reader.getAnnotationMetadata().getAnnotatedMethods(Bean.class.getName());
for (MethodMetadata method : methods) {
    System.out.println("method:" + method);

    BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition();
    builder.setFactoryMethodOnBean(method.getMethodName(),"config");
    builder.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);
    AbstractBeanDefinition bd = builder.getBeanDefinition();
    context.getDefaultListableBeanFactory().registerBeanDefinition(method.getMethodName(),bd);

    String initMethod = method.getAnnotationAttributes(Bean.class.getName()).get("initMethod").toString();
    if(initMethod.length() >0 ){
        builder.setInitMethodName(initMethod);
    }
}

实现BeanFactoryPostProcessor

AtBeanPostProcessor 类

public class AtBeanPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
        try {
            CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();
            MetadataReader reader = factory.getMetadataReader(new ClassPathResource("com/example/spring01/com/a05/Config.class"));
            Set<MethodMetadata> methods = reader.getAnnotationMetadata().getAnnotatedMethods(Bean.class.getName());
            for (MethodMetadata method : methods) {
                System.out.println("method:" + method);

                BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition();
                builder.setFactoryMethodOnBean(method.getMethodName(),"config");
                builder.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);
                AbstractBeanDefinition bd = builder.getBeanDefinition();
                if(configurableListableBeanFactory instanceof DefaultListableBeanFactory) {
                    DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) configurableListableBeanFactory;
                    beanFactory.registerBeanDefinition(method.getMethodName(), bd);
                }
                String initMethod = method.getAnnotationAttributes(Bean.class.getName()).get("initMethod").toString();
                if(initMethod.length() >0 ){
                    builder.setInitMethodName(initMethod);
                }
            }

        }catch (Exception e){

        }
    }
}

工厂后处理器模拟实现—Mapper

在Config,使用@Bean 注册

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

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

在这里插入图片描述

自定义 MapperPostProcessor

这里不能使用名字生成器和MapperFactoryBean的BeanDefinition作为参数直接生成名字,这样会导致多个相同的类型的对象因为名字一样产生覆盖的问题
解决办法 这里参考Spring源码的做法用@Mapper注解修饰的接口的BeanDefinition作为参数生成名字

public class MapperPostProcessor implements BeanDefinitionRegistryPostProcessor {
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanFactory) throws BeansException {
        try {
            PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
            Resource[] resources = resolver.getResources("classpath:com/example/spring01/com/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()) {

                    AbstractBeanDefinition bd = BeanDefinitionBuilder
                        .genericBeanDefinition(MapperFactoryBean.class)
                        .addConstructorArgValue(classMetadata.getClassName())
                        .setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE)
                        .getBeanDefinition();
                    
                    AbstractBeanDefinition bd2 = BeanDefinitionBuilder.genericBeanDefinition(classMetadata.getClassName()).getBeanDefinition();
                    String name = generator.generateBeanName(bd2, beanFactory);
                    beanFactory.registerBeanDefinition(name,bd);
                }
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

    }

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

    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值