Spring源码之创建AOP代理

来源:互联网 发布:植物精灵for mac 编辑:程序博客网 时间:2024/06/05 02:50

我们在上节中提到了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_beanNameObject cacheKey = getCacheKey(bean.getClass(), beanName);if (!this.earlyProxyReferences.contains(cacheKey)) {//如果给它适合被代理,则需要封装指定beanreturn <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>();//获取所有的beanNameString[] beanNames =BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.beanFactory, Object.class, true, false);//循环所有的beanName找出对应的增强方法for (String beanName : beanNames) {//不合法的bean则略过,由子类定义规则,默认返回trueif (!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 classif (!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;}
















0 0