这篇文章,我来了解一下是如何创建增强AOP代理的.我们已经知道做AOP代理的工作是AnnotationAwareAspectJAutoProxyCreator来做的,所以我们来理解一下这个类.
这个类实现了BeanPostProcessor,然后实现了其中的postProcessAfterInitialization的方法,这个方法的就是AOP操作的开始.而这个方法具体的实现是在它的父类中,我们找到这个方法
@Override
public Object postProcessAfterInitialization(@Nullable 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) {
if (StringUtils.hasLength(beanName) && 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;
}
最开始判断不需要创建代理的情况,并直接返回bean.
其中创建代理的代码为:
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
以上代码就是两个步骤:
- 获取增强方法或者是增强器
- 根据获取的增强来创建代理
我们先来看看是如何获取增强方法的
protected Object[] getAdvicesAndAdvisorsForBean(
Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
if (advisors.isEmpty()) {
return DO_NOT_PROXY;
}
return advisors.toArray();
}
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
List<Advisor> candidateAdvisors = findCandidateAdvisors();
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}
我们看下第二个方法中的两个核心方法findCandidateAdvisors和findAdvisorsThatCanApply.两个方法分别实现了获取增强和应用的先后功能.
获取增强器
findCandidateAdvisors是AnnotationAwareAspectJAutoProxyCreator实现的,因为是通过注解的方式,我们进入到这个方法中
@Override
protected List<Advisor> findCandidateAdvisors() {
// Add all the Spring advisors found according to superclass rules.
List<Advisor> advisors = super.findCandidateAdvisors();
// Build Advisors for all AspectJ aspects in the bean factory.
if (this.aspectJAdvisorsBuilder != null) {
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
}
return advisors;
}
分别实现了在配置文件中获取增强以及通过注解来获取增强.其中通过注解来获取增强的方法是this.aspectJAdvisorsBuilder.buildAspectJAdvisors()来实现的.我们进入到这个方法中去,我们只截取其中核心的代码
String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Object.class, true, false);
.....
for (String beanName : beanNames) {
.....
Class<?> beanType = this.beanFactory.getType(beanName);
if (beanType == null) {
continue;
}
if (this.advisorFactory.isAspect(beanType)) {
......
List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
......
}
for (String aspectName : aspectNames) {
List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);
if (cachedAdvisors != null) {
advisors.addAll(cachedAdvisors);
}
else {
MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);
advisors.addAll(this.advisorFactory.getAdvisors(factory));
}
}
}
大概步骤就是:
从容器中获取所有的bean,然后在其中寻找有注解标记的,对标记有@AspectJ注解的类进行增强器的提取,放入到缓存中.
List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
这句话就是增强器的提取,我们进入到这个代码中去:
我们看一下核心的代码:
Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName);
这个是对普通增强器的提取
public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
int declarationOrderInAspect, String aspectName) {
validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());
AspectJExpressionPointcut expressionPointcut = getPointcut(
candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
if (expressionPointcut == null) {
return null;
}
return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
}
getPointCut就是获取切点的信息,也就是对切点表达式的获取,比如说@Before("test()"),最后在进行注解的封装.现在已经获取到了切点的信息,然后就是根据切点的信息,生成增强.也就是这个方法InstantiationModelAwarePointcutAdvisorImpl.
public InstantiationModelAwarePointcutAdvisorImpl(AspectJExpressionPointcut declaredPointcut,
Method aspectJAdviceMethod, AspectJAdvisorFactory aspectJAdvisorFactory,
MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
this.declaredPointcut = declaredPointcut;
this.declaringClass = aspectJAdviceMethod.getDeclaringClass();
this.methodName = aspectJAdviceMethod.getName();
this.parameterTypes = aspectJAdviceMethod.getParameterTypes();
this.aspectJAdviceMethod = aspectJAdviceMethod;
this.aspectJAdvisorFactory = aspectJAdvisorFactory;
this.aspectInstanceFactory = aspectInstanceFactory;
this.declarationOrder = declarationOrder;
this.aspectName = aspectName;
if (aspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
// Static part of the pointcut is a lazy type.
Pointcut preInstantiationPointcut = Pointcuts.union(
aspectInstanceFactory.getAspectMetadata().getPerClausePointcut(), this.declaredPointcut);
// Make it dynamic: must mutate from pre-instantiation to post-instantiation state.
// If it's not a dynamic pointcut, it may be optimized out
// by the Spring AOP infrastructure after the first evaluation.
this.pointcut = new PerTargetInstantiationModelPointcut(
this.declaredPointcut, preInstantiationPointcut, aspectInstanceFactory);
this.lazy = true;
}
else {
// A singleton aspect.
this.pointcut = this.declaredPointcut;
this.lazy = false;
this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);
}
}
最开始就是单纯的赋值.不同的注解就是不同的增强逻辑,其中逻辑的实现就是在instantiateAdvice中完成的,其中就会根据不同的注解生成不同的增强器
switch (aspectJAnnotation.getAnnotationType()) {
case AtPointcut:
if (logger.isDebugEnabled()) {
logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
}
return null;
case AtAround:
springAdvice = new AspectJAroundAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtBefore:
springAdvice = new AspectJMethodBeforeAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtAfter:
springAdvice = new AspectJAfterAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtAfterReturning:
springAdvice = new AspectJAfterReturningAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
if (StringUtils.hasText(afterReturningAnnotation.returning())) {
springAdvice.setReturningName(afterReturningAnnotation.returning());
}
break;
case AtAfterThrowing:
springAdvice = new AspectJAfterThrowingAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();
if (StringUtils.hasText(afterThrowingAnnotation.throwing())) {
springAdvice.setThrowingName(afterThrowingAnnotation.throwing());
}
break;
default:
throw new UnsupportedOperationException(
"Unsupported advice type on method: " + candidateAdviceMethod);
}
通过AtBefore就生成了AspectJMethodBeforeAdvice的增强器,它是怎么使用的呢,这个时候我么要引入一个拦截器的类,如下面的代码:
public class MethodBeforeAdviceInterceptor implements MethodInterceptor, BeforeAdvice, Serializable {
private final MethodBeforeAdvice advice;
/**
* Create a new MethodBeforeAdviceInterceptor for the given advice.
* @param advice the MethodBeforeAdvice to wrap
*/
public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) {
Assert.notNull(advice, "Advice must not be null");
this.advice = advice;
}
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
return mi.proceed();
}
}
其中this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());调用的就是我们上面通过注解生成的AspectJMethodBeforeAdvice增强器,使用的就是其中
public void before(Method method, Object[] args, @Nullable Object target) throws Throwable {
invokeAdviceMethod(getJoinPointMatch(), null, null);
}
//然后一直找
return this.aspectJAdviceMethod.invoke(this.aspectInstanceFactory.getAspectInstance(), actualArgs);
调用的就是最后的invoke方法
以上就是获取增强器的过程,完成了所有增强器的解析,然后就是挑选出适合的增强器
寻找匹配的增强
这个比较简单,就是通过匹配class,来找出适合的增强器
创建代理
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
......
protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
@Nullable Object[] specificInterceptors, TargetSource targetSource) {
........
return proxyFactory.getProxy(getProxyClassLoader());
}
这个方法实际上就是先配置一下proxyFactory然后委托给proxyFactory创建代理.首先就是将增强器,放置到代理工厂去,完成了对增强的封装.然后就是代理的创建和获取了.
接下来就是创建代理了,两种方式jdk动态代理和cglib代理,那么spring是如何选择代理方式的呢?
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
这三个方面影响这spring的判断:
isOptimize:这个判断只对cglib代理有效,判断cglib代理是否使用激进的优化策略.
proxyTargetClass:这个为true时,目标类本身被代理,而不是目标类的接口,设置为true的话就是cglib的方式创建
hasNoUserSuppliedProxyInterfaces:是否存在代理接口.
然后就是对cglib代理和jdk动态代理的总结:
- 如果对象实现了接口,那么默认采用JDK的动态代理实现AOP
- 如果对象实现了接口,那么强制使用cglib代理实现AOP
-
如果没有实现接口,必须要采用cglib代理
在简单的JDK动态代理中,实现代理的核心就是InvocationHandler,在这个InvacationHandler中重写,三个函数
- 构造函数,将目标对象传入
- invoke方法,这个方法中实现了AOP增强的全部逻辑
- getProxy方法
我们发现JdkDynamicAopProxy实现了InvocationHandler,接口,自然也就有了invoke方法和getProxy方法,我们来看一下invoke方法,这里就是创建的代理的过程
invoke方法中
invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// Proceed to the joinpoint through the interceptor chain.
retVal = invocation.proceed();
JdkDynamicAopProxy的invoke方法就是创建一个拦截器的链,然后对链进行封装,然后在proceed方法中依次调用.