spring源码系列(九)——Spring AOP

spring源码系列(九)——Spring AOPAspect Oriented Programming 面向切面编程,在传统的oop开发过程当中,逻辑是自上而下的,譬如我们实现一个登录功能,浏

欢迎大家来到IT世界,在知识的湖畔探索吧!

一、什么是aop

Aspect Oriented Programming 面向切面编程,在传统的oop开发过程当中,逻辑是自上而下的,譬如我们实现一个登录功能,浏览器发起http请求到controller,controller负责接受请求,封装参数、验证参数等等,继而把数据传给service,service处理完成之后调用dao,dao操作db后返回;在这个过程当中会产生很多横切性的问题;

比如controller当中的日志记录、比如service当中的权限校验,比如dao当中的事务处理;这些横切性的问题和主业务逻辑是没有关系的,比如日志的记录失败与否并不会影响整个登录逻辑;这些横切的问题如果不去处理会散落在代码的各个地方;面向切面编程就是我们程序员编码只关心横切性问题的抽象;

二、什么spring aop

aop 面向切面编程是一种编程目标,说白了是一个标准;而实现这种编程标准的技术手段有很多;比如:你可以用JDK动态代理来实现aop,也可以使用aspectj这种静态编程技术来实现代理从而实现aop;

spring aop就是实现aop 的一种技术手段;实现aop除了spring aop市面上还有很多其他技术来实现aop;

三、spring aop的核心原理

对于上述的横切性问题spring的做法是把这些问题集中到一个切面(Aspect)当中,然后利用动态代理技术动态增强业务bean;

spring aop的核心技术是JDK动态代理和cglib动态代理,加上spring内部的BeanPostProcessor一起工作,从而达到了对spring当中bean完成增强;

四、spring aop当中的专业术语

Join point

连接点:程序执行当中的一个点,他是一个最终结果,因为spring aop最小连接单位是一个方法,故而一个切点就是一个方法(但是是被连接了的方法);

Pointcut

切点:一组连接点的集合;因为在开发中可能连接点可能会有很多,根据业务和功能的不同会进行分组,切点就是一组连接点的描述(相当于连接点=一条数据,切点等于一张表;一个数据库当中可以存在多张表,表可以有多条数据);

Advice

通知:通知可以从三个维度来理解:1、通知的内容,也就是你增强一个方法的具体业务逻辑,比如日志记录,比如事务操作;2、通知的时机:Before advice、After returning advice、After throwing advice、After (fifinally) advice、Around advice;3、通知的目标,也就是这个通知需要作用到哪个或者哪些连接点上;

Introduction

导入:springAop可以在不修改代码的情况下让某个类强制实现某个接口,并且可以指定接口的默认实现方法;

Target object

目标对象:由于spring aop是借助CGLIB或者JDK动态代理的来实现增强的,目标对象的概念和动态代理当中那个目标对象是同一个概念——被代理的那个对象;

AOP proxy

代理对象:一个被jdk动态代理或者被CGLIB动态代理了之后的对象;

Weaving

织入:一个过程;把切面和应用程序对象连接的过程;

Aspect

切面:上述所有概念在编码过程中存在的类称为切面,切点、连接点、通知等等存在的类称之为一个切面;

五、spring aop开发

1、启用@AspectJ

支持使用Java Confifiguration启用@AspectJ支持要使用Java @Confifiguration启用@AspectJ支持,请添加@EnableAspectJAutoProxy注释

@Configuration 
@EnableAspectJAutoProxy 
public class AppConfig { 
}

欢迎大家来到IT世界,在知识的湖畔探索吧!

使用XML配置启用@AspectJ支持要使用基于xml的配置启用@AspectJ支持,可以使用aop:aspectj-autoproxy元素

<aop:aspectj-autoproxy/>

2、声明一个Aspect

申明一个@Aspect注释类,并且定义成一个bean交给Spring管理

欢迎大家来到IT世界,在知识的湖畔探索吧!@Component 
@Aspect 
public class UserAspect { }

3、申明一个pointCut

切入点表达式由@Pointcut注释表示。切入点声明由两部分组成:一个签名包含名称和任何参数,以及一个切入点表达式,该表达式确定我们对哪个方法执行感兴趣;

@Pointcut("execution(* transfer(..))")// 切入点表达式 
private void anyOldTransfer() {}// 切入点签名

切入点确定感兴趣的 join points(连接点),从而使我们能够控制何时执行通知。Spring AOP只支持Spring bean的方法执行 join points(连接点),所以您可以将切入点看作是匹配Spring bean上方法的执行;

欢迎大家来到IT世界,在知识的湖畔探索吧!/** * 申明Aspect,并且交给spring容器管理 */ 
@Component 
@Aspect 
public class UserAspect { 
  /*** 申明切入点,匹配UserDao所有方法调用 
  * execution匹配方法执行连接点 
  * within:将匹配限制为特定类型中的连接点 
  * args:参数 
  * target:目标对象 
  * this:代理对象 
  */
  @Pointcut("execution(* com.yao.dao.UserDao.*(..))") 
  public void pintCut(){ 
    System.out.println("point cut");
  }

4、申明一个Advice通知

advice通知与pointcut切入点表达式相关联,并在切入点匹配的方法执行@Before之前、@After之后或前后运行;

/*** 申明Aspect,并且交给spring容器管理 */
@Component 
@Aspect 
public class UserAspect { 
  /*** 申明切入点,匹配UserDao所有方法调用 
  * execution匹配方法执行连接点 
  * within:将匹配限制为特定类型中的连接点 
  * args:参数
  * target:目标对象 
  * this:代理对象 
  */
  @Pointcut("execution(* com.yao.dao.UserDao.*(..))") 
  public void pintCut(){ 
    System.out.println("point cut"); 
  }
  /** 
  * 申明before通知,在pintCut切入点前执行 
  * 通知与切入点表达式相关联, 
  * 并在切入点匹配的方法执行之前、之后或前后运行。 
  * 切入点表达式可以是对指定切入点的简单引用,也可以是在适当位置声明的切入点表达式。 
  */
  @Before("com.yao.aop.UserAspect.pintCut()") 
  public void beforeAdvice(){ 
    System.out.println("before"); 
  }
}

六、各种连接点joinPoint的意义

1、execution

用于匹配方法执行 join points连接点,最小粒度方法,在aop中主要使用

execution(modifiers-pattern? ret-type-pattern declaring-type-pattern?name-pattern(param-pattern) throws-pattern?) 
这里问号表示当前项可以有也可以没有,其中各项的语义如下 
modifiers-pattern:方法的可见性,如public,protected; 
ret-type-pattern:方法的返回值类型,如int,void等; 
declaring-type-pattern:方法所在类的全路径名,如com.spring.Aspect; 
name-pattern:方法名,如buisinessService(); 
param-pattern:方法的参数类型,如java.lang.String; 
throws-pattern:方法抛出的异常类型,如java.lang.Exception; 
example: 
//匹配com.chenss.dao包下任意接口和 类的任意方法 
@Pointcut("execution(* com.chenss.dao.*.*(..))")
//匹配com.chenss.dao包下的 任意接口和类的public方法 
@Pointcut("execution(public * com.chenss.dao.*.*(..))")
//匹配com.chenss.dao包下的任 意接口和类的public 无方法参数的方法 
@Pointcut("execution(public * com.chenss.dao.*.*())")
//匹配 com.chenss.dao包下的任意接口和类的第一个参数为String类型的方法 
@Pointcut("execution(* com.chenss.dao.*.*(java.lang.String, ..))")
//匹配 com.chenss.dao包下的任意接口和类的只有一个参数,且参数为String类型的方法 
@Pointcut("execution(* com.chenss.dao.*.*(java.lang.String))")
//匹配 com.chenss.dao包下的任意接口和类的只有一个参数,且参数为String类型的方法 
@Pointcut("execution(* com.chenss.dao.*.*(java.lang.String))")
//匹配任意的public方法 
@Pointcut("execution(public * *(..))")
//匹配任意的以te开头的方法 
@Pointcut("execution(* te*(..))")
//匹配 com.chenss.dao.IndexDao接口中任意的方法 
@Pointcut("execution(* com.chenss.dao.IndexDao.*(..))")
//匹配com.chenss.dao包及其子包中任 意的方法
@Pointcut("execution(* com.chenss.dao..*.*(..))")

关于这个表达式的详细写法:https://docs.spring.io/spring-framework/docs/current/spring-framework- reference/core.html#aop-pointcuts-examples

由于Spring切面粒度最小是达到方法级别,而execution表达式可以用于明确指定方法返回类型,类名,方法名和参数名等与方法相关的信息,并且在Spring中,大部分需要使用AOP的业务场景也只需要达到方法级别即可,因而execution表达式的使用是最为广泛的;

2、within

该表达式的最小粒度为类;

within与execution相比,粒度更大,仅能实现到包和接口、类级别。而execution可以精确到方法的返回值,参数个数、修饰符、参数类型等;

//匹配com.chenss.dao包中的任意方法 
@Pointcut("within(com.chenss.dao.*)")
//匹配com.chenss.dao包及其子包中的任意方法
@Pointcut("within(com.chenss.dao..*)")

3、args

args表达式的作用是匹配指定参数类型和指定参数数量的方法,与包名和类名无关

args同execution不同的地方在于: args匹配的是运行时传递给方法的参数类型 execution(* *(java.io.Serializable))匹配的是方法在声明时指定的方法参数类型;

4、this

JDK代理时,指向接口和代理类proxy,cglib代理时 指向接口和子类(不使用proxy)

5、target

target 指向接口和子类

/** 
* 如果配置设置proxyTargetClass=false,或默认为false,则是用JDK代理,否则使用的是CGLIB代理
* JDK代理的实现方式是基于接口实现,代理类继承Proxy,实现接口。 
* 而CGLIB继承被代理的类来实现。 
* 所以使用target会保证目标不变,关联对象不会受到这个设置的影响。 
* 但是使用this对象时,会根据该选项的设置,判断是否能找到对象。 
*/
//目标对象,也就是被代理的对象。限制 目标对象为com.chenss.dao.IndexDaoImpl类
@Pointcut("target(com.chenss.dao.IndexDaoImpl)")
//当前对象,也就是代理对象,代理对象时 通过代理目标对象的方式获取新的对象,与原值并非一个 
@Pointcut("this(com.chenss.dao.IndexDaoImpl)")
//具有@Chenss的目标对象中的任意方法 
@Pointcut("@target(com.chenss.anno.Chenss)")
//等同于@target
@Pointcut("@within(com.chenss.anno.Chenss)")

七、源码分析

我们思考一下我们应该从哪个地方作为入口进行分析?

想一下aop是做什么的,主要是在我们方法执行之前之后去做一些事情,那么肯定得是这个类实例化之后再进行增强;

所以我们只需要找创建类那一块代码,并且是实例化之后的代码

注:如果不知道怎么到这里来的,可以看一下之前的文章,怎么实例化bean,怎么进行属性注入的;

spring源码系列(九)——Spring AOP

属性填充基本不可能在这个里面,这个只是进行属性注入,那么就是初始化bean的时候会根据aop组件对类生成代理类进行增强;

spring源码系列(九)——Spring AOP

这里会获取所有待执行的BeanPostProcessors进行执行;

public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
      throws BeansException {

   Object result = existingBean;
   for (BeanPostProcessor processor : getBeanPostProcessors()) {
      Object current = processor.postProcessAfterInitialization(result, beanName);
      if (current == null) {
         return result;
      }
      result = current;
   }
   return result;
}

其中有一个AbstractAutoProxyCreator用来实现用AOP代理封装每个符合条件的bean,将其委托给指定的拦截器

spring源码系列(九)——Spring AOP

public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {   if (bean != null) {      Object cacheKey = getCacheKey(bean.getClass(), beanName);      if (this.earlyProxyReferences.remove(cacheKey) != bean) {         return wrapIfNecessary(bean, beanName, cacheKey);      }   }   return bean;}

wrapIfNecessary

先找到bean对应的通知,再根据通知创建对应的代理对象;

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;
}

getAdvicesAndAdvisorsForBean

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();
}

findEligibleAdvisors

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;
}

org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#findCandidateAdvisors

这个方法会先获取所有实现了Advisor接口的类,就是通知类;
再调用buildAspectJAdvisors方法对所有切面进行增强;

protected List<Advisor> findCandidateAdvisors() {
		// Add all the Spring advisors found according to superclass rules.
        /** 根据Advisor类型获取所有的实现了Advisor接口的类 */
		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;
	}

buildAspectJAdvisors方法获取切面及切面相关的通知时只会获取一次,获取一次之后会放入aspectBeanNames切面集合和advisorsCache切面对应的通知集合;

下次获取就直接从缓存中找就好了,这里需要注意的一点是,这里获取出来的时候会进行排序

public List<Advisor> buildAspectJAdvisors() {
    /** 当前项目当中所有切面 */
   List<String> aspectNames = this.aspectBeanNames;

   /** 判断是否等于null */
   if (aspectNames == null) {
      synchronized (this) {
         aspectNames = this.aspectBeanNames;
         if (aspectNames == null) {
            List<Advisor> advisors = new ArrayList<>();
            aspectNames = new ArrayList<>();
            /** 获取当前容器当中所有bean的名字 */
            String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
                  this.beanFactory, Object.class, true, false);
            for (String beanName : beanNames) {
               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.
               Class<?> beanType = this.beanFactory.getType(beanName, false);
               if (beanType == null) {
                  continue;
               }
               /** 判断是否为切面 */
               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);

                     /** 找出当前切面的所有通知,并且已进行排序 */
                     List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
                     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 ArrayList<>();
   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;
}
private List<Method> getAdvisorMethods(Class<?> aspectClass) {
   final List<Method> methods = new ArrayList<>();
   ReflectionUtils.doWithMethods(aspectClass, method -> {
      // Exclude pointcuts
      if (AnnotationUtils.getAnnotation(method, Pointcut.class) == null) {
         methods.add(method);
      }
   }, ReflectionUtils.USER_DECLARED_METHODS);
   if (methods.size() > 1) {
       /** 排序 */
      methods.sort(METHOD_COMPARATOR);
   }
   return methods;
}

我们可以发现他的排序规则是怎样的:Around->Before->After->AfterReturning->AfterThrowing;

private static final Comparator<Method> METHOD_COMPARATOR;

static {
   // Note: although @After is ordered before @AfterReturning and @AfterThrowing,
   // an @After advice method will actually be invoked after @AfterReturning and
   // @AfterThrowing methods due to the fact that AspectJAfterAdvice.invoke(MethodInvocation)
   // invokes proceed() in a `try` block and only invokes the @After advice method
   // in a corresponding `finally` block.
   Comparator<Method> adviceKindComparator = new ConvertingComparator<>(
         new InstanceComparator<>(
               Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class),
         (Converter<Method, Annotation>) method -> {
            AspectJAnnotation<?> ann = AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(method);
            return (ann != null ? ann.getAnnotation() : null);
         });
   Comparator<Method> methodNameComparator = new ConvertingComparator<>(Method::getName);
   METHOD_COMPARATOR = adviceKindComparator.thenComparing(methodNameComparator);
}

我们通过findCandidateAdvisors获取到所有的通知,再根据bean进行过滤,注意:这里是先获取所有的通知在进行过滤的,而且这里也有一个排序,那这个排序是干嘛的呢?

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;
}

sortAdvisors

其实看到这里我们就不用看了,我之前也分析过这个比较器,如果该类实现了Ordered接口,就通过其方法获取对应的值,否则就获取一个无穷大的值再进行排序;

public static final AnnotationAwareOrderComparator INSTANCE = new AnnotationAwareOrderComparator();

	@Override
	@Nullable
	protected Integer findOrder(Object obj) {
		Integer order = super.findOrder(obj);
		if (order != null) {
			return order;
		}
		return findOrderFromAnnotation(obj);
	}

protected List<Advisor> sortAdvisors(List<Advisor> advisors) {
   AnnotationAwareOrderComparator.sort(advisors);
   return advisors;
}

public static void sort(List<?> list) {
   if (list.size() > 1) {
      list.sort(INSTANCE);
   }
}

找出对应的通知之后再根据通知创建对应的代理类,这里需要注意的是会根据代理工厂利用不同的技术来创建代理类;

protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
      @Nullable Object[] specificInterceptors, TargetSource targetSource) {

   if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
      AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
   }

   /** 代理工厂 */
   ProxyFactory proxyFactory = new ProxyFactory();
   proxyFactory.copyFrom(this);

   if (proxyFactory.isProxyTargetClass()) {
      // Explicit handling of JDK proxy targets (for introduction advice scenarios)
      if (Proxy.isProxyClass(beanClass)) {
         // Must allow for introductions; can't just set interfaces to the proxy's interfaces only.
         for (Class<?> ifc : beanClass.getInterfaces()) {
            proxyFactory.addInterface(ifc);
         }
      }
   }
   else {
      // No proxyTargetClass flag enforced, let's apply our default checks...
      if (shouldProxyTargetClass(beanClass, beanName)) {
         proxyFactory.setProxyTargetClass(true);
      }
      else {
         evaluateProxyInterfaces(beanClass, proxyFactory);
      }
   }

   Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
   /** 添加aop通知 */
   proxyFactory.addAdvisors(advisors);
   proxyFactory.setTargetSource(targetSource);
   customizeProxyFactory(proxyFactory);

   proxyFactory.setFrozen(this.freezeProxy);
   if (advisorsPreFiltered()) {
      proxyFactory.setPreFiltered(true);
   }

   /** 通过代理工厂选择是Cglib还是jdk动态代理来生成代理类 */
   return proxyFactory.getProxy(getProxyClassLoader());
}

spring一般会尽量选择jdk动态代理来创建代理类

public Object getProxy(@Nullable ClassLoader classLoader) {
   return createAopProxy().getProxy(classLoader);
}
protected final synchronized AopProxy createAopProxy() {
   if (!this.active) {
      activate();
   }
   return getAopProxyFactory().createAopProxy(this);
}
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
   if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
      Class<?> targetClass = config.getTargetClass();
      if (targetClass == null) {
         throw new AopConfigException("TargetSource cannot determine target class: " +
               "Either an interface or a target is required for proxy creation.");
      }
      if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
         return new JdkDynamicAopProxy(config);
      }
      return new ObjenesisCglibAopProxy(config);
   }
   else {
      return new JdkDynamicAopProxy(config);
   }
}

jdk动态代理创建代理类

public Object getProxy(@Nullable ClassLoader classLoader) {
   if (logger.isTraceEnabled()) {
      logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
   }
       /**
        * advised为代理工厂,存储了代理的一些必要参数
        * AopProxyUtils.completeProxiedInterfaces:从代理工厂中获取代理对象需要实现的接口集合
        */
   Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
   findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
   /** 创建代理对象 */
   return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}

代理类一般是通过invoke方法来处理相应的代码逻辑的

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
   Object oldProxy = null;
   boolean setProxyContext = false;

   /** 获取目标对象的包裹对象 */
   TargetSource targetSource = this.advised.targetSource;
   /** 目标对象 */
   Object target = null;

   try {
      if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
         // The target does not implement the equals(Object) method itself.
         return equals(args[0]);
      }
      else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
         // The target does not implement the hashCode() method itself.
         return hashCode();
      }
      else if (method.getDeclaringClass() == DecoratingProxy.class) {
         // There is only getDecoratedClass() declared -> dispatch to proxy config.
         return AopProxyUtils.ultimateTargetClass(this.advised);
      }
      else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
            method.getDeclaringClass().isAssignableFrom(Advised.class)) {
         // Service invocations on ProxyConfig with the proxy config...
         return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
      }

      Object retVal;

      if (this.advised.exposeProxy) {
         // Make invocation available if necessary.
         oldProxy = AopContext.setCurrentProxy(proxy);
         setProxyContext = true;
      }

      // Get as late as possible to minimize the time we "own" the target,
      // in case it comes from a pool.
           /** 真实的目标对象 */
      target = targetSource.getTarget();
      Class<?> targetClass = (target != null ? target.getClass() : null);

      // Get the interception chain for this method.
           /** 获取所有的通知对象 */
      List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

      // Check whether we have any advice. If we don't, we can fallback on direct
      // reflective invocation of the target, and avoid creating a MethodInvocation.
      if (chain.isEmpty()) {
         // We can skip creating a MethodInvocation: just invoke the target directly
         // Note that the final invoker must be an InvokerInterceptor so we know it does
         // nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
         Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
         retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
      }
      else {
         // We need to create a method invocation...
               /** 将相关参数封装成ReflectiveMethodInvocation */
         MethodInvocation invocation =
               new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
         // Proceed to the joinpoint through the interceptor chain.
               /** 这个方法是最重要的方法,通过proceed方法依次执行集合中的通知 */
         retVal = invocation.proceed();
      }

      // Massage return value if necessary.
      Class<?> returnType = method.getReturnType();
      if (retVal != null && retVal == target &&
            returnType != Object.class && returnType.isInstance(proxy) &&
            !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
         // Special case: it returned "this" and the return type of the method
         // is type-compatible. Note that we can't help if the target sets
         // a reference to itself in another returned object.
         retVal = proxy;
      }
      /** 如果返回类型为空并且返回类型不为Void则抛出异常 */
      else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
         throw new AopInvocationException(
               "Null return value from advice does not match primitive return type for: " + method);
      }
      return retVal;
   }
   finally {
      if (target != null && !targetSource.isStatic()) {
         // Must have come from TargetSource.
         targetSource.releaseTarget(target);
      }
      if (setProxyContext) {
         // Restore old proxy.
         AopContext.setCurrentProxy(oldProxy);
      }
   }
}

public Object proceed() throws Throwable {
   // We start with an index of -1 and increment early.
       /** 判断链上还有没有增强器,如果没有则执行目标对象的目标方法 */
   if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
      return invokeJoinpoint();
   }

   /** 顺序获取增强器 */
   Object interceptorOrInterceptionAdvice =
         this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
   /** 判断是否继承动态方法匹配器 */
   if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
      // Evaluate dynamic method matcher here: static part will already have
      // been evaluated and found to match.
      InterceptorAndDynamicMethodMatcher dm =
            (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
      Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
      if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
         return dm.interceptor.invoke(this);
      }
      else {
         // Dynamic matching failed.
         // Skip this interceptor and invoke the next in the chain.
         return proceed();
      }
   }
   else {
      // It's an interceptor, so we just invoke it: The pointcut will have
      // been evaluated statically before this object was constructed.
           /** 执行通知类的处理逻辑 */
      return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
   }
}
protected Object invokeJoinpoint() throws Throwable {
    /** 执行目标对象的目标方法 */
   return AopUtils.invokeJoinpointUsingReflection(this.target, this.method, this.arguments);
}

BeforeAdvice通知会先执行自己的增强逻辑,再去执行proceed方法,如果还有待执行的通知则进行执行,没有则执行目标方法;

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();
   }

}

AspectJAfterAdvice通知会先执行proceed方法,再执行invokeAdviceMethod他自己的通知方法,proceed方法会再去从通知链里面进行获取,如果没有了就会执行目标方法;

public class AspectJAfterAdvice extends AbstractAspectJAdvice
      implements MethodInterceptor, AfterAdvice, Serializable {

   public AspectJAfterAdvice(
         Method aspectJBeforeAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif) {

      super(aspectJBeforeAdviceMethod, pointcut, aif);
   }


   @Override
   public Object invoke(MethodInvocation mi) throws Throwable {
      try {
         return mi.proceed();
      }
      finally {
         invokeAdviceMethod(getJoinPointMatch(), null, null);
      }
   }

   @Override
   public boolean isBeforeAdvice() {
      return false;
   }

   @Override
   public boolean isAfterAdvice() {
      return true;
   }

}

Advice类型总结:

BeforeAdvice:先执行增强逻辑,再执行proceed方法;

AfterReturningAdvice:执行proceed方法之后进行执行;

AfterAdvice:执行proceed方法和AfterReturningAdvice之后进行执行;

proceed方法:有通知执行通知,没通知执行目标方法;

总结

  1. SpringAOP不是一种新的AOP实现,使用JDK动态代理和CGLIB动态代理实现;
  2. SpringAOP配置方式核心是Advisor,可以自定义Advisor,也可以通过AspectJ间接定义Advisor;
  3. SpringAOP的实现遵循了AOP联盟规范,AOP联盟顶级API接口贯穿了整个AOP过程;

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://itzsg.com/22592.html

(0)

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

联系我们YX

mu99908888

在线咨询: 微信交谈

邮件:itzsgw@126.com

工作时间:时刻准备着!

关注微信