目录
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完成指定包的类扫描
- 工具类链接如下
- https://hkm-web.oss-cn-beijing.aliyuncs.com/Utils
- 自定义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集合后即可。
-