背景:
这里为什么会单独讲一下这个类呢??
①我在看Spring源码Bean的创建过程中 看到这个方法resolveBeforeInstantiation、看懂原理很有用
②我之前一次面试问 spring的Bean的创建流程 一般遵循 getBean---> doGetBean -> createBean-->doCreateBean 这几个重要方法 有什么功能会打破这个流程嘛?当时不知道 太细了
③这在实际开发中看过别人写过类似代码 就是这个可能会用得到,当有类似需求时候你能想到这种方式。比如:你想要你的应用程序的某个类被spring容器管理是一个代理对象。你应该如何实现呢?InstantiationAwareBeanPostProcessor就是其中一个方式
知识储备:
①Spring中什么是BeanPostProcessor、在什么阶段加入spring容器管理的
②SpringBean的整体创建流程要知道
注:源码跟踪示例使用配置文件方式 毕竟使用的方式千篇一律 有趣的原理才是万里挑一
源码跟踪:
提示:源码跟踪禁忌抠每一行代码 弄清源码功能整体的脉络思路就好
- createBean方法里面的resolveBeforeInstantiation方法
// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance. Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
这里主要干了什么事情呢? 官方注释【给Bean增强器一个返回代理而不是目标bean实例的机会】这句话翻译成大白话就是这个地方可能会发生proxy,也就是会篡改bean的原始类型,返回一个代理对象加入到spring容器中
- resolveBeforeInstantiation具体干了什么呢?
@Nullable protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) { Object bean = null; if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) { // Make sure bean class is actually resolved at this point. if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) { Class<?> targetType = determineTargetType(beanName, mbd); if (targetType != null) { /**使用bean实例化前的后置处理器来处理目标bean*/ bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName); /**如果bean不等于空,必然是发生了代理*/ if (bean != null) { /**发生了代理,相当于bean完成了一次"实例化",正常的bean的实例化流程和初始化流程肯定走不了, * 因为走的是代理方法的实例化和初始化了,所以下面需要再调用一次当前bean的初始化增强器的后置处理方法 */ bean = applyBeanPostProcessorsAfterInitialization(bean, beanName); } } } mbd.beforeInstantiationResolved = (bean != null); } return bean; }
①hasInstantiationAwareBeanPostProcessors 意思如果容器中含有这样的InstantiationAwareBeanPostProcessors 那么将要执行applyBeanPostProcessorsBeforeInstantiation方法
注意:hasInstantiationAwareBeanPostProcessors这个属性是容器的一个属性 什么时候初始化呢 ?是在registerBeanPostProcessors方法
- applyBeanPostProcessorsBeforeInstantiation有具体干了什么呢?
①遍历所有的BeanPostProcessor 找出InstantiationAwareBeanPostProcessors对象执行postProcessBeforeInstantiation方法
②我们分析下postProcessBeforeInstantiation参数 将要实例化的Bean的class和beanName
注意:容器中BeanPostProcessor 什么时候初始化呢 ?是在registerBeanPostProcessors方法 - 既然postProcessBeforeInstantiation方法返回代理对象 那么 我自己编写一个类 实现InstantiationAwareBeanPostProcessors接口、重写postProcessBeforeInstantiation方法、在这个方法里 使用cglib或者jdk返回一个代理对象不就可以了嘛 那么接下里自己实现一下
案例:
- 配置文件
<bean id="myBeanPostProcessor" class="com.zhangfuyin.bpp.MyBeanPostProcessor"/> <bean id="instantiationAwareBean" class="com.zhangfuyin.bpp.InstantiationAwareBean"/>
- java
public class MyBeanPostProcessor implements InstantiationAwareBeanPostProcessor { @Override public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException { if(beanClass == InstantiationAwareBean.class){ Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(beanClass); enhancer.setCallback(new DistributedLockInterceptor()); return enhancer.create(); } return null; } } ============================================================================= public class DistributedLockInterceptor implements MethodInterceptor { @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { Class<?>[] classes = method.getParameterTypes(); System.out.println("==============DistributedLockInterceptor.invoke before"); Object rtnObj = methodProxy.invokeSuper(o,objects); System.out.println("==============DistributedLockInterceptor.invoke after"); return rtnObj; } } ============================================================================= public class InstantiationAwareBean { public void doSomething(){ System.out.println("==============doSomething===================="); } }
- 测试
public static void main(String agrs[]){ ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("instantiationAwareBeanPostProcessor.xml"); InstantiationAwareBean instantiationAwareBean = ac.getBean(InstantiationAwareBean.class); instantiationAwareBean.doSomething(); }
打印结果:执行目标方法 会进入代理类的方法拦截器 证明代理类被注入spring容器
==============DistributedLockInterceptor.invoke before
==============doSomething====================
==============DistributedLockInterceptor.invoke after