在spring aop中,如果我们的类属符合如下条件:被切面的pointcut匹配到、或者属于自定义的Advisor接口实现类,那么spring在bean完成实例化之后,会为类生成代理对象。这是众所周知的aop流程。
此外,spring还为我们提供了TargetSourceCreator接口,该接口的功能是:在bean实例化之前,就为类生成代理。 现在我们通过查看源码的方式,来了解该接口的功能。
创建代理
doGetBean
在循环依赖中我们讲了spring实例化bean的入口,refresh->finishBeanFactoryInitialization->preInstantiateSingletons->getBean->doGetBean,看doGetBean中的如下代码
if (mbd.isSingleton()) {
// 实例化bean
sharedInstance = getSingleton(beanName, () -> {
try {
// 真正的完成bean的创建
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
destroySingleton(beanName);
throw ex;
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
createBean
createBean(beanName, mbd, args);方法真正的完成了bean的实例化,包括循环依赖、AOP、生命周期等。
所谓的AOP无非就是将bean加强,在bean的方法前后加上其他的方法而已,bean的class在虚拟机启动的时候就加载到JVM里了,我们不会通过修改class来动态扩展bean的功能,但是可以新生成一个类(动态代理类),这个类呢,包含了bean的所有功能,同时又进行了加强,然后将这个动态代理类实例化,替换掉原有的bean,最后放到spring单例池中。
如果你的类没有被其他类依赖,那么可以在doCreateBean之前就创建好代理对象。
//给Bean后置处理器一个机会,返回一个替代目标对象的代理对象。
//就在这里
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
//注意如果有 InstantiationAwareBeanPostProcessor类型的接口
//并返回了自定义对象 这里会直接返回
return bean;
}
//如果上面直接返回了bean 下面的doCreateBean就不会执行
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
注意此时还没后面的bean初始化代码,这里AOP的准备工作,AOP实现是靠BeanPostProcessor后置处理器完成的。
BeanFactoryPostProcessor和BeanPostProcessors两者有啥区别?
BeanFactoryPostProcessor干预BeanDefinition的生成,而BeanPostProcessors干预bean的实例化。
// 给Bean后置处理器一个机会,返回一个替代目标对象的代理对象。
@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) {
//调用InstantiationAwareBeanPostProcessor的
//postProcessBeforeInstantiation
//参数是Class
bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
//这里返回的是null
if (bean != null) {
//调用BeanPostProcessor的 postProcessAfterInitialization
//注意是BeanPostProcessor
bean = applyBeanPostProcessorsAfterInitialization (bean, beanName);
}
}
}
mbd.beforeInstantiationResolved = (bean != null);
}
return bean;
}
这个resolveBeforeInstantiation()方法的意义到底是什么?
其实很简单,它的意思就是说,如果我们指定了targetSource,那么可以在这里创建一个代理直接返回,就不需要走下边的实例化和初始化阶段了,因为指定了targetSource后,这个bean就由开发人员自己负责完成创建了。而如果没有指定targetSource,那么就按照正常流程往下执行bean的实例化和初始化,说白了就是人家注释上说的:“给你一个返回代理的机会”。
protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
//for循环,拿到所有的BeanPostProcessors。
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
//判断是InstantiationAwareBeanPostProcessor
//强转为InstantiationAwareBeanPostProcessor
InstantiationAwareBeanPostProcessor ibp =
(InstantiationAwareBeanPostProcessor) bp;
//调用InstantiationAwareBeanPostProcessor的
//postProcessBeforeInstantiation方法
Object result = ibp.postProcessBeforeInstantiation
(beanClass, beanName);
if (result != null) {
return result;
}
}
}
//如果没有实现自定义的InstantiationAwareBeanPostProcessor
//这里返回的是null
return null;
}
注意这里收集到的是InstantiationAwareBeanPostProcessor InstantiationAwareBeanPostProcessor是BeanPostProcessor的子接口。如果applyBeanPostProcessorsBeforeInstantiation方法返回bean不为空,则实例化结束直接返回resolveBeforeInstantiation方法的返回值。不会执行下面的doCreateBean方法。
spring会遍历所有BeanPostProcessor,这么多后置处理器具体生成代理用到的是哪个?
答:AnnotationAwareAspectJAutoProxyCreator。
AnnotationAwareAspectJAutoProxyCreator继承自AbstractAutoProxyCreator。AbstractAutoProxyCreator是InstantiationAwareBeanPostProcessor类型,并且重写了postProcessBeforeInstantiation方法,所以此时进入AbstractAutoProxyCreator的方法,postProcessBeforeInstantiation方法如下:
postProcessBeforeInstantiation
此时生成代理的第一个时机都出现了,在postProcessBeforeInstantiation方法中生成代理
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
Object cacheKey = getCacheKey(beanClass, beanName);
if (!StringUtils.hasLength(beanName) ||
!this.targetSourcedBeans.contains(beanName)) {
//advisedBeans是一个集合,用来保存不需要代理的类。比如我们上面定义的切面
//本身是不需要被代理的,还有加了@Configuration注解的Config配置类,
//是不需要代理的,Config其实已经被代理了,之前讲过。
if (this.advisedBeans.containsKey(cacheKey)) {
return null;
}
//isInfrastructureClass(beanClass)
//判断我们这个业务类是否需要被代理,进入isInfrastructureClass代码
//判断Advice、Pointcut、Advisor是否是beanClass的超类或者超接口
//shouldSkip(beanClass, beanName)
//主要是判断beanName不为空且不是original instance
//2个条件都是false 说明需要代理
if (isInfrastructureClass(beanClass)
|| shouldSkip(beanClass, beanName)) {
//不需要代理
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return null;
}
}
//这里会做判断 如果 targetSource
//如果有自定义TargetSource
//将当前beanName放入targetSourcedBeans缓存中,直接走创建代理的分支
//不会走createBean去创建Bean,这里就是给一个机会。
//关于自定义TargetSource这个分支暂时不讲。
TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
//一般情况下targetSource为null不会走这个分支 直接返回null
//一般情况下targetSource为null不会走这个分支 直接返回null
//一般情况下targetSource为null不会走这个分支 直接返回null
if (targetSource != null) {
if (StringUtils.hasLength(beanName)) {
this.targetSourcedBeans.add(beanName);
}
//获取切面
Object[] specificInterceptors =
getAdvicesAndAdvisorsForBean(beanClass,
beanName,
targetSource);
//创建代理对象
Object proxy =
createProxy(beanClass,
beanName,
specificInterceptors,
targetSource);
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
return null;
}
if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) 这行代码就是判断我们这个业务类是否需要被代理,进入isInfrastructureClass代码:
//判断Advice、Pointcut、Advisor、AopInfrastructureBean
//是否是我们的beanClass的超类或者超接口
protected boolean isInfrastructureClass(Class<?> beanClass) {
return (super.isInfrastructureClass(beanClass) ||
(this.aspectJAdvisorFactory != null &&
this.aspectJAdvisorFactory.isAspect(beanClass)));
}
调用父类的方法
protected boolean isInfrastructureClass(Class<?> beanClass) {
//判断Advice、Pointcut、Advisor、AopInfrastructureBean
//是否是beanClass的超类或者超接口
boolean retVal = Advice.class.isAssignableFrom(beanClass) ||
Pointcut.class.isAssignableFrom(beanClass) ||
Advisor.class.isAssignableFrom(beanClass) ||
AopInfrastructureBean.class.isAssignableFrom(beanClass);
return retVal;
}
首先会调用父类的方法 class1.isAssignableFrom(class2) 判定此 Class1 对象所表示的类或接口与指定的 Class2 参数所表示的类或接口是否相同,或是否是其超类或超接口。
如果是则返回 true;否则返回 false。
Advice、Pointcut、Advisor等是跟切面相关的,不需要代理。 如果父类方法返回false,继续判断该类是不是一个切面,是切面的话也是不需要被代理的。
shouldSkip(beanClass, beanName)是判断beanName不为空且不是original instance。
如果2个条件都是false才会被代理 符合条件的放入advisedBeans 集合中,后面会根据这个集合判断业务类是否需要被代理。
上面只是判断是否需要代理。如果是不需要代理的class加入不需要代理的Map集合中。
TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
getCustomTargetSource(beanClass, beanName);一般情况下targetSource为null。
targetSource为null直接返回null的话就不会提前创建代理了。也就是说getCustomTargetSource方法如果返回TargetSource类型,那么if逻辑里会将当前bean加入this.targetSourcedBeans.add(beanName);并且为当前类生成代理,那么getCustomTargetSource方法逻辑是什么呢?我们进去看看
@Nullable
protected TargetSource getCustomTargetSource(Class<?> beanClass, String beanName) {
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;
}
先看第一个判断this.customTargetSourceCreators != null,首先要知道this是谁?
this是AbstractAutoProxyCreator,customTargetSourceCreators是他的属性
AbstractAutoProxyCreator暴露了一个方法
setCustomTargetSourceCreators(TargetSourceCreator... targetSourceCreators)
总结一下:那也就是说如果我们想要在bean实例化之前,就为类生成代理。我们需要调用 AbstractAutoProxyCreator#setCustomTargetSourceCreators来设置TargetSourceCreator。
继续往下看
如果customTargetSourceCreators成员有值,于是遍历该成员。
调用TargetSourceCreator#getTargetSource方法,方法逻辑如下
@Override
@Nullable
public final TargetSource getTargetSource(Class<?> beanClass, String beanName) {
//此处是模板模式会调用到AbstractBeanFactoryBasedTargetSourceCreator的具体子类方法中,
//具体子类方法会返回TargetSource
AbstractBeanFactoryBasedTargetSource targetSource =
createBeanFactoryBasedTargetSource(beanClass, beanName);
if (targetSource == null) {
return null;
}
if (logger.isDebugEnabled()) {
logger.debug("Configuring AbstractBeanFactoryBasedTargetSource: " + targetSource);
}
//拷贝1个新的internalBeanFactory
DefaultListableBeanFactory internalBeanFactory = getInternalBeanFactoryForBean(beanName);
// We need to override just this bean definition, as it may reference other beans
// and we're happy to take the parent's definition for those.
// Always use prototype scope if demanded.
BeanDefinition bd = this.beanFactory.getMergedBeanDefinition(beanName);
GenericBeanDefinition bdCopy = new GenericBeanDefinition(bd);
if (isPrototypeBased()) {
bdCopy.setScope(BeanDefinition.SCOPE_PROTOTYPE);
}
internalBeanFactory.registerBeanDefinition(beanName, bdCopy);
// Complete configuring the PrototypeTargetSource.
targetSource.setTargetBeanName(beanName);
//设置拷贝的internalBeanFactory到targetSource
targetSource.setBeanFactory(internalBeanFactory);
return targetSource;
}
AbstractBeanFactoryBasedTargetSourceCreator类是TargetSourceCreator接口的一个抽象实现类。
createBeanFactoryBasedTargetSource(beanClass, beanName);是标准的模板模式。
createBeanFactoryBasedTargetSource(beanClass, beanName);会调用到AbstractBeanFactoryBasedTargetSourceCreator的具体子类方法中,返回TargetSource。
接着往下看getInternalBeanFactoryForBean(beanName);创建一个新的BeanFactory,新的BeanFactory会拥有老的BeanFactory的属性。但需要注意的是,新BeanFactory的BeanPostProcessor集合里,去除了AbstractAutoProxyCreator类型,如下
protected DefaultListableBeanFactory getInternalBeanFactoryForBean(String beanName) {
synchronized (this.internalBeanFactories) {
DefaultListableBeanFactory internalBeanFactory=this.internalBeanFactories.get(beanName);
if (internalBeanFactory == null) {
internalBeanFactory = buildInternalBeanFactory(this.beanFactory);
this.internalBeanFactories.put(beanName, internalBeanFactory);
}
return internalBeanFactory;
}
}
protected DefaultListableBeanFactory buildInternalBeanFactory(ConfigurableBeanFactory containingFactory) {
// Set parent so that references (up container hierarchies) are correctly resolved.
DefaultListableBeanFactory internalBeanFactory
= new DefaultListableBeanFactory(containingFactory);
// 拷贝所有的BeanPostProcessor
internalBeanFactory.copyConfigurationFrom(containingFactory);
//排除了AOP核心组件对应的BeanPostProcessor
internalBeanFactory.getBeanPostProcessors().removeIf(beanPostProcessor ->
beanPostProcessor instanceof AopInfrastructureBean);
return internalBeanFactory;
}
我们可以看到是克隆一个原来的BeanFactory出来,然后将里面所有的AopInfrastructureBean组件都进行移除,而这个组件是什么?其实就是我们的AOP的核心组件,相当于就是将克隆出来的BeanFactory当中的所有AOP的组件全部remove掉。
参考链接:ac.nowcoder.com/discuss/826…
到此,类的代理对象就生成了,克隆出来的BeanFactory当中的所有AOP的组件被全部remove掉。所以之后的spring的实例化逻辑也不会生成代理了。
总结一下:如果我们想要在bean实例化之前,就为类生成代理,需要提供AbstractBeanFactoryBasedTargetSourceCreator的实现类。
调用代理对象方法
假设生成的是jdk代理。当调用对象方法时,会进入invoke方法。方法首先获取TargetSource对象
@Override
@Nullable
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
TargetSource targetSource = this.advised.targetSource;
Object target = null;
//调用getTarget获取原来的对象
target = targetSource.getTarget();
}
调用targetSource.getTarget();获取原来的对象.
在前言里提到的aop流程中,最终生成的TargetSource是SingletonTargetSource类型,于是获取到的target就是原来的对象。
而在上述流程中,我们是提前生成代理的,生成的TargetSource类型是我们钩子方法里自定义的,所以获取到的target取决于我们如何实现。
总结一下:如果我们想要在bean实例化之前,就为类生成代理,还需要提供TargetSource接口的实现。
下面我们自己来实现TargetSource相关接口。
使用TargetSource提前创建代理
日志接口
package target.source;
import org.springframework.stereotype.Component;
@Component
public interface LogService {
void print();
}
日志接口实现类
package target.source;
import org.springframework.stereotype.Component;
@Component
public class AopLog implements LogService {
public String log() {
System.out.println("----log----");
return "log";
}
@Override
public void print() {
System.out.println("----print----");
}
}
配置类
package target.source;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@EnableAspectJAutoProxy(proxyTargetClass = false)
@ComponentScan()
public class BeanConfig {
}
切面和切面表达式
package target.source;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.core.PriorityOrdered;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class Aop implements PriorityOrdered {
//指定切入点表达式,拦截那些方法,即为那些类生成代理对象
//@Pointcut("execution(* com.bie.aop.UserDao.save(..))") ..代表所有参数
//@Pointcut("execution(* com.bie.aop.UserDao.*())") 指定所有的方法
//@Pointcut("execution(* com.bie.aop.UserDao.save())") 指定save方法
@Pointcut("execution(* aop.*.*(..))")
public void pointCut(){
}
@Before("pointCut()")
public void Before(){
System.out.println("Before");
}
@After("pointCut()")
public void After(){
System.out.println("After");
}
@AfterThrowing("pointCut()")
public void AfterThrowing(){
System.out.println("AfterThrowing");
}
@AfterReturning("pointCut()")
public void AfterReturning(){
System.out.println("AfterReturning");
}
@Around("pointCut()")
public void Around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("Around Before");
joinPoint.proceed();
System.out.println("Around After");
}
@Override
public int getOrder() {
return 1;
}
}
根据上面的总结:如果我们想要在bean实例化之前,就为类生成代理:
1.需要提供AbstractBeanFactoryBasedTargetSourceCreator的实现类
2.需要提供TargetSource接口的实现。
3.需要调用 AbstractAutoProxyCreator#setCustomTargetSourceCreators来设置TargetSourceCreator。
下面就是开始做这些事情。
CustomTargetSourceCreator
1.需要提供AbstractBeanFactoryBasedTargetSourceCreator的实现类
package target.source;
import org.springframework.aop.framework.autoproxy.target.AbstractBeanFactoryBasedTargetSourceCreator;
import org.springframework.aop.target.AbstractBeanFactoryBasedTargetSource;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
public class CustomTargetSourceCreator extends AbstractBeanFactoryBasedTargetSourceCreator {
@Override
protected AbstractBeanFactoryBasedTargetSource createBeanFactoryBasedTargetSource(Class<?> beanClass, String beanName) {
if (getBeanFactory() instanceof ConfigurableListableBeanFactory) {
if(beanClass.isAssignableFrom(AopLog.class)) {
return new CustomTargetSource();
}
}
return null;
}
}
CustomTargetSource
2.需要提供TargetSource接口的实现。
package target.source;
import org.springframework.aop.target.AbstractBeanFactoryBasedTargetSource;
import java.io.Serializable;
public class CustomTargetSource extends AbstractBeanFactoryBasedTargetSource implements Serializable {
private static final long serialVersionUID = 5177019431887513952L;
@Override
public Object getTarget() throws Exception {
//此处获取的BeanFactory是上面拷贝出来的BeanFactory
return getBeanFactory().getBean(getTargetBeanName());
}
}
其中getBeanFactory()的值,是上述流程提到的新的BeanFactory。
由于该BeanFactory的BeanPostProcessor没有了AbstractAutoProxyCreator。
所以getBeanFactory().getBean(getTargetBeanName())获取的bean,一定是原生的bean,而不是代理对象。
CustomTargetSourceCreatorBeanPostProcessor
3.需要调用 AbstractAutoProxyCreator#setCustomTargetSourceCreators来设置TargetSourceCreator。
package target.source;
import org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.core.PriorityOrdered;
import org.springframework.stereotype.Component;
@Component
public class CustomTargetSourceCreatorBeanPostProcessor implements BeanPostProcessor, PriorityOrdered, BeanFactoryAware {
private BeanFactory beanFactory;
@Override
public int getOrder() {
return 45;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if(bean instanceof AnnotationAwareAspectJAutoProxyCreator) {
AnnotationAwareAspectJAutoProxyCreator creator
= (AnnotationAwareAspectJAutoProxyCreator)bean;
CustomTargetSourceCreator targetSourceCreator
= new CustomTargetSourceCreator();
targetSourceCreator.setBeanFactory(beanFactory);
creator.setCustomTargetSourceCreators(targetSourceCreator);
}
return bean;
}
//这里的BeanFactory是原生的BeanFactory
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
}
光写了CustomTargetSourceCreator 还不行,因为它必须作为AbstractAutoProxyCreator类的成员,所以我们需要给AbstractAutoProxyCreator的成员赋值。
此处我们自定义了CustomTargetSourceCreatorBeanPostProcessor。
到此,我们就完成了对StudentServiceImpl类型提前生成代理功能的整合。