Spring的后处理器-BeanFactoryPostprocessor

目录

Spring后处理器

Bean工厂后处理器-BeanFactoryPostProcessor

修改beanDefinition对象

添加beanDefiniton对象

方法一

方法二

自定义@Component


Spring后处理器

  • Spring后处理器是Spring对外开放的重要拓展点(让我们可以用添加自己的逻辑),允许我们介入到Bean的整个实例化流程中来,以达到动态注册BeanDefinition(向BeanDefitionMap中添加BeanDefition对象的过程),动态修改BeanDefition,以及动态修改Bean的作用。Spring主要有两种后处理器
    • BeanFactoryPostprocessor:Bean工厂后处理器,(执行时机)在BeanDefinitionMap填充完毕,Bean实例化之前执行
    • BeanPostProcessor:Bean后处理器,(执行时机)一般在Bean实例化后,填充到单例池singletonObjects之前执行

Bean工厂后处理器-BeanFactoryPostProcessor

  • BeanFactoryPostProcessor是一个接口规范,实现该接口的类只要交由Spring容器管理(即在配置文件中注册该类称为Bean对象)的话,那么Spring就会回调该接口的方法,用于对BeanDefition注册和修改功能
  • BeanFactoryPostProcessor定义如下
    • //
      // Source code recreated from a .class file by IntelliJ IDEA
      // (powered by FernFlower decompiler)
      //
      
      package org.springframework.beans.factory.config;
      
      import org.springframework.beans.BeansException;
      
      @FunctionalInterface
      public interface BeanFactoryPostProcessor {
          void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
      }
      
修改beanDefinition对象
  • 创建一个实现类(修改beanDefinition对象

    • package com.example.PostProcessor;
      
      import org.springframework.beans.BeansException;
      import org.springframework.beans.factory.config.BeanDefinition;
      import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
      import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
      
      public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
          @Override
          public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
              System.out.println("beanDefinitionMap填充完毕后会回调该方法");
              // todo 修改Map集合中的BeanDefinition对象
              BeanDefinition userService = beanFactory.getBeanDefinition("userService");
              userService.setBeanClassName("com.example.DAO.Impl.UserDAOImpl");
      
          }
      }
      
  • 测试类

    • package com.example.Test;
      
      
      import org.springframework.context.support.ClassPathXmlApplicationContext;
      public class TestApplicationContext {
          public static void main(String[] args)  {
              ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
              System.out.println(context.getBean("userService"));
          }
      }
      
  • 运行结果如下

    • 显然bean对应的类被改变了 
添加beanDefiniton对象
方法一
  • 创建一个类(添加beanDefiniton对象
    • package com.example.PostProcessor;
      
      import org.springframework.beans.BeansException;
      import org.springframework.beans.factory.config.BeanDefinition;
      import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
      import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
      import org.springframework.beans.factory.support.DefaultListableBeanFactory;
      import org.springframework.beans.factory.support.RootBeanDefinition;
      
      public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
          @Override
          public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
              // todo 向Map集合中添加一个BeanDefinition对象,即在配置文件中没有注册
              // 创建一个新的beanDefinition对象
              BeanDefinition beanDefinition = new RootBeanDefinition();
              // 设置bean对应的类
              beanDefinition.setBeanClassName("com.example.DAO.Impl.UserDAOImpl");
              DefaultListableBeanFactory listableBeanFactory = (DefaultListableBeanFactory) beanFactory;
              // 添加该beanDefinition对象
              listableBeanFactory.registerBeanDefinition("UserDAO", beanDefinition);
          }
      }
      

      在配置文件中没有配置UserDAO了

  • 测试类

    • package com.example.Test;
      
      
      import com.example.DAO.Impl.UserDAOImpl;
      import org.springframework.context.support.ClassPathXmlApplicationContext;
      
      public class TestApplicationContext {
          public static void main(String[] args) {
              ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
              
              System.out.println(context.getBean(UserDAOImpl.class));
          }
      }
      
  • 运行结果

                beanDefinition对象成功添加


方法二
  • Spring提供了一个BeanFactoryPostProcessor的子接口BeanDefinitionRegistryPostProcessor专门用于注册BeanDefinition操作
    • //
      // Source code recreated from a .class file by IntelliJ IDEA
      // (powered by FernFlower decompiler)
      //
      
      package org.springframework.beans.factory.support;
      
      import org.springframework.beans.BeansException;
      import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
      
      public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {
          void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;
      }
      
  • 创建一个类实现后处理器BeanFactoryPostProcessor的子接口BeanDefinitionRegistryPostProcessor(记得将该类注册到Spring容器中)

    • package com.example.PostProcessor;
      
      import org.springframework.beans.BeansException;
      import org.springframework.beans.factory.config.BeanDefinition;
      import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
      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.DefaultListableBeanFactory;
      import org.springframework.beans.factory.support.RootBeanDefinition;
      
      public class MyBeanFactoryPostProcessor02 implements BeanDefinitionRegistryPostProcessor {
          @Override
          public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
              // 注册beanDefinition
              BeanDefinition beanDefinition = new RootBeanDefinition();
              beanDefinition.setBeanClassName("com.example.DAO.Impl.UserDAOImpl");
              registry.registerBeanDefinition("UserDAO", beanDefinition);
          }
          @Override
          public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
      
          }
      }
      

      实现添加beanDefiniton就会简单很多

  • 测试类

    • package com.example.Test;
      
      
      import com.example.DAO.Impl.UserDAOImpl;
      import org.springframework.context.support.ClassPathXmlApplicationContext;
      
      public class TestApplicationContext {
          public static void main(String[] args) {
              ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
              System.out.println(context.getBean(UserDAOImpl.class));
          }
      }
      
  • 运行结果如下

完整流程图 

        
 


自定义@Component
  • 案例
    • 使用Spring的BeanFactoryPostProcessor扩展点完成自定义注解扫描
  • 要求
    • 自定义@MyComponent注解,使用在类上
    • 使用资料中提供好的包扫描工具BaseClassScanUtils完成指定包的类扫描
    • 自定义BeanFactoryPostProcessor完成注解@MyComponent的解析,解析最终被Spring管理
  • 具体代码如下
    • 注解类
      • package com.example.Anno;
        
        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 {
            String value(); //用于设置注解的值
        }
        
    • 工具类

      • package com.example.Utils;
        
        import com.example.Anno.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.util.HashMap;
        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);
            }
        }
        
    • 使用注解来注册为Bean对象的类

      • package com.example.Beans;
        
        import com.example.Anno.MyComponent;
        
        @MyComponent("otherBean")
        public class otherBeans {
        }
        

        在配置文件中没有配置该类作为bean对象

    • 后工厂处理器类(该类要交给Spring容器管理

      • package com.example.PostProcessor;
        
        
        import com.example.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 MyComponentBeanFactoryProcessor implements BeanDefinitionRegistryPostProcessor {
            @Override
            public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
                // 通过工具去扫描指定包及其子包下的所有类,收集使用@MyComponent注解的类,放在Map集合中
                Map<String, Class> MyComponentAnnotationMap = BaseClassScanUtils.scanMyComponentAnnotation("com.example");
                // 遍历Map,组装BeanDefinition进行注册
                MyComponentAnnotationMap.forEach((beanName,clazz)->{
                    // 获取beanClassName
                    String beanClassName = clazz.getName();
                    // 创建beanDefinition
                    BeanDefinition beanDefinition = new RootBeanDefinition();
                    beanDefinition.setBeanClassName(beanClassName);
                    // 注册
                    registry.registerBeanDefinition(beanName,beanDefinition);
                });
        
            }
        
            @Override
            public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        
            }
        }
        

        通过后工厂处理器类来将标记了自己创建的@MyComponent注解的类创建为beanDefinition对象后添加到beanDefinitionMap集合中。

    • 测试类

      • package com.example.Test;
        
        
        import com.example.Beans.otherBeans;
        import org.springframework.context.support.ClassPathXmlApplicationContext;
        
        public class TestApplicationContext {
            public static void main(String[] args) {
                ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
                System.out.println(context.getBean(otherBeans.class));
            }
        }
        
    • 运行结果


      •  

      • 运行成功~

  • 使用注解注册bean的原理

    • 最主要是通过Bean工厂后处理器进行实现的,通过工具类获取到添加了注解的类的集合后,在后处理器中,对扫描结果进行遍历,然后生成对对应的beanDefinition对象后,注册到beanDefinitonMap集合后即可。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值