对于指定bean的增强方法的获取一定是包含两个步骤的:

  1. 获取所有的增强
  2. 寻找所有增强中使用于bean的增强并应用

那么findCandidateAdvisors与findAdvisorsThatCanApply便是做了这两件事情。当然,如果无法找到对应的增强器便返回DO_NOT_PROXY,其中DO_NOT_PROXY=null.

protected Object[] getAdvicesAndAdvisorsForBean(Class beanClass, String beanName, TargetSource targetSource)
{
List advisors = findEligibleAdvisors(beanClass, beanName);
if(advisors.isEmpty())
return DO_NOT_PROXY;
else
return advisors.toArray();
}
protected List findEligibleAdvisors(Class beanClass, String beanName)
{
  //获取所有的增强器
List candidateAdvisors = findCandidateAdvisors();
  //获取适合beanname的增强器
List eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
extendAdvisors(eligibleAdvisors);
if(!eligibleAdvisors.isEmpty())
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
return eligibleAdvisors;
}

所有增强器的获取

由于分析的是使用注解进行的AOP,所以对于findCandidateAdvisors的实现其实是由AnnotationAwareAspectJAutoProxyCreator类完成的,我们继续跟踪AnnotationAwareAspectJAutoProxyCreator的findCandidateAdvisors方法。

protected List findCandidateAdvisors()
{
//当使用注解方式配置AOP的时候并不是丢弃了对XML配置的支持。
//在这里调用父类方法加载配置文件中的AOP声明
List advisors = super.findCandidateAdvisors();
//Build Advisors for all AspectJ aspects in the bean factory
advisors.addAll(aspectJAdvisorsBuilder.buildAspectJAdvisors());
return advisors;
}

AnnotationAwareAspectJAutoProxyCreator间接继承了AbstractAdvisorAutoProxyCreator,在实现获取增强的方法中除了保留父类的获取配置文件中定义的增强外,同时添加了获取Bean的注解增强的功能,那么其实现正是由this.aspectJAdvisorsBuilder.buildAspectJAdvisors()来实现的。

(1)获取所有beanName,这一步骤中所有在beanFactory中注册的Bean都会被提取出来。

(2)遍历所有beanName,并找出声明AspectJ注解的类,进行进一步的处理。

(3)对标记为AspectJ注解的类进行增强器的提取。

(4)将提取结果加入缓存。

提取Advisor

现在来看看函数实现,对Spirng中所有的类进行分析,提取Advisor。

public List buildAspectJAdvisors()
{
List aspectNames = null;
synchronized(this){
aspectNames = aspectBeanNames;
if(aspectNames == null)
{
List advisors = new LinkedList();
aspectNames = new LinkedList();
//获取所有的beanName
String beanNames[] = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, java/lang/Object, true, false);
//循环所有的beanName找出对应的增强方法
for(String beanName : beanNames)
{
//不合法的bean则略过,由子类定义规则,默认返回true
if(!isEligibleBean(beanName))
continue;
//获取对应的bean的类型
Class beanType = beanFactory.getType(beanName);
//如果存在Aspect注解
if(beanType == null || !advisorFactory.isAspect(beanType))
continue;
aspectNames.add(beanName);
AspectMetadata amd = new AspectMetadata(beanType, beanName);
MetadataAwareAspectInstanceFactory factory;
if(amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON)
{
factory = new BeanFactoryAspectInstanceFactory(beanFactory, beanName);
//解析标记AspectJ注解中的增强方法
List classAdvisors = advisorFactory.getAdvisors(factory);
if(beanFactory.isSingleton(beanName))
advisorsCache.put(beanName, classAdvisors);
else
aspectFactoryCache.put(beanName, factory);
advisors.addAll(classAdvisors);
continue;
}
if(beanFactory.isSingleton(beanName))
throw new IllegalArgumentException((
                    new StringBuilder()).append("Bean with name '")
                                .append(beanName)
                                .append("' is a singleton, but aspect instantiation model is not singleton")
                                .toString());
factory = new PrototypeAspectInstanceFactory(beanFactory, beanName);
aspectFactoryCache.put(beanName, factory);
advisors.addAll(advisorFactory.getAdvisors(factory));
} aspectBeanNames = aspectNames;
return advisors; }

至此,已经完成了Advisor的提取。

切点信息的获取

在上面的步骤中最为重要也最为繁杂的就是增强器的获取,而这一切功能委托给了getAdvisors方法去实现(this.advisorFactory.getAdvisors(factory))。

    public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory maaif) {
     //获取标记为AspectJ的类
final Class<?> aspectClass = maaif.getAspectMetadata().getAspectClass();
     //获取标记为AspectJ的name
final String aspectName = maaif.getAspectMetadata().getAspectName();
     //验证
validate(aspectClass);
final MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
new LazySingletonAspectInstanceFactoryDecorator(maaif);
final List<Advisor> advisors = new LinkedList<Advisor>();
for (Method method : getAdvisorMethods(aspectClass)) {
Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName);
if (advisor != null) {
advisors.add(advisor);
}
}
     //如果寻找的增强器不为空而且又配置了增强延迟初始化那么需要在首位加入同步实例化增强器
if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
advisors.add(0, instantiationAdvisor);
}
     //对DeclareParents注解的获取
for (Field field : aspectClass.getDeclaredFields()) {
Advisor advisor = getDeclareParentsAdvisor(field);
if (advisor != null) {
advisors.add(advisor);
}
}
return advisors;
}

函数中首先完成了增强器的获取,包括获取注解以及根据注解生成增强的步骤,然后考虑到在配置中可能会将增强配置成延迟初始化,那么需要在首位加入同步实例化增强器以保证增强使用之前的实例化,最后是对DeclareParents注解的获取。

普通增强器的获取逻辑通过getAdvisor方法实现,实现步骤包括对切点的注解的获取及根据注解信息生成增强。

(1)切点信息的获取。所谓获取切点信息就是指定注解的表达式信息的获取,如@Before("test()")

public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aif, int declarationOrderInAspect, String aspectName)
{
validate(aif.getAspectMetadata().getAspectClass());
//切点信息的获取
AspectJExpressionPointcut ajexp = getPointcut(candidateAdviceMethod, aif.getAspectMetadata().getAspectClass());
if(ajexp == null)
return null;
else
//根据切点信息生成增强器
return new InstantiationModelAwarePointcutAdvisorImpl(this, ajexp, aif, candidateAdviceMethod, declarationOrderInAspect, aspectName);
} private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod, Class<?> candidateAspectClass) {
//获取方法上的注解
AspectJAnnotation<?> aspectJAnnotation =
AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
if (aspectJAnnotation == null) {
return null;
}
//使用AspectJExpressionPointcut实例封装获取的信息
AspectJExpressionPointcut ajexp =
new AspectJExpressionPointcut(candidateAspectClass, new String[0], new Class[0]);
//提取得到的注解中的表达式如:@Pointcut("execution(* *.*test*(..))")中的execution(* *.*test*(..))
ajexp.setExpression(aspectJAnnotation.getPointcutExpression());
return ajexp;
} protected static AspectJAnnotation findAspectJAnnotationOnMethod(Method method) {
//设置敏感的注解类
Class<? extends Annotation>[] classesToLookFor = new Class[] {
Before.class, Around.class, After.class, AfterReturning.class, AfterThrowing.class, Pointcut.class};
for (Class<? extends Annotation> c : classesToLookFor) {
AspectJAnnotation foundAnnotation = findAnnotation(method, c);
if (foundAnnotation != null) {
return foundAnnotation;
}
}
return null;
}
//获取指定方法上的注解并使用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;
}
}

(2)根据切点信息生成增强。所有的增强都有Advisor实现类InstantiationModelAwarePontcutAdvisorImpl统一封装。

public InstantiationModelAwarePointcutAdvisorImpl(AspectJAdvisorFactory af, AspectJExpressionPointcut ajexp,
MetadataAwareAspectInstanceFactory aif, Method method, int declarationOrderInAspect, String aspectName) { this.declaredPointcut = ajexp;
this.method = method;
this.atAspectJAdvisorFactory = af;
this.aspectInstanceFactory = aif;
this.declarationOrder = declarationOrderInAspect;
this.aspectName = aspectName; if (aif.getAspectMetadata().isLazilyInstantiated()) {
Pointcut preInstantiationPointcut =
Pointcuts.union(aif.getAspectMetadata().getPerClausePointcut(), this.declaredPointcut);
this.pointcut = new PerTargetInstantiationModelPointcut(this.declaredPointcut, preInstantiationPointcut, aif);
this.lazy = true;
}
else {
this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);
this.pointcut = declaredPointcut;
this.lazy = false;
}
}

封装过程只是简单地将信息封装在类的实例中,所有的信息单纯地复制。在实例初始化的过程中还完成了对于增强器的初始化。因为不同的增强所体现的逻辑是不同的,比如@Before(“test()”)与After(“test()”)标签的不同就是增强器增强的位置不同,所以就需要不同的增强器来完成不同的逻辑,而根据注解中的信息初始化对应的增强器就是在instantiateAdvice函数中实现的。

private Advice instantiateAdvice(AspectJExpressionPointcut pcut)
{
return atAspectJAdvisorFactory.getAdvice(method, pcut, aspectInstanceFactory, declarationOrder, aspectName);
}
public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut ajexp,
          MetadataAwareAspectInstanceFactory aif, int declarationOrderInAspect, String aspectName)
{
Class candidateAspectClass = aif.getAspectMetadata().getAspectClass();
validate(candidateAspectClass);
AbstractAspectJAdvisorFactory.AspectJAnnotation aspectJAnnotation =
              AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
if(aspectJAnnotation == null)
return null;
if(!isAspect(candidateAspectClass))
throw new AopConfigException(
            (new StringBuilder())
                  .append("Advice must be declared inside an aspect type: Offending method '")
                  .append(candidateAdviceMethod)
                  .append("' in class [")
                  .append(candidateAspectClass.getName())
                  .append("]").toString());
if(logger.isDebugEnabled())
logger.debug((new StringBuilder()).append("Found AspectJ method: ").append(candidateAdviceMethod).toString());
AbstractAspectJAdvice springAdvice;
switch(SwitchMap.org.springframework.aop.aspectj.annotation.AbstractAspectJAdvisorFactory.AspectJAnnotationType
            [aspectJAnnotation.getAnnotationType().ordinal()])
{
case 1: // '\001'
springAdvice = new AspectJMethodBeforeAdvice(candidateAdviceMethod, ajexp, aif);
break; case 2: // '\002'
springAdvice = new AspectJAfterAdvice(candidateAdviceMethod, ajexp, aif);
break; case 3: // '\003'
springAdvice = new AspectJAfterReturningAdvice(candidateAdviceMethod, ajexp, aif);
AfterReturning afterReturningAnnotation = (AfterReturning)aspectJAnnotation.getAnnotation();
if(StringUtils.hasText(afterReturningAnnotation.returning()))
springAdvice.setReturningName(afterReturningAnnotation.returning());
break; case 4: // '\004'
springAdvice = new AspectJAfterThrowingAdvice(candidateAdviceMethod, ajexp, aif);
AfterThrowing afterThrowingAnnotation = (AfterThrowing)aspectJAnnotation.getAnnotation();
if(StringUtils.hasText(afterThrowingAnnotation.throwing()))
springAdvice.setThrowingName(afterThrowingAnnotation.throwing());
break; case 5: // '\005'
springAdvice = new AspectJAroundAdvice(candidateAdviceMethod, ajexp, aif);
break; case 6: // '\006'
if(logger.isDebugEnabled())
logger.debug(
              (new StringBuilder()).append("Processing pointcut '")
                           .append(candidateAdviceMethod.getName())
                           .append("'").toString());
return null; default:
throw new UnsupportedOperationException(
            (new StringBuilder()).append("Unsupported advice type on method ")
                         .append(candidateAdviceMethod).toString());
}
springAdvice.setAspectName(aspectName);
springAdvice.setDeclarationOrder(declarationOrderInAspect);
String argNames[] = parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);
if(argNames != null)
springAdvice.setArgumentNamesFromStringArray(argNames);
springAdvice.calculateArgumentBindings();
return springAdvice;
}
}

从函数中可以看到,Spring会根据不同的注解生成不同的增强器,例如AtBefore会对应AspectJMethodBeforeAdvice。

增加同步实例化增强器

如果寻找的增强器不为空而且又配置了增强延迟初始化,那么就需要在首位加入同步实例化增强器。

    protected static class SyntheticInstantiationAdvisor extends DefaultPointcutAdvisor {
public SyntheticInstantiationAdvisor(final MetadataAwareAspectInstanceFactory aif) {
super(aif.getAspectMetadata().getPerClausePointcut(), new MethodBeforeAdvice() {
@Override
public void before(Method method, Object[] args, Object target) {
// Simply instantiate the aspect
aif.getAspectInstance();
}
});
}
}

获取DeclareParents注解

DeclareParents主要用于引介增强的注解形式的实现,而其实现方式驭普通增强很类似,只不过使用DeclareParentsAdvisor对功能进行封装。

引介是一种特殊的增强,它为类添加一些属性和方法。这样,即使一个业务类原本没有实现某个接口,通过引介功能,可以动态的未该业务类添加接口的实现逻辑,让业务类成为这个接口的实现类。

private Advisor getDeclareParentsAdvisor(Field introductionField)
{
DeclareParents declareParents = (DeclareParents)introductionField.getAnnotation(org/aspectj/lang/annotation/DeclareParents);
if(declareParents == null)
return null;
if("org/aspectj/lang/annotation/DeclareParents".equals(declareParents.defaultImpl()))
throw new IllegalStateException("defaultImpl must be set on DeclareParents");
else
return new DeclareParentsAdvisor(introductionField.getType(), declareParents.value(), declareParents.defaultImpl());
}

至此已经完成了所有增强器的解析,但是对于所有增强器来讲,并不一定都适用于当前的Bean,还要挑取除适合的增强器,也就是满足我们配置的通配符的增强器。具体的实现在findAdvisorsThatCanApply中。

获取合适的增强器

findAdvisorsThatCanApply函数的主要功能是寻找所有增强器中适用于当前class的增强器。对于真是的匹配在canApply中实现。

protected List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class beanClass, String beanName) {
ProxyCreationContext.setCurrentProxiedBeanName(beanName);
try {
return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
}
finally {
ProxyCreationContext.setCurrentProxiedBeanName(null);
}
}
public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
if (candidateAdvisors.isEmpty()) {
return candidateAdvisors;
}
List<Advisor> eligibleAdvisors = new LinkedList<Advisor>();
//首先处理引介增强
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) {
continue;
}
//对于普通bean的处理
if (canApply(candidate, clazz, hasIntroductions)) {
eligibleAdvisors.add(candidate);
}
}
return eligibleAdvisors;
}
public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
Assert.notNull(pc, "Pointcut must not be null");
if (!pc.getClassFilter().matches(targetClass)) {
return false;
}
MethodMatcher methodMatcher = pc.getMethodMatcher();
IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
}
Set<Class> classes = new LinkedHashSet<Class>(ClassUtils.getAllInterfacesForClassAsSet(targetClass));
classes.add(targetClass);
for (Class<?> clazz : classes) {
Method[] methods = clazz.getMethods();
for (Method method : methods) {
if ((introductionAwareMethodMatcher != null &&
introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions)) ||
methodMatcher.matches(method, targetClass)) {
return true;
}
}
}
return false;
}
 

AOP动态代理解析3-增强方法的获取的更多相关文章

  1. AOP动态代理解析4-代理的创建

    做完了增强器的获取后就可以进行代理的创建了 AnnotationAwareAspectJAutoProxyCreator->postProcessAfterInitialization-> ...

  2. AOP动态代理解析1-标签的解析

    spring.handlers http\://www.springframework.org/schema/aop=org.springframework.aop.config.AopNamespa ...

  3. AOP动态代理解析4-jdk代理的实现

    JDKProxy的使用关键是创建自定义的InvocationHandler,而InvocationHandler中包含了需要覆盖的函数getProxy,而当前的方法正是完成了这个操作.在此确认一下JD ...

  4. AOP动态代理解析2-代码织入入口

    通过自定义配置完成了对AnnotationAwareAspectJAutoProxyCreator类型的自动注册,那么这个类到底做了什么工作来完成AOP的操作呢?首先我们看看AnnotationAwa ...

  5. AOP动态代理解析5-cglib代理的实现

    CGLIB是一个强大的高性能的代码生成包.它广泛地被许多AOP的框架使用,例如Spring AOP和dynaop,为他们提供方法的Interception(拦截).EasyMock和jMock是通过使 ...

  6. Java 动态代理 两种实现方法

    AOP的拦截功能是由java中的动态代理来实现的.说白了,就是在目标类的基础上增加切面逻辑,生成增强的目标类(该切面逻辑或者在目标类函数执行之前,或者目标类函数执行之后,或者在目标类函数抛出异常时候执 ...

  7. 技术的正宗与野路子 c#, AOP动态代理实现动态权限控制(一) 探索基于.NET下实现一句话木马之asmx篇 asp.net core 系列 9 环境(Development、Staging 、Production)

    黄衫女子的武功似乎与周芷若乃是一路,飘忽灵动,变幻无方,但举手抬足之间却是正而不邪,如说周芷若形似鬼魅,那黄衫女子便是态拟神仙. 这段描写出自<倚天屠龙记>第三十八回. “九阴神抓”本是& ...

  8. Spring ( 四 )Spring的AOP动态代理、切面编程

    个人博客网:https://wushaopei.github.io/    (你想要这里多有) 一.AOP切面编程 1.什么是AOP AOP是面向切面编程.全称:Aspect Oriented Pro ...

  9. Spring学习笔记之aop动态代理(3)

    Spring学习笔记之aop动态代理(3) 1.0 静态代理模式的缺点: 1.在该系统中有多少的dao就的写多少的proxy,麻烦 2.如果目标接口有方法的改动,则proxy也需要改动. Person ...

随机推荐

  1. JSON数据格式

    JSON 数据格式 JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式.JSON采用完全独立于语言的文本格式,这些特性使JSON成为理想的数据交换语言.易于人 ...

  2. ExpandableListView的用法

    ExpandableListView组件是android中一个比较常用的组件,当点击一个父item的时候可以将它的子item显示出来,像手机QQ中的好友列表就是实现的类型效果.使用Expandable ...

  3. August 17th 2016 Week 34th Wednesday

    Life is painting a picture, not doing a sum. 生活就像是绘画,而不是做算术. I am too serious about digits. All what ...

  4. July 8th, Week 28th Friday, 2016

    Care and diligence bring luck. 谨慎和勤奋带来好运气. Just as we have said before, diligence is the mother of g ...

  5. centOS填坑笔记(一)

    第一次使用centOS安装软件时,对二进制包的./configure进行配置时(./configure是源代码安装的第一步,主要的作用是对即将安装的软件进行配置,)报错:WARNING: failed ...

  6. maven配置httpclient3.X jar包

    <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging& ...

  7. C++中实现对象的clone()

    在C#中,许多对象自动实现了clone函数,在C++中,要拷贝一个对象,除了自定义一个拷贝构造函数来实现对象复制外,还可以像C#中那样实现一个clone函数,这需要借助编译器实现的一个隐藏拷贝构造函数 ...

  8. vector reserve与resize区别

    vector 的reserve增加了vector的capacity,但是它的size没有改变!而resize改变了vector的capacity同时也增加了它的size!原因如下:reserve是容器 ...

  9. Cocoapods的使用教程

    前言 对于iOS App的开发,几乎都采用了Cocoapods来管理第三方库,那么对于我们开发人员来说,这是必备技能,必须要掌握如何使用.这篇文章就是介绍如何安装和使用CocoaPods的. 这篇文章 ...

  10. Git - 使用指南

    GIT (分布式版本控制系统) 编辑 Git是一款免费.开源的分布式版本控制系统,用于敏捷高效地处理任何或小或大的项目.[1]  Git的读音为/gɪt/. Git是一个开源的分布式版本控制系统,可以 ...