我们在上节中提到了AnnotationAwareAspectJAutoProxyCreator的类,其实这个类实现了BeanPostProcessor接口,所以Spring在加载Bean时,会先调用postProcessAfterInitialization方法。因此,笔者也从这里开始分析。下面先看一张AnnotationAwareAspectJAutoProxyCreator类的层次结构图。(相关资源可到这里下载:http://pan.baidu.com/s/1sjSo9a9)
在开始了解Spring的AOP代理的源码,我们按照惯例先来分析它的时序图。
1. AbstractAutoProxyCreator
在这个类中,我们主要是看postProcessAfterInitialization中的代码。在这个方法里,主要是根据给定的bean的class和name构建出个key,格式:beanClassName_beanName,同时,如果这个bean适合被代理,那么就要封装这个bean。当然,如果这个bean需要增强方法,那就要调用相应的方法来增强该类。
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean != null) {
//根据给定的bean的class和name构建出个key,格式:beanClassName_beanName
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (!this.earlyProxyReferences.contains(cacheKey)) {
//如果给它适合被代理,则需要封装指定bean
return <strong>wrapIfNecessary(bean, beanName, cacheKey);</strong>
}
}
return bean;
}
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
//如果已经处理过
if (beanName != null && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
//无需增强
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
//给定的bean是否代表一个基础设施类,基础设施类不应代理,或者配置了指定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 =<strong> getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);</strong>
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
//创建代理
Object proxy = <strong>createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));</strong>
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
2. AbstractAdvisorAutoProxyCreator
前面我们已经说了,对于有些bean是需要增强的,那么我们的程序就要调用相应的方法来处理增强。其实调用的就是上面提到的getAdvicesAndAdvisorsForBean的说方法。这个方法就是在AbstractAdvisorAutoProxyCreator的类,在方法中,首先要做的事情就是获取增强器,然后寻找匹配的增强器,这两个笔者将在下面会讲到。我们先来看getAdvicesAndAdvisorsForBean的方法,之后调用findEligibleAdvisors(),读者可以自己领悟。
protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, TargetSource targetSource) {
List<Advisor> advisors = <strong>findEligibleAdvisors(beanClass, beanName);</strong>
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;
}
3. AnnotationAwareAspectJAutoProxyCreator
我们继续跟踪findCandidateAdvisors()的方法,进入AnnotationAwareAspectJAutoProxyCreator的类当中。在这个方法中, 我们会发现在,不管是用注解还是用配置文件的AOP声明,其实都离不开对XML文件的读取。
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.
advisors.addAll(<strong>this.aspectJAdvisorsBuilder.buildAspectJAdvisors()</strong>);
return advisors;
}
4. BeanFactoryAspectJAdvisorsBuilder
在上面的类中,在findCandidateAdvisor()中我们最关心的是buildAspctJAdvisors()的方法。这个方法才是提取AspectJ注解的类的核心方法。Spring的源码如下。读者可以根据笔者的注解去解读。
public List<Advisor> buildAspectJAdvisors() {
List<String> aspectNames = null;
synchronized (this) {
aspectNames = this.aspectBeanNames;
if (aspectNames == null) {
List<Advisor> advisors = new LinkedList<Advisor>();
aspectNames = new LinkedList<String>();
//获取所有的beanName
String[] beanNames =
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.beanFactory, Object.class, true, false);
//循环所有的beanName找出对应的增强方法
for (String beanName : beanNames) {
//不合法的bean则略过,由子类定义规则,默认返回true
if (!isEligibleBean(beanName)) {
continue;
}
// We must be careful not to instantiate beans eagerly as in this
// case they would be cached by the Spring container but would not
// have been weaved
//获取对应的bean的类型
Class<?> beanType = this.beanFactory.getType(beanName);
if (beanType == null) {
continue;
}
//如果存在Aspect注解
if (this.advisorFactory.isAspect(beanType)) {
aspectNames.add(beanName);
AspectMetadata amd = new AspectMetadata(beanType, beanName);
if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
MetadataAwareAspectInstanceFactory factory =
new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
//解析标记AspectJ注解中的增强方法
List<Advisor> classAdvisors = <strong>this.advisorFactory.getAdvisors(factory)</strong>;
if (this.beanFactory.isSingleton(beanName)) {
this.advisorsCache.put(beanName, classAdvisors);
}
else {
this.aspectFactoryCache.put(beanName, factory);
}
advisors.addAll(classAdvisors);
}
else {
// Per target or per this.
if (this.beanFactory.isSingleton(beanName)) {
throw new IllegalArgumentException("Bean with name '" + beanName +
"' is a singleton, but aspect instantiation model is not singleton");
}
MetadataAwareAspectInstanceFactory factory =
new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
this.aspectFactoryCache.put(beanName, factory);
advisors.addAll(this.advisorFactory.getAdvisors(factory));
}
}
}
this.aspectBeanNames = aspectNames;
return advisors;
}
}
if (aspectNames.isEmpty()) {
return Collections.emptyList();
}
//记录在缓存中
List<Advisor> advisors = new LinkedList<Advisor>();
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));
}
}
return advisors;
}
5. ReflectiveAspectJAdvisorFactory
我们不能忽略的就是上面的方法中的this.advisorFactory.getAdvisors(factory)的方法调用了。这个方法是在ReflectiveAspectJAdvisorFactory的类中。在这个方法中也就是最为重要,也是为复杂的的增强器获取了。我们可以来品读一下getAdvisors()的方法。
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
//获取标记为AspectJ的类
Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
//获取标记为AspetJr的类
String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
//验证
validate(aspectClass);
// We need to wrap the MetadataAwareAspectInstanceFactory with a decorator
// so that it will only instantiate once.
MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);
List<Advisor> advisors = new LinkedList<Advisor>();
for (Method method : getAdvisorMethods(aspectClass)) {
Advisor advisor =<strong> getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName);</strong>
if (advisor != null) {
advisors.add(advisor);
}
}
// If it's a per target aspect, emit the dummy instantiating aspect.
if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
//如果寻找的增强不为空,而且又配置了增强延迟初始化,那么需要在首位加入同步实例化增强口器
Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
advisors.add(0, instantiationAdvisor);
}
// Find introduction fields.
//获取DeclareParents注解
for (Field field : aspectClass.getDeclaredFields()) {
Advisor advisor = getDeclareParentsAdvisor(field);
if (advisor != null) {
advisors.add(advisor);
}
}
return advisors;
}
在上面的函数中,对增强器的获取,最后是对DeclareParants注解的获取。增强器的获取逻辑是通过getAdvisor方法实现的,实现步骤包括对切入点的注解的获取以及根据注解信息生成增强。
public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
int declarationOrderInAspect, String aspectName) {
validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());
//节点信息的获取
AspectJExpressionPointcut expressionPointcut = <strong>getPointcut(
candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass())</strong>;
if (expressionPointcut == null) {
return null;
}
//根据切点信息生成增强器
return <strong>new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
this, aspectInstanceFactory, declarationOrderInAspect, aspectName);</strong>
}
对于切点信息的获取,可能读者有占迷糊,其实就是指定注解表达式的获取,如@Before(“test()”)。这里主要是调用getPointcut()的方法。
private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod, Class<?> candidateAspectClass) {
//获取方法上的注解
AspectJAnnotation<?> aspectJAnnotation =
AbstractAspectJAdvisorFactory.<strong>findAspectJAnnotationOnMethod(candidateAdviceMethod);</strong>
if (aspectJAnnotation == null) {
return null;
}
//使用AspetJExpressionPointcut实例封装获取的信息
AspectJExpressionPointcut ajexp =
new AspectJExpressionPointcut(candidateAspectClass, new String[0], new Class<?>[0]);
//提取得到的注解中的表达式。
ajexp.setExpression(aspectJAnnotation.getPointcutExpression());
return ajexp;
}
6. AbstractAspectJAdvisorFactory
在上面的类方法getPointcut()中,我们找到的findAspectJAnnotationOnMethod的方法,这个方法是存在AbstractAspectJAdvisorFactory类中的,所以我们继续跟踪,可以看到这个方法就是对所有敏感类的注解。看到这个地方的代码,相信读者可以“柳暗花明”了。
@SuppressWarnings("unchecked")
protected static AspectJAnnotation<?> findAspectJAnnotationOnMethod(Method method) {
//设置敏感的注解类
Class<?>[] classesToLookFor = new Class<?>[] {
<strong>Before.class, Around.class, After.class, AfterReturning.class, AfterThrowing.class, Pointcut.class</strong>};
for (Class<?> c : classesToLookFor) {
AspectJAnnotation<?> foundAnnotation = <strong>findAnnotation</strong>(method, (Class<Annotation>) c);
if (foundAnnotation != null) {
return foundAnnotation;
}
}
return null;
}
这里还有一个方法另忽略了,那就是findAnnotation,这里就是指定方法上的注解并使用AspectJAnnotation封装。
private static <A extends Annotation> AspectJAnnotation<A> findAnnotation(Method method, Class<A> toLookFor) {
A result = AnnotationUtils.findAnnotation(method, toLookFor);
if (result != null) {
return new AspectJAnnotation<A>(result);
}
else {
return null;
}
}
7. InstantiationModelAwarePointcutAdvisorImpl
相应读者并没有忘记前4.5中的getAdvisor()方法中的另外实例化的类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 = <strong>instantiateAdvice(this.declaredPointcut)</strong>;
}
}
在方法体的最后,我们看到了instantiateAdvice()的方法。这个方法体就是对不同的增强体做不同的处理。
private Advice instantiateAdvice(AspectJExpressionPointcut pcut) {
return this.aspectJAdvisorFactory.<strong>getAdvice(this.aspectJAdviceMethod, pcut,
this.aspectInstanceFactory, this.declarationOrder, this.aspectName);</strong>
}
8. ReflectiveAspectJAdvisorFactory
其实上面的对不同有增强做不同的处理,主要的还是getAdvice的方法中运行。
public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut,
MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
Class<?> candidateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
validate(candidateAspectClass);
AspectJAnnotation<?> aspectJAnnotation =
AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
if (aspectJAnnotation == null) {
return null;
}
// If we get here, we know we have an AspectJ method.
// Check that it's an AspectJ-annotated class
if (!isAspect(candidateAspectClass)) {
throw new AopConfigException("Advice must be declared inside an aspect type: " +
"Offending method '" + candidateAdviceMethod + "' in class [" +
candidateAspectClass.getName() + "]");
}
if (logger.isDebugEnabled()) {
logger.debug("Found AspectJ method: " + candidateAdviceMethod);
}
AbstractAspectJAdvice springAdvice;
switch (aspectJAnnotation.getAnnotationType()) {
case AtBefore:
springAdvice = new AspectJMethodBeforeAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
<strong>case AtAfter:</strong>
springAdvice = <strong>new AspectJAfterAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);</strong>
break;
<strong>case AtAfterReturning:</strong>
springAdvice = <strong>new AspectJAfterReturningAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);</strong>
AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
if (StringUtils.hasText(afterReturningAnnotation.returning())) {
springAdvice.setReturningName(afterReturningAnnotation.returning());
}
break;
<strong>case AtAfterThrowing</strong>:
springAdvice =<strong> new AspectJAfterThrowingAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();</strong>
if (StringUtils.hasText(afterThrowingAnnotation.throwing())) {
springAdvice.setThrowingName(afterThrowingAnnotation.throwing());
}
break;
<strong>case AtAround</strong>:
springAdvice = <strong>new AspectJAroundAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);</strong>
break;
case <strong>AtPointcut</strong>:
if (logger.isDebugEnabled()) {
logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
}
return null;
default:
throw new UnsupportedOperationException(
"Unsupported advice type on method: " + candidateAdviceMethod);
}
// Now to configure the advice...
springAdvice.setAspectName(aspectName);
springAdvice.setDeclarationOrder(declarationOrder);
String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);
if (argNames != null) {
springAdvice.setArgumentNamesFromStringArray(argNames);
}
springAdvice.calculateArgumentBindings();
return springAdvice;
}