Spring高级篇-基于BeanDefinitionRegistryPostProcessor手写后置处理器

上一篇文章中通过ConfigurationClassPostProcessor、MapperScannerConfigurer扫描到了Config类中定义的Bean信息。这篇文章来手动实现这些扫描类的功能。

如何扫描到定义的类加入到容器中?
BeanDefinitionRegistryPostProcessor接口继承BeanFactoryPostProcessor接口,在所有bean定义信息将要被加载,bean实例还没有创建的时候执行。BeanDefinitionRegistry是bean定义信息的保存中心,以后BeanFactory就是按照BeanDefinitionRegistry里面保存的每一个bean定义信息创建bean实例
BeanDefinitionRegistryPostProcessor会在BeanFactoryPostProcessor之前执行,可以利用BeanDefinitionRegistryPostProcessor给容器中添加一些其它组件

自定义@ComponentScan处理器

思路:
1.通过 AnnotationUtils.findAnnotation 找到 ComponentScan注解
2.获取需要扫描的包
3.通过PathMatchingResourcePatternResolver获取包下的资源信息
4.通过CachingMetadataReaderFactory读取类的元数据信息
5.判断注解元信息上是否加了 @Component注解 或者 @Component派生类
6.生成BeanDefinition对象信息
7.BeanDefinition注入到beanFactory中

public class ComponentScanPostProcessor implements BeanDefinitionRegistryPostProcessor {
    @Override // context.refresh
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {

    }

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanFactory) throws BeansException {
        try {
            //1.通过 AnnotationUtils.findAnnotation 找到 ComponentScan注解
            ComponentScan componentScan = AnnotationUtils.findAnnotation(Config.class, ComponentScan.class);
            if (componentScan != null) {
                //2.获取需要扫描的包
                for (String p : componentScan.basePackages()) {
                    String path = "classpath*:" + p.replace(".", "/") + "/**/*.class";
                    CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();
                    //3.通过PathMatchingResourcePatternResolver获取包下的资源信息
                    Resource[] resources = new PathMatchingResourcePatternResolver().getResources(path);
                    AnnotationBeanNameGenerator generator = new AnnotationBeanNameGenerator();
                    for (Resource resource : resources) {
                        //4.通过CachingMetadataReaderFactory读取类的元数据信息
                        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()));
                        //5.判断注解元信息上是否加了 @Component注解 或者 @Component派生类
                        if (annotationMetadata.hasAnnotation(Component.class.getName())
                            || annotationMetadata.hasMetaAnnotation(Component.class.getName())) {
                            //6.生成BeanDefinition对象信息
                            AbstractBeanDefinition bd = BeanDefinitionBuilder
                                    .genericBeanDefinition(reader.getClassMetadata().getClassName())
                                    .getBeanDefinition();
                            String name = generator.generateBeanName(bd, beanFactory);
                            //7.BeanDefinition注入到beanFactory中
                            beanFactory.registerBeanDefinition(name, bd);
                        }
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

自定义@Bean处理器

思路:
1.创建类的元信息读取的工厂类
2.读取Config类的元数据信息
3.获取定义了@Bean注解的方法
4.通过BeanDefinitionBuilder生成 BeanDefinition 对象信息
5.BeanDefinition 注册到 beanFactory 中

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

    }

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanFactory) throws BeansException {
        try {
            //1.创建类的元信息读取的工厂类
            CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();
            //2.读取Config类的元数据信息
            MetadataReader reader = factory.getMetadataReader(new ClassPathResource("com/study/spring/a05/Config.class"));
            //3.获取定义了@Bean注解的方法
            Set<MethodMetadata> methods = reader.getAnnotationMetadata().getAnnotatedMethods(Bean.class.getName());
            for (MethodMetadata method : methods) {
                System.out.println("AtBeanPostProcessor ==> " + method);
                //4.通过BeanDefinitionBuilder生成 BeanDefinition 对象信息
                String initMethod = method.getAnnotationAttributes(Bean.class.getName()).get("initMethod").toString();
                BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition();
                builder.setFactoryMethodOnBean(method.getMethodName(), "config");
                //设置自动注入Bean的参数
                builder.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);
                if (initMethod.length() > 0) {
                    builder.setInitMethodName(initMethod);
                }
                AbstractBeanDefinition bd = builder.getBeanDefinition();
                //5.BeanDefinition 注册到 beanFactory 中
                beanFactory.registerBeanDefinition(method.getMethodName(), bd);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

自定义@Mapper处理器

思路:
1.通过 PathMatchingResourcePatternResolver 读取mapper目录下的资源
2.读取类的元信息
3.判断类是否是接口 如果是接口创建类的实现类
4.通过 MapperFactoryBean 创建Mapper接口的实现类
5.通过类名称重新创建一个 BeanDefinition用来获取BeanName,因为上面通过MapperFactoryBean 创建的BeanDefinition 类名称都是相同的
6.BeanDefinition 注册到 beanFactory 中

public class MapperPostProcessor implements BeanDefinitionRegistryPostProcessor {

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanFactory) throws BeansException {
        try {
            //1.通过 PathMatchingResourcePatternResolver 读取mapper目录下的资源
            PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
            Resource[] resources = resolver.getResources("classpath:com/study/spring/a05/mapper/**/*.class");
            AnnotationBeanNameGenerator generator = new AnnotationBeanNameGenerator();
            //2.读取类的元信息
            CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();
            for (Resource resource : resources) {
                MetadataReader reader = factory.getMetadataReader(resource);
                ClassMetadata classMetadata = reader.getClassMetadata();
                //3.判断类是否是接口 如果是接口创建类的实现类
                if (classMetadata.isInterface()) {
                    //4.通过 MapperFactoryBean 创建Mapper接口的实现类
                    AbstractBeanDefinition bd = BeanDefinitionBuilder.genericBeanDefinition(MapperFactoryBean.class)
                            .addConstructorArgValue(classMetadata.getClassName())
                            .setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE)
                            .getBeanDefinition();
                    //5.通过类名称重新创建一个 BeanDefinition ? 这里为什么要重新创建一个 ?
                    AbstractBeanDefinition bd2 = BeanDefinitionBuilder.genericBeanDefinition(classMetadata.getClassName()).getBeanDefinition();
                    String name = generator.generateBeanName(bd2, beanFactory);
                    //6.BeanDefinition 注册到 beanFactory 中
                    beanFactory.registerBeanDefinition(name, bd);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

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

    }
}

测试

public static void main(String[] args) throws IOException {

        GenericApplicationContext context = new GenericApplicationContext();
        context.registerBean("config", Config.class);
        context.registerBean(ComponentScanPostProcessor.class); // 解析 @ComponentScan
        context.registerBean(AtBeanPostProcessor.class); // 解析 @Bean
        context.registerBean(MapperPostProcessor.class); // 解析 Mapper 接口

        context.refresh();

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

        context.close();
    }

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值