Java Spring后处理器
在Spring框架中,交给Spring管理的类信息都会被Spring底层自动加载被封装成对应的BeanDefinition对象存储在beanDefinitionMap的Map集合中去,那么除了直接将类信息配置的方式外,还有别的方式可以对想要交给Spring管理的类进行针对性处理封装,这里就可以使用到Spring的后处理器。
后处理器:是Spring对外开放的重要扩展点,允许我们介入到Bean的整个实例化流程中来,以达到动态注册BeanDefinition,动态修改BeanDefinition,以及动态修改Bean的作用
Spring的后处理器分为两类:BeanFactoryPostProcessor、BeanPostProcessor
- BeanFactoryPostProcessor:Bean工厂后处理器,在BeanDefinitionMap填充完毕,Bean实例化之前执行
- BeanPostProcessor:Bean后处理器,一般在Bean实例化之后,填充到单例池singletonObjects之前执行
Bean实例化链接:Bean的实例化
BeanFactoryPostProcessor样例:
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
System.out.println("beanDefinitionMap填充完毕后,Spring容器回调此方法");
//功能一:修改BeanDefinition的信息
//根据BeanName获取封装的BeanDefinition对象
BeanDefinition myClass= configurableListableBeanFactory.getBeanDefinition("myClass");
myClass.setBeanClassName("com.test.MyClassChange");
//功能二:注册BeanDefinition到beandDefinitionMap中
//设置BeanDefinition的Bean信息
RootBeanDefinition rootBeanDefinition = new RootBeanDefinition();
rootBeanDefinition.setBeanClassName("com.test.MyClassNew");
//进行BeanDefinition注册
DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) configurableListableBeanFactory;
defaultListableBeanFactory.registerBeanDefinition("myClassNew",rootBeanDefinition);
}
}
FactoryBeanProcessor工厂后处理,可以 修改 beanBeanDefintionMap中注册的BeanBeanDefintion内容或者 新注册 BeanBeanDefintion到beanBeanDefintionMap中去,注册功能可以理解注解的实现,工厂后处理器去遍历带上注解的类,让后将其进行注册
BeanFactoryPostProcessor类似注解实现样例:
public class MyComponentBeanFactoryPostPocessor implements BeanDefinitionRegistryPostProcessor {
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
// 通过扫描工具去扫描指定包及其子包下的所有类,收集使用@MyComponent的注解的类
Map<String, Class> myComponentAnnotationMap = BaseClassScanUtils.scanMyComponentAnnotation("com.test");
// 遍历Map,组装BeanDefinition对象
Iterator<String> iterator = myComponentAnnotationMap.keySet().iterator();
while (iterator.hasNext()) {
String key = iterator.next();
String className = myComponentAnnotationMap.get(key).getName();
RootBeanDefinition rootBeanDefinition = new RootBeanDefinition();
//获取待注册的类名
rootBeanDefinition.setBeanClassName(className);
//进行BeanDefinition注册
beanDefinitionRegistry.registerBeanDefinition(key, rootBeanDefinition);
System.out.println("工厂后处理器注册了" + key + "对象");
}
}
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
}
}
注册的时候可以用专用子接口BeanDefinitionRegistryPostProcessor去注册,此接口在BeanFactoryPostProcessor之前执行
BeanPostProcessor样例:
public class MyBeanPostProcessor implements BeanPostProcessor {
//在init方法执行之前执行
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println(beanName + ":postProcessBeforeInitialization");
//判断Bean的实例类型
if(bean instanceof MyClass){
MyClass myClass= (MyClass) bean;
//MyClass中有个String属性attribute,在此处可以注入值
myClass.setAttribute("setAttribute");
}
return null;
}
//在init方法执行之后执行
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println(beanName + ":postProcessAfterInitialization");
return null;
}
}
BeanPostProcessor可以修改Bean的内容,先创建Bean的构造方法,再执行postProcessBeforeInitialization方法、执行Bean的其他方法(init初始化方法等)、最后执行postProcessAfterInitialization方法
Spring的AOP代理增强就是基于此后处理的原理进行实现,可以在Bean实例中进行切面的织入
AOP博客链接:AOP博客链接
代理博客链接:代理博客链接
BeanFactoryPostProcessor类似AOP实现样例:
public class myAopBeanPostProcessor implements BeanPostProcessor {
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return null;
}
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
// 使用动态代理,对目标Bean进行增强,返回proxy对象,进而存储到单例池singletonObjects中
Object beanProxy = Proxy.newProxyInstance(
bean.getClass().getClassLoader(),
bean.getClass().getInterfaces(),
(proxy, method, args) -> {
//1、前置增强
System.out.println("方法:" + method.getName() + "-开始时间:" + new Date());
//2、执行目标方法
Object result = method.invoke(bean, args);
//3、后置增强
System.out.println("方法:" + method.getName() + "-结束时间:" + new Date());
return result;
}
);
return beanProxy;
}
}