1 Spring后处理器
Spring的后处理器是Spring对外开发的重要扩展点,允许我们介入到整个Bean实例化流程中来,以达到动态注册BeanDefinition,动态修改BeanDefinition,以及动态修改Bean的作用。
BeanFactoryPostProcessor: Bean工厂后处理器,在BeanDefinitionMap填充完毕,Bean实例化之前执行。只会执行一次。
BeanPostProcessor: Bean后处理器,一般在Bean实例化之后,填充到单例池singletonObjects之前执行。会执行多次,每个bean创建完成后,放入singletonObjects之前。
解析:
动态注册BeanDefinition:在创建完BeanDefinition后,加入到BeanDefinitionMap的过程。
1.1 BeanFactoryPostProcessor
BeanFactoryPostProcessor是一个接口规范,实现了该接口的类只要交由Spring容器管理的话,那么Spring就会调该接口的方法,用于对BeanDefinition注册和修改的功能。
实现该接口的类
交给Spring管理
Spring自动调用
public class MyBeanFactoryPostPorcess implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
// 调用工厂后处理器
BeanDefinition beanDefinition = beanFactory.getBeanDefinition("dataSource");
System.out.println("beanDefinition.getBeanClassName() = " + beanDefinition.getBeanClassName());
}
}
<!--注入工厂后处理器-->
<bean id="factoryProfessor" class="cn.msf.processor.MyBeanFactoryPostPorcess"></bean>
结果
测试动态生成bean,并不需要利用bean标签
public class MyBeanFactoryPostPorcess implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
// 动态注册
BeanDefinition definition = new RootBeanDefinition();
definition.setBeanClassName("cn.msf.dao.impl.PersonDaoImpl");
DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) beanFactory;
defaultListableBeanFactory.registerBeanDefinition("personDao",definition);
// 调用工厂后处理器
BeanDefinition beanDefinition = beanFactory.getBeanDefinition("dataSource");
System.out.println("beanDefinition.getBeanClassName() = " + beanDefinition.getBeanClassName());
}
}
结果
一般可以使用BeanFactoryPostProcessor的子接口BeanDefinitionRegistryPostProcessor可以避免强转。
在Day4下中最后的图进行扩展。Day4 下 Spring 的get方法和实例化流程
1.2 实现简单的MyComponent注解
首先定义注解
@Target(ElementType.TYPE) // 注解的位置在类上
@Retention(RetentionPolicy.RUNTIME)
public @interface MyComponent {
String value();
}
配置后工厂处理器
public class MyBeanFactoryPostProcessor2 implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
Map<String, Class> map = BaseClassScanUtils.scanMyComponentAnnotation("cn.msf");
map.forEach((name,clazz)->{
String beanClassName = clazz.getName();
RootBeanDefinition beanDefinition = new RootBeanDefinition();
beanDefinition.setBeanClassName(beanClassName);
registry.registerBeanDefinition(name,beanDefinition);
});
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
}
}
// 包扫描代码
package cn.msf.utils;
import cn.msf.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.lang.annotation.Annotation;
import java.util.HashMap;
import java.util.List;
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("cn.msf");
System.out.println(stringClassMap);
}
}
<bean id="factoryProfessor" class="cn.msf.processor.MyBeanFactoryPostProcessor2"></bean>
测试
- 3 BeanPostProcessor 后置处理器
作用在bean实例化之后,加载到SingletonObjects之前,每次产生一个bean都会触发。
例如: 属性的填充、初始方init(bean属性的填充)的执行等,其中有一个对外进行扩展的点BeanPostProcessor,我们称为Bean后处理。跟上面的Bean工厂后处理器相似,它也是一个接口,实现了该接口并被容器管理的BeanPostProcessor,会在流程节点上被Spring自动调用。
实现该接口的类
交给Spring管理
Spring自动调用
入门测试
package cn.msf.processor;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
/**
* @author : msf
* @date : 2023/1/10
*/
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println(beanName + ": postProcessBeforeInitialization");
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println(beanName + ": postProcessAfterInitialization");
return bean;
}
}
<bean id="userDao" class="cn.msf.dao.impl.UserDaoImpl" init-method="init"></bean>
<bean class="cn.msf.processor.MyBeanPostProcessor"></bean>
public class UserDaoImpl implements UserDao {
public UserDaoImpl() {
System.out.println("UserDao 实例化方法");
}
public void init() {
System.out.println("UserDao 初始化方法");
}
}
测试结果