相信很多看过 Spring 的人都曾为这句话:“Give BeanPostProcessors a chance to return a proxy instead of the target bean instance” 感受到迷惑,今天简单理解下。字面翻译是说给你个机会创建代理对象。但是我们知道创建代理对象之前肯定得先要有目标对象,可是在 Spring 说这句话之前目标对象根本还没创建,核心源码如下:
try {
// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
// 如果自己生成了自己的 bean 实例的话就 Spring 就不会帮你生成这个对象喽哦
if (bean != null) {
return bean;
}
}
try {
// 这里才开始创建目标对象
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
}
从上述源码中可看出 bean 的创建是在 doCreateBean() 方法,但 resolveBeforeInstantiation() 方法处 Spring 就很明确的说出了这样一句话:Give BeanPostProcessors a chance to return a proxy instead of the target bean instance。就很纳闷为什么在这个地方就可以返回一个代理对象呢(肯定也是在其他某个地方生成了这个类的非代理对象即目标对象)?
进入 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) {
// fun_call_1: 此时实现了 InstantiationAwareBeanPostProcessor 接口的方法在此处被调用
// 而且如果回调方法返回了不为 null 就会继续调用 applyBeanPostProcessorsAfterInitialization() 方法
// 这里而不是直接调用 applyBeanPostProcessorsBeforeInitialization() 方法,搞不懂为什么不这样调用
bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
if (bean != null) {
bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
}
}
}
mbd.beforeInstantiationResolved = (bean != null);
}
return bean;
}
@Nullable
protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
Object result = bp.postProcessBeforeInstantiation(beanClass, beanName);
if (result != null) {
return result;
}
}
return null;
}
可以看到其实又是 BeanPostProcessor 接口的应用(埋点),但这里关注的是 InstantiationAwareBeanPostProcessor 类型的 BeanPostProcessor。如果这里的 BeanPostProcessor 接口处理完之后返回 bean 不为 null,那么整个 Spring 的 getBean() 流程结束, 表示 bean 创建完成,就根本走不到 doCreateBean() 方法逻辑。
接着在通过 idea 查看有哪些类实现了 postProcessBeforeInstantiation() 方法,如下图示:
一眼看过去就会发现我们的老朋友 AbstractAutoProxyCreator 类,而且刚好是个能够创建代理类的类,又刚好和 Spring 说的那个句话(Give BeanPostProcessors a chance to return a proxy instead of the target bean instance)有点关联,所以是不是这个类可以帮我们提前生成个代理对象呢?但是这个类是个抽象类,如果想要用到它里面的方法,那么必然要找它的实现类,这找到这抽象类有名实实现子类 AnnotationAwareAspectJAutoProxyCreator 类,要导入此类,直接使用注解 @EnableAspectJAutoProxy ,那么都用到这个注解了,干脆把 @Aspect 切面逻辑也一起给补充完整,代码如下:
@Aspect
@Configuration
public class JavAspect {
@Pointcut("execution(* com.gwm.proxy..*.*(..))")
public void pointcutGwm() {}
@Before(value = "pointcutGwm()")
public void beforeTest(JoinPoint joinPoint) {
System.out.println("beforeTest log info ===================");
}
}
@ComponentScan
@EnableAspectJAutoProxy
public class AopProxyTest {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AopProxyTest.class);
Person bean = context.getBean(Person.class);
bean.show();
}
}
然后再定义一个 Person 类并且有个 show() 方法,逻辑很简单,并且这个类是在上面的 @Pointcut 条件下能够扫描到的,如下代码:
@Component
public class Person {
public void show() {
System.out.println("======>show...");
}
}
从上述代码可以看出,明显 Spring会给 Person 类做代理进行逻辑增强。当执行 show() 方法必然会调用到切面逻辑,结果如下:
beforeTest log info ===================
======>show...
但此时需要注意一个细节, Spring 创建出的代理对象是在 doCreateBean() 方法之后,也就是说目标类已创建好再创建代理的。但现在我要在 doCreateBean() 方法之前去创建代理,还未执行 doCreateBean() 方法。
目标对象是在 doCreateBean() 方法中创建的
代理对象是在 AbstractAutoProxyCreator 类的 postProcessAfterInitialization() 方法中创建的
如果真的能够在 doCreateBean() 方法执之前创建出代理对象,那么就能够理解 Spring 为什么在源码那个地方会注释着一句这样的话啦。也就能够理解在这里确实能够给你一次机会创建代理对象(注意此时 doCreateBean() 方法可还没执行,也就是说目标类还没创建呢!)。
但是真的能够在没有目标对象的情况下创建出代理对象么?
答案肯定是不行滴。
肯定是要先有目标对象才可生成代理,所以肯定是在某个地方提前把目标对象生成好了。这个地方就是 Spring 注释那句话的地方,源码如下:
try {
// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
// 如果自己生成了自己的 bean 实例的话就 Spring 就不会帮你生成这个对象喽哦
if (bean != null) {
return bean;
}
}
try {
// 这里才开始创建目标对象
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
}
进入 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 = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
if (bean != null) {
bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
}
}
}
}
return bean;
}
@Nullable
protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
Object result = bp.postProcessBeforeInstantiation(beanClass, beanName);
if (result != null) {
return result;
}
}
return null;
}
重点看到 postProcessBeforeInstantiation() 方法的实现逻辑(在 AbstractAutoProxyCreator 类中,上述通过 @EnableAspectJAutoProxy 注解引入了切面类)进入此方法 postProcessBeforeInstantiation() 源码如下:
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
Object cacheKey = getCacheKey(beanClass, beanName);
TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
if (targetSource != null) {
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
return null;
}
从源码中就可以清晰明了的看到,getCustomTargetSource() 方法必然就是去生成目标对象的,目标对象有了,自然就可以去生成代理对象。所以就算没有执行 doCreateBean() 方法生成目标对象,此时我们也可以生成代理对象,因为在这里有个 getCustomTargetSource() 方法给我们自己去生成目标对象。所以这里就会造成一种假象,什么假象呢?因为没有执行 doCreateBean() 方法,会认为还没有创建好目标对象,就生成代理对象,有点扯淡,从而就会质疑 Spring 在源码中那个地方注释这样一句话就很离谱。
现在应该能够明白为什么 Spring 会在那个地方注释这样一句话了吧,那么接下来就是看怎么自己生成目标对象了。因为我们给他提供好目标对象,它就能帮我们创建出代理对象,那就需要看下 getCustomTargetSource() 方法的实现逻辑,核心源码如下:
@Nullable
protected TargetSource getCustomTargetSource(Class<?> beanClass, String beanName) {
// We can't create fancy target sources for directly registered singletons.
if (this.customTargetSourceCreators != null &&
this.beanFactory != null && this.beanFactory.containsBean(beanName)) {
for (TargetSourceCreator tsc : this.customTargetSourceCreators) {
TargetSource ts = tsc.getTargetSource(beanClass, beanName);
if (ts != null) {
// Found a matching TargetSource.
if (logger.isTraceEnabled()) {
logger.trace("TargetSourceCreator [" + tsc +
"] found custom TargetSource for bean with name '" + beanName + "'");
}
return ts;
}
}
}
return null;
}
从上述源码中可以看出,如果想要返回目标对象,就需要让 customTargetSourceCreators 集合有值,才有机会返回对象,并且还要重写 getTargetSource() 方法,返回一个自定义的目标对象,这样才能保证有在此处有提前生成好的目标对象返回,这样就能够在 doCreateBean() 方法之前就提前生成代理对象。
那么现在怎么给 customTargetSourceCreators 集合添加值呢?
从源码中可以看出 customTargetSourceCreators 属性是 AbstractAutoProxyCreator 类中的属性,AbstractAutoProxyCreator 类又是个 BeanPostProcessor 接口应用,想要往一个 BeanPostProcessor 接口属性赋值,可以通过比这个 BeanPostProcessor 优先级更高的 BeanPostProcessor 来为后面的 BeanPostProcessor 赋值,所以可以自定义一个 BeanPostProcessor 接口,并且实现 PriorityOrdered 最高优先级接口,代码如下:
@Component
public class TargetSourceCreatorBeanPostProcessor implements BeanPostProcessor, BeanFactoryAware, PriorityOrdered {
private BeanFactory beanFactory;
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
// 这里直往 AbstractAutoProxyCreator 类中的 customTargetSourceCreators 属性添加值
if (bean instanceof AnnotationAwareAspectJAutoProxyCreator) {
AbstractAutoProxyCreator autoProxyCreator = (AbstractAutoProxyCreator) bean;
MyTargetSourceCreator myTargetSourceCreator = new MyTargetSourceCreator();
myTargetSourceCreator.setBeanFactory(beanFactory);
autoProxyCreator.setCustomTargetSourceCreators(myTargetSourceCreator);
}
return bean;
}
@Override
public int getOrder() {
return 0;
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
}
这里因为还需要一个 BeanFactory,所以还需要实现 BeanFactoryAware 接口,把 BeanFactory 也赋值进去
autoProxyCreator.setCustomTargetSourceCreators()
方法就是往 customTargetSourceCreators 集合中赋值。现在知道了怎么给 customTargetSourceCreators 属性赋值,然后开始准备好这个入参值,发现需要传入 TargetSourceCreator 类型的参数,那么就还需要实现下这个接口,但是实现这个接口比较麻烦,直接找它的子类 AbstractBeanFactoryBasedTargetSourceCreator,代码如下:
public class MyTargetSourceCreator extends AbstractBeanFactoryBasedTargetSourceCreator {
@Override
protected AbstractBeanFactoryBasedTargetSource createBeanFactoryBasedTargetSource(Class<?> beanClass, String beanName) {
if (beanClass.isAssignableFrom(Person.class)) {
return new MyTargetSource();
}
return null;
}
}
为了演示简单,在 MyTargetSourceCreator 重写 createBeanFactoryBasedTargetSource() 方法,该类只关注 Person 类,只对 Person 类提前生成代理对象。其他类走正常流程。并且发现返回值需要一个 AbstractBeanFactoryBasedTargetSource 对象,需要我们就去给他实现下呗,代码如下:
public class MyTargetSource extends AbstractBeanFactoryBasedTargetSource {
@Override
public Object getTarget() throws Exception {
return getBeanFactory().getBean(getTargetBeanName());
}
}
在这里 getBeanFactory()、getTargetBeanName() 方法都是 AbstractBeanFactoryBasedTargetSource 类实现的。
但是这里这句代码 getBeanFactory().getBean(getTargetBeanName());
你们觉得返回的是真正的目标对象,还是代理对象???
注意此时的 Spring 工程里面可是引入了 @EnableAspectJAutoProxy
注解,而且 @Pointcut 条件也满足,此时的 getBean() 流程必然会对 Person 类又生成代理对象。但是这里不会,因为 Spring 在这里做了特殊处理!做了什么特殊处理呢?
Spring 会在这里拷贝出来另一个全新的 BeanFactory(你敢相信?),然后把 @EnableAspectJAutoProxy
注解引入的切面入口类 AnnotationAwareAspectJAutoProxyCreator 直接给踢除。在这个全新的 BeanFactory 工厂中就不存在切面入口类,也就不会对 Person 类生成代理对象,直接走正常的 getBean() 流程创建出 Person 目标对象。现在一起看下这个源码,还是从 getCustomTargetSource() 方法开始看起,源码如下:
@Nullable
protected TargetSource getCustomTargetSource(Class<?> beanClass, String beanName) {
// We can't create fancy target sources for directly registered singletons.
if (this.customTargetSourceCreators != null &&
this.beanFactory != null && this.beanFactory.containsBean(beanName)) {
for (TargetSourceCreator tsc : this.customTargetSourceCreators) {
TargetSource ts = tsc.getTargetSource(beanClass, beanName);
if (ts != null) {
// Found a matching TargetSource.
if (logger.isTraceEnabled()) {
logger.trace("TargetSourceCreator [" + tsc +
"] found custom TargetSource for bean with name '" + beanName + "'");
}
return ts;
}
}
}
// No custom TargetSource found.
return null;
}
customTargetSourceCreators 集合现在已经有值,前面已通过 BeanPostProcessor 给它赋值上,然后进入 getTargetSource() 方法,源码如下:
@Override
@Nullable
public final TargetSource getTargetSource(Class<?> beanClass, String beanName) {
AbstractBeanFactoryBasedTargetSource targetSource =
createBeanFactoryBasedTargetSource(beanClass, beanName);
DefaultListableBeanFactory internalBeanFactory = getInternalBeanFactoryForBean(beanName);
BeanDefinition bd = this.beanFactory.getMergedBeanDefinition(beanName);
GenericBeanDefinition bdCopy = new GenericBeanDefinition(bd);
if (isPrototypeBased()) {
bdCopy.setScope(BeanDefinition.SCOPE_PROTOTYPE);
}
internalBeanFactory.registerBeanDefinition(beanName, bdCopy);
targetSource.setTargetBeanName(beanName);
targetSource.setBeanFactory(internalBeanFactory);
return targetSource;
}
从上述源码中可以看出 getInternalBeanFactoryForBean() 方法就是去创建一个全新的 BeanFactory ,然后再给 Person 类重新创建一个 BeanDefinition,并且明确指定是 PROTOTYPE 多例类型 bean(这里还没明白为什么要设置死为 PROTOTYPE 多例类型),然后注册到全新 BeanFactory 工厂中。
然后再看到 getInternalBeanFactoryForBean() 方法,核心源码如下:
protected DefaultListableBeanFactory getInternalBeanFactoryForBean(String beanName) {
synchronized (this.internalBeanFactories) {
return this.internalBeanFactories.computeIfAbsent(beanName,
name -> buildInternalBeanFactory(this.beanFactory));
}
}
protected DefaultListableBeanFactory buildInternalBeanFactory(ConfigurableBeanFactory containingFactory) {
DefaultListableBeanFactory internalBeanFactory = new DefaultListableBeanFactory(containingFactory);
internalBeanFactory.copyConfigurationFrom(containingFactory);
internalBeanFactory.getBeanPostProcessors().removeIf(beanPostProcessor ->
beanPostProcessor instanceof AopInfrastructureBean);
return internalBeanFactory;
}
可以看到 buildInternalBeanFactory() 方法中,有个非常骚的操作 removeIf(),获取到 BeanFactory 中的所有 beanPostProcessors 对象,然后判断是 AopInfrastructureBean 类型的就直接踢除。恰好 @EnableAspectJAutoProxy 注解导入的类 AnnotationAwareAspectJAutoProxyCreator 就是 AopInfrastructureBean 类型。如下图示:
踢除了 AOP 切面入口类,那么 Person 类在此处调用 getBean() 流程就不会返回代理,而是返回目标对象。
public class MyTargetSource extends AbstractBeanFactoryBasedTargetSource {
@Override
public Object getTarget() throws Exception {
return getBeanFactory().getBean(getTargetBeanName());
}
}
然后再回到前面的源码如下:
@Nullable
protected TargetSource getCustomTargetSource(Class<?> beanClass, String beanName) {
// We can't create fancy target sources for directly registered singletons.
if (this.customTargetSourceCreators != null &&
this.beanFactory != null && this.beanFactory.containsBean(beanName)) {
for (TargetSourceCreator tsc : this.customTargetSourceCreators) {
TargetSource ts = tsc.getTargetSource(beanClass, beanName);
if (ts != null) {
// Found a matching TargetSource.
if (logger.isTraceEnabled()) {
logger.trace("TargetSourceCreator [" + tsc +
"] found custom TargetSource for bean with name '" + beanName + "'");
}
return ts;
}
}
}
return null;
}
最终 getCustomTargetSource() 就返回了一个自定义实现的目标对象。然后回到上一层调用,源码如下:
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
Object cacheKey = getCacheKey(beanClass, beanName);
TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
if (targetSource != null) {
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
return null;
}
getCustomTargetSource() 方法返回目标对象不为 null,那么就会去调用 createProxy() 方法生成代理对象。这样就实现了在 doCreateBean() 方法之前提前生成代理对象。从而就可以明白为什么 Spring 会在源码上标注 Give BeanPostProcessors a chance to return a proxy instead of the target bean instance 这样一句代码注释。