1 何时创建代理
doCreateBean是短路操作
AnnotationAwareAspectJAutoProxyCreator(bean工厂级别postProcessor)在所有bean创建时进行了拦截,执行其中的postProcessBeforeInstantiation方法
1.1 postProcessBeforeInstantiation
调用时机
先来回顾一下此方法在Bean创建的过程中的调用时机。
AbstractAutowireCapableBeanFactory.createBean部分源码:
//// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
可以看出,调用发生在Bean实例的创建之前。
AbstractAutoProxyCreator.postProcessBeforeInstantiation:
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
//1.cacheKey的格式beanClassName_beanName
Object cacheKey = getCacheKey(beanClass, beanName);
//2 从缓存中拿 或 不需要代理直接返回null<br /> //2.1检查缓存已经生成直接返回<br /> if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {<br /> if (this.advisedBeans.containsKey(cacheKey)) {<br /> return null;<br /> }<br /> //2.2isInfrastructureClass检查基础类 如Advice、Pointcut、Advisor、AopInfrastructureBean<br /> // 2.2 shouldSkip检查 子类 aopAdvice和原始类 object String<br /> if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {<br /> this.advisedBeans.put(cacheKey, Boolean.FALSE);<br /> return null;<br /> }<br /> }
//3 创建代理对象并加入缓存
// Create proxy here if we have a custom TargetSource.<br /> // Suppresses unnecessary default instantiation of the target bean:<br /> // The TargetSource will handle target instances in a custom fashion.<br /> // 3.1 获取封装当前bean的TargetSource对象 SpringAOP代理不直接代理target,而需要通过代理TargetSource<br /> // 如果不存在,则直接退出当前方法,否则从TargetSource中获取当前bean对象,并且判断是否需要将切面逻辑应用在当前bean上<br /> TargetSource targetSource = getCustomTargetSource(beanClass, beanName);<br /> if (targetSource != null) {<br /> if (StringUtils.hasLength(beanName)) {<br /> this.targetSourcedBeans.add(beanName);<br /> }<br /> //3.2 获取能够应用当前bean的切面逻辑<br /> Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);<br /> //3.3 根据切面逻辑为当前bean生成代理对象<br /> Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);<br /> this.proxyTypes.put(cacheKey, proxy.getClass());<br /> return proxy;<br /> }
return null;<br /> }<br />
应该代理 ?
Spring首先会对当前的beanClass进行检查(是否应该/可以对其进行代理)。
不应该代理的类分为两种情况:
- 用于实现AOP的Spring基础类,此种情况在isInfrastructureClass方法中完成检测(单词Infrastructure正是基础设施的意思)。
- 子类定义的应该跳过的类,默认AbstractAutoProxyCreator的实现直接返回false,即都不应该跳过。
基础类检测
AbstractAutoProxyCreator.isInfrastructureClass:
protected boolean isInfrastructureClass(Class<?> beanClass) {
boolean retVal = Advice.class.isAssignableFrom(beanClass) ||
Pointcut.class.isAssignableFrom(beanClass) ||
Advisor.class.isAssignableFrom(beanClass) ||
AopInfrastructureBean.class.isAssignableFrom(beanClass);
return retVal;
}
可以看出,任何Advice、Pointcut、Advisor、AopInfrastructureBean的子类都被当做Spring实现AOP的基础设施类。跳过类检测
即shouldSkip方法。前面提到了,AbstractAutoProxyCreator的默认实现直接返回fasle,这一特性被子类AspectJAwareAdvisorAutoProxyCreator重写:
@Override
protected boolean shouldSkip(Class<?> beanClass, String beanName) {
ListcandidateAdvisors = findCandidateAdvisors();
for (Advisor advisor : candidateAdvisors) {
if (advisor instanceof AspectJPointcutAdvisor) {
if (((AbstractAspectJAdvice) advisor.getAdvice()).getAspectName().equals(beanName)) {
return true;
}
}
}
return super.shouldSkip(beanClass, beanName);
}
那么此方法跳过的是谁呢?
其实就是我们通过aop:aspect标签配置的切面,即:
里的aopAdvice。
从前面的aop:aspect一节中可以知道,Spring对于aop:config的解析其实是把aop:before/after等标签解析成为了AspectJPointcutAdvisor类型的BeanDefinition,而aopAdvice以AbstractAspectJAdvice的类型保存在其中。
所以可以得出结论: Spring跳过的是适用于当前bean的Advisor的Advice/Aspect对象。AOP逻辑
那么Spring又是如何找到适用于当前bean的Advisor的呢?
1:对于XML版本 AbstractAdvisorAutoProxyCreator.getAdvicesAndAdvisorsForBean
protected ListfindEligibleAdvisors(Class<?> beanClass, String beanName) {
//1.寻找所有候选的Advisors
ListcandidateAdvisors = findCandidateAdvisors();
//2.判断可以应用的Advisors、 引入introduction处理
ListeligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
//3扩展Advisor 子类向Advisor链表中添加自己的Advisor
extendAdvisors(eligibleAdvisors);
//4 Advisors排序
if (!eligibleAdvisors.isEmpty()) {
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}
2.对于注解版本
AnnotationAwareAspectJAutoProxyCreator.findCandidateAdvisors
protected ListfindCandidateAdvisors() {
// Add all the Spring advisors found according to superclass rules.
Listadvisors = super.findCandidateAdvisors();
// Build Advisors for all AspectJ aspects in the bean factory.
if (this.aspectJAdvisorsBuilder != null) {
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
}
return advisors;
}Advisor寻找
AbstractAdvisorAutoProxyCreator.getAdvicesAndAdvisorsForBean
关键便是findCandidateAdvisors方法,此方法将逻辑委托给BeanFactoryAdvisorRetrievalHelper.findAdvisorBeans:
public ListfindAdvisorBeans() {
String[] advisorNames = null;
synchronized (this) {
// 结果缓存
advisorNames = this.cachedAdvisorBeanNames;
if (advisorNames == null) {
// 去容器中寻找
advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Advisor.class, true, false);
this.cachedAdvisorBeanNames = advisorNames;
}
}
if (advisorNames.length == 0) {
return new LinkedList();
}
Listadvisors = new LinkedList ();
for (String name : advisorNames) {
if (isEligibleBean(name)) {
if (!this.beanFactory.isCurrentlyInCreation(name)) {
advisors.add(this.beanFactory.getBean(name, Advisor.class));
}
}
}
return advisors;
}
可以看出,首先是从容器中获取到所有的Advisor示例,然后调用isEligibleBean方法逐一判断Advisor是否适用于当前bean。适用性检测
指的便是isEligibleBean方法。最终调用的是AbstractAdvisorAutoProxyCreator的同名方法:
protected boolean isEligibleAdvisorBean(String beanName) {
return true;
}
而AbstractAdvisorAutoProxyCreator的子类AspectJAwareAdvisorAutoProxyCreator并没有覆盖此方法,所以此处会对容器中所有的Advisor的Advice进行跳过。检测结果缓存
因为postProcessBeforeInstantiation方法会在每个bean初始化之前被调用,所以没有必要每次都真的进行基础类检测和跳过类检测,Spring使用了advisedBeans作为缓存用以提高性能。TargetSource
从源码中可以看出,对于自定义的TargetSource,Spring会立即执行代理子类的创建。Spring的代理其实是针对TargetSource的,其类图:
关于此接口在此不展开叙述。1.2 postProcessAfterInitialization(解决早期对象的动态代理)
AbstractAutoProxyCreator.postProcessAfterInitialization:
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (!this.earlyProxyReferences.contains(cacheKey)) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
关键便在于wrapIfNecessary方法:
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
//自定义TargetSource,已经进行过代理子类生成
if (beanName != null && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// Create proxy if we have advice.
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
// 创建
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
可以看出,在此方法的开头又进行了基础类以及跳过类的检测,再次不再赘述。2 Advisor
2.1 Advisor
即getAdvicesAndAdvisorsForBean方法,这里进行的便是去容器中寻找适用于当前bean的Advisor,最终调用的是
AbstractAdvisorAutoProxyCreator.findEligibleAdvisors:
protected ListfindEligibleAdvisors(Class<?> beanClass, String beanName) {
ListcandidateAdvisors = findCandidateAdvisors();
ListeligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}
findCandidateAdvisors前面已经说过了。2.2 适用性判断
findAdvisorsThatCanApply最终调用AopUtils.findAdvisorsThatCanApply:
public static ListfindAdvisorsThatCanApply(List candidateAdvisors, Class<?> clazz) {
if (candidateAdvisors.isEmpty()) {
return candidateAdvisors;
}
ListeligibleAdvisors = new LinkedList ();
for (Advisor candidate : candidateAdvisors) {
if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
eligibleAdvisors.add(candidate);
}
}
boolean hasIntroductions = !eligibleAdvisors.isEmpty();
for (Advisor candidate : candidateAdvisors) {
if (candidate instanceof IntroductionAdvisor) {
// already processed
continue;
}
if (canApply(candidate, clazz, hasIntroductions)) {
eligibleAdvisors.add(candidate);
}
}
return eligibleAdvisors;
}
关键在于canApply方法,从源码中可以看出,对于Advisor的判断分为了IntroductionAdvisor以及非IntroductionAdvisor两种情况。
这种分开处理导致了IntroductionAdvisor在Advisor链中总是位于非IntroductionAdvisor前面。
canApply(candidate, clazz)其实等价于canApply(candidate, clazz, false):
public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
if (advisor instanceof IntroductionAdvisor) {
return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);
}
else if (advisor instanceof PointcutAdvisor) {
PointcutAdvisor pca = (PointcutAdvisor) advisor;
return canApply(pca.getPointcut(), targetClass, hasIntroductions);
}
else {
// It doesn’t have a pointcut so we assume it applies.
return true;
}
}
很明显,对于引入Advisor与其它Advisor是两种不同的判断方式。引入
引入的概念在下面aop:scoped-proxy中有提到。因为引入的目的在于动态地向一个类添加另一种功能(接口),所以只要判断给定的类是否是要引入到的类即可。其它
AopUtils.canApply:
public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
//是否Pointcut可以匹配当前类
if (!pc.getClassFilter().matches(targetClass)) {
return false;
}
MethodMatcher methodMatcher = pc.getMethodMatcher();
//是否Pointcut可以匹配所有方法
if (methodMatcher == MethodMatcher.TRUE) {
// No need to iterate the methods if we’re matching any method anyway…
return true;
}
IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
}
Set> classes = new LinkedHashSet >
(ClassUtils.getAllInterfacesForClassAsSet(targetClass));
classes.add(targetClass);
for (Class<?> clazz : classes) {
Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
for (Method method : methods) {
if ((introductionAwareMethodMatcher != null &&
introductionAwareMethodMatcher
.matches(method, targetClass, hasIntroductions)) ||
methodMatcher.matches(method, targetClass)) {
return true;
}
}
}
return false;
}
Spring的Pointcut由ClassFilter和MethodMatcher两部分组成,其中前者用以判断给定的类是否在Pointcut的匹配范围内,后者用以在ClassFilter匹配满足的情况下判断给定的方法是否在Pointcut匹配的范围内。
从源码中可以看出,如果ClassFilter匹配得到满足并且Pointcut并不能匹配此类的任意方法,便会用反射的方法获取targetClass(被检测类)的全部方法逐一交由Pointcut的MethodMatcher进行检测。
关于Pointcut表达式是如何解析及存储的在此不再展开。Advisor扩展
AbstractAdvisorAutoProxyCreator.extendAdvisors允许子类向Advisor链表中添加自己的Advisor。子类AspectJAwareAdvisorAutoProxyCreator重写了此方法,其逻辑是:
如果Advisor链表中的Advisor含有AspectJ Advice,那么将会把一个ExposeInvocationInterceptor添加到链表的表头,目的在于将MethodInvocation以ThreadLocal的方式暴露给后面所有的Advisor,暂不知道具体的用途。2.4 排序
即sortAdvisors方法,用于对实现了Ordered接口的Advisor进行排序。
3 getAdvicesAndAdvisors 转换 Interceptor
4 创建代理
AbstractAutoProxyCreator.createProxy(略去非关键代码):
protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
@Nullable Object[] specificInterceptors, TargetSource targetSource) {
if (this.beanFactory instanceof ConfigurableListableBeanFactory) {<br /> AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);<br /> }
ProxyFactory proxyFactory = new ProxyFactory();<br /> //1.拷贝当前类的属性<br /> proxyFactory.copyFrom(this);
// 2.判断不是TargetClass<br /> if (!proxyFactory.isProxyTargetClass()) {<br /> if (shouldProxyTargetClass(beanClass, beanName)) {<br /> proxyFactory.setProxyTargetClass(true);<br /> }<br /> else {<br /> evaluateProxyInterfaces(beanClass, proxyFactory);<br /> }<br /> }
// 3 可能是 advise advise需要warp成DefaultPointcutAdvisor 或Advisor<br /> Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);<br /> //4 设置要Advisor封装到proxyFactory 将interceptor适配为Advisor<br /> proxyFactory.addAdvisors(advisors);<br /> //5.<br /> proxyFactory.setTargetSource(targetSource);<br /> //6 定制代理工作<br /> customizeProxyFactory(proxyFactory);<br /> //7 缺省为false 即创建后不允许修改<br /> proxyFactory.setFrozen(this.freezeProxy);<br /> if (advisorsPreFiltered()) {<br /> proxyFactory.setPreFiltered(true);<br /> }<br /> // 8获得代理 cglib或jdk 动态代理<br /> return proxyFactory.getProxy(getProxyClassLoader());<br /> }
4.1 JDK动态代理 or Cglib
由DefaultAopProxyFactory.createAopProxy方法决定使用何种方式创建代理子类。
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
if (config.isOptimize() || config.isProxyTargetClass() ||
hasNoUserSuppliedProxyInterfaces(config)) {
Class<?> targetClass = config.getTargetClass();
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
return new ObjenesisCglibAopProxy(config);
} else {
return new JdkDynamicAopProxy(config);
}
}
Optimize 且没有实现接口 使用JdkDynamicAopProxy
代理类本身是接口或isProxyClass 使用jdk
逻辑很明显,如果指定了(proxy-target-classs设为true)使用Cglib,那么就会使用Cglib的方式,如果没有指定(或为false),那么先回检测被代理类是否实现了自己的接口,如果实现了,那么就采用JDK动态代理的方式。
4.2 使用JDK动态代理
JdkDynamicAopProxy.getProxy:
@Override
public Object getProxy(ClassLoader classLoader) {
//找到可以用来进行代理的接口
Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
//用来代理的接口中是否定义了equals或者是hashCode方法?
//结果保存在内部equalsDefined和hashCodeDefined两个成员变量中
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
可以看出,关键的InvocationHandler参数其实就是JdkDynamicAopProxy自身。
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
TargetSource targetSource = this.advised.targetSource;<br /> Object target = null;
try {<br /> //1.Equals方法<br /> if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {<br /> // The target does not implement the equals(Object) method itself.<br /> return equals(args[0]);<br /> }<br /> //2.hashCode方法<br /> else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {<br /> // The target does not implement the hashCode() method itself.<br /> return hashCode();<br /> }<br /> else if (method.getDeclaringClass() == DecoratingProxy.class) {<br /> // There is only getDecoratedClass() declared -> dispatch to proxy config.<br /> return AopProxyUtils.ultimateTargetClass(this.advised);<br /> }<br /> //3<br /> else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&<br /> method.getDeclaringClass().isAssignableFrom(Advised.class)) {<br /> // Service invocations on ProxyConfig with the proxy config...<br /> return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);<br /> }
Object retVal;
//4 处理expose属性,将本代理加入缓存中<br /> if (this.advised.exposeProxy) {<br /> // Make invocation available if necessary.<br /> oldProxy = AopContext.setCurrentProxy(proxy);<br /> setProxyContext = true;<br /> }
// Get as late as possible to minimize the time we "own" the target,<br /> // in case it comes from a pool.<br /> target = targetSource.getTarget();<br /> Class<?> targetClass = (target != null ? target.getClass() : null);
// Get the interception chain for this method.<br /> //5 获得当前方法的调用链<br /> List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
// Check whether we have any advice. If we don't, we can fallback on direct<br /> // reflective invocation of the target, and avoid creating a MethodInvocation.<br /> //6.判断调用链是否为空<br /> if (chain.isEmpty()) {<br /> // We can skip creating a MethodInvocation: just invoke the target directly<br /> // Note that the final invoker must be an InvokerInterceptor so we know it does<br /> // nothing but a reflective operation on the target, and no hot swapping or fancy proxying.<br /> //6.1调用链是为空,直接调用invokeJoinpointUsingReflection<br /> Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);<br /> retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);<br /> }<br /> else {<br /> // We need to create a method invocation...<br /> //6.2调用链不为空,封装调用ReflectiveMethodInvocation<br /> MethodInvocation invocation =<br /> new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);<br /> // Proceed to the joinpoint through the interceptor chain.<br /> //6.3 执行拦截器<br /> retVal = invocation.proceed();<br /> }
// Massage return value if necessary.<br /> Class<?> returnType = method.getReturnType();<br /> if (retVal != null && retVal == target &&<br /> returnType != Object.class && returnType.isInstance(proxy) &&<br /> !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {<br /> // Special case: it returned "this" and the return type of the method<br /> // is type-compatible. Note that we can't help if the target sets<br /> // a reference to itself in another returned object.<br /> retVal = proxy;<br /> }<br /> else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {<br /> throw new AopInvocationException(<br /> "Null return value from advice does not match primitive return type for: " + method);<br /> }<br /> return retVal;<br /> }<br /> finally {<br /> if (target != null && !targetSource.isStatic()) {<br /> // Must have come from TargetSource.<br /> targetSource.releaseTarget(target);<br /> }<br /> if (setProxyContext) {<br /> // Restore old proxy.<br /> AopContext.setCurrentProxy(oldProxy);<br /> }<br /> }<br /> }
equals & hashCode
如果被代理类实现了equals或者是hashCode方法,那么生成的代理子类的equals、hashCode方法实际上执行的是JdkDynamicAopProxy相应方法的逻辑。
invoke方法部分源码:
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
// The target does not implement the equals(Object) method itself.
return equals(args[0]);
}
链式调用
对于切点方法,比如前面aop:aspect示例配置中的beforeSend
Spring会创建一个MethodInvocation对象对所有相关的Advisor进行链式调用。invoke相关源码:
List