上海手机网站建设哪家好网络口碑营销的成功案例
目录
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 {@Overridepublic 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 {@Overridepublic 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 {@Overridepublic void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {// 注册beanDefinitionBeanDefinition beanDefinition = new RootBeanDefinition();beanDefinition.setBeanClassName("com.example.DAO.Impl.UserDAOImpl");registry.registerBeanDefinition("UserDAO", beanDefinition);}@Overridepublic 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);//扫描到的classString 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;}//如果没有为"",那就把当前类的类名作为beanNameannotationClassMap.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 {@Overridepublic void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {// 通过工具去扫描指定包及其子包下的所有类,收集使用@MyComponent注解的类,放在Map集合中Map<String, Class> MyComponentAnnotationMap = BaseClassScanUtils.scanMyComponentAnnotation("com.example");// 遍历Map,组装BeanDefinition进行注册MyComponentAnnotationMap.forEach((beanName,clazz)->{// 获取beanClassNameString beanClassName = clazz.getName();// 创建beanDefinitionBeanDefinition beanDefinition = new RootBeanDefinition();beanDefinition.setBeanClassName(beanClassName);// 注册registry.registerBeanDefinition(beanName,beanDefinition);});}@Overridepublic 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集合后即可。
-