spring aop使用

spring aop

一.Advisor 和 Advice

Advice,我们通常都会把他翻译为通知,其实很不好理解,其实他还有另外一个意思,就是“建议”,我觉得把Advice理解为“建议”会更好。

比如,我们已经完成了一个功能,这时客户跟我们说,我建议在这个功能之前可以再增加一些逻辑,再之后再增加一些逻辑。

在Spring中,Advice分为:

  1. 前置Advice:MethodBeforeAdvice
  2. 后置Advice:AfterReturningAdvice
  3. 环绕Advice:MethodInterceptor
  4. 异常Advice:ThrowsAdvice

Pointcut

切点,表示我想让哪些地方加上我的代理逻辑。

比如某个方法,

比如某些方法,

比如某些方法名前缀为“find”的方法,

比如某个类下的所有方法,等等。

例子:

public class LoggerAfterReturningAdvice implements AfterReturningAdvice {

   // 方法执行后进行调用,后置增强  --->建议
   @Override
   public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
      System.out.println("AfterReturningAdvice");
   }
}
public class LoggerMethodBeforeAdvice implements MethodBeforeAdvice {

   // 方法执行前进行调用,前置增强
   @Override
   public void before(Method method, Object[] args, Object target) throws Throwable {
      System.out.println(method.getName());
      System.out.println("MethodBeforeAdvice");
   }
}
public class LoggerMethodInterceptor implements MethodInterceptor {

   // 可以理解为环绕通知,可以更加自由的控制是在方法执行前,后进行调用
   @Override
   public Object invoke(MethodInvocation i) throws Throwable {
      System.out.println("method "+i.getMethod()+" is called on "+
            i.getThis()+" with args "+i.getArguments());
      Object ret=i.proceed();
      System.out.println("method "+i.getMethod()+" returns "+ret);
      return ret;
   }
}
public class HxyPointcut  implements Pointcut {
   @Override
   public ClassFilter getClassFilter() {
      return ClassFilter.TRUE;
   }

   @Override
   public MethodMatcher getMethodMatcher() {
      return new StaticMethodMatcherPointcut() {
         @Override
         public boolean matches(@NonNull Method method, Class<?> targetClass) {
            // 对于toString方法不进行拦截
            return !method.getName().equals("toString");
         }
      };
   }
}
public class LubanService {

   public User test() {
      System.out.println("===");
      return new User("xxx");
   }

   @Override
   public String toString() {
      System.out.println("LubanService toString invoke");
      return "LubanService";
   }

}
public static void main(String[] args) {
   ProxyFactory proxyFactory = new ProxyFactory();
       // 一个Advisor代表的是一个已经跟指定切点绑定了的通知
   // 在这个例子中意味着环绕通知不会作用到toString方法上
   Advisor advisor = new DefaultPointcutAdvisor(new HxyPointcut(), new LoggerMethodInterceptor());

   proxyFactory.addAdvisor(advisor);
   proxyFactory.addAdvice(new LoggerMethodBeforeAdvice());
   proxyFactory.addAdvice(new LoggerAfterReturningAdvice());
   proxyFactory.setTarget(new LubanService());

   proxyFactory.setProxyTargetClass(true);

   Object proxy = proxyFactory.getProxy();

   // 调用代理类的toString方法,通过控制台查看代理逻辑的执行情况
   proxy.toString();

   if (proxy instanceof LubanService) {
      ((LubanService) proxy).test();
   }

   // 判断引入是否成功,并执行引入的逻辑
   if (proxy instanceof Runnable) {
      ((Runnable) proxy).run();
   }
}

环绕通知

public interface MethodInterceptor extends Interceptor {

   Object invoke(MethodInvocation invocation) throws Throwable;

}

invocation.proceed 就是在执行当前的这个方法

前置通知(Before Advice)

public interface MethodBeforeAdvice extends BeforeAdvice {

   void before(Method method, Object[] args, @Nullable Object target) throws Throwable;

}

后置通知(After Returning Advice)

public interface AfterReturningAdvice extends AfterAdvice {

   void afterReturning(@Nullable Object returnValue, Method method, Object[] args, @Nullable Object target) throws Throwable;

}
class MethodBeforeAdviceAdapter implements AdvisorAdapter, Serializable {

   @Override
   public boolean supportsAdvice(Advice advice) {
      return (advice instanceof MethodBeforeAdvice);
   }

   @Override
   public MethodInterceptor getInterceptor(Advisor advisor) {
      MethodBeforeAdvice advice = (MethodBeforeAdvice) advisor.getAdvice();
      return new MethodBeforeAdviceInterceptor(advice);
   }

}
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 {
      //实际上还是利用拦截器,在方法执行前调用了通知的before方法完成了前置通知
      this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
      return mi.proceed();  // methodinter target.test();
   }

Advisor (绑定通知跟切点)

一个Advisor实际上就是一个绑定在指定切点上的通知。

   Advisor advisor = new DefaultPointcutAdvisor(new HxyPointcut(), new LoggerMethodInterceptor());
   proxyFactory.addAdvisor(advisor);
   proxyFactory.addAdvice(new LoggerMethodInterceptor());

有2种实现方式 一种直接添加一个Advisor,还有一种是添加一个Advice

addAdvice方法如下:

@Override
public void addAdvice(Advice advice) throws AopConfigException {
   int pos = this.advisors.size();
   addAdvice(pos, advice);
}
public void addAdvice(int pos, Advice advice) throws AopConfigException {
   Assert.notNull(advice, "Advice must not be null");
   if (advice instanceof IntroductionInfo) {
      // We don't need an IntroductionAdvisor for this kind of introduction:
      // It's fully self-describing.
      addAdvisor(pos, new DefaultIntroductionAdvisor(advice, (IntroductionInfo) advice));
   }
   else if (advice instanceof DynamicIntroductionAdvice) {
       // 不能直接添加一个不是IntroductionInfo的DynamicIntroductionAdvice(动态引入通知)
      // We need an IntroductionAdvisor for this kind of introduction.
      throw new AopConfigException("DynamicIntroductionAdvice may only be added as part of IntroductionAdvisor");
   }
   else {
        // 如果是普通的通知,那么会创建一个DefaultPointcutAdvisor
        // DefaultPointcutAdvisor所定义的切点会匹配所有类以及所有方法
      addAdvisor(pos, new DefaultPointcutAdvisor(advice));  // Advisor advice pointcut
   }
}

其实也是调用了addAdvisor方法

img

ProxyCreatorSupport

这个类的主要作用是为创建一个AOP代理对象提供一些功能支持,通过它的getAopProxyFactory能获取一个创建代理对象的工厂。

ProxyConfig

/** use serialVersionUID from Spring 1.2 for interoperability. */
private static final long serialVersionUID = -8409359707199703185L;

// 是否开启cglib
private boolean proxyTargetClass = false;

// 跟cglib优化有关系
private boolean optimize = false;

boolean opaque = false;

// 是否将生成的代理对象设置到AopContext中去,后面可以通过AopContext.currentProxy()拿到
boolean exposeProxy = false;

private boolean frozen = false;

AdvisedSupport

1.目标对象 2.执行通知 3.实现哪些接口

AdvisedSupport本身实现了Advised接口,Advised接口定义了管理通知的方法

spring 提供3种方式进行代理

  1. ProxyFactoryBean

  2. ProxyFactory

  3. Auto-proxy

    1.ProxyFactoryBean

    AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
    ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();
    proxyFactoryBean.setBeanFactory(applicationContext.getBeanFactory());
    proxyFactoryBean.setInterfaces(Runnable.class);
    proxyFactoryBean.setProxyTargetClass(true);
    proxyFactoryBean.setTarget(applicationContext.getBean(HxyService.class));
    proxyFactoryBean.setInterceptorNames("loggerMethodBeforeAdvice");
    applicationContext.getBeanFactory().registerSingleton("myproxy",proxyFactoryBean);
    HxyService proxyBean = (HxyService) applicationContext.getBean("myproxy");
    proxyBean.testAop();
    

3.实现自动aop代理

image-20200702103750263

  1. BeanNameAutoProxyCreator 使用方式

    @Bean
    public BeanNameAutoProxyCreator creator(){
       BeanNameAutoProxyCreator beanNameAutoProxyCreator = new BeanNameAutoProxyCreator();
       beanNameAutoProxyCreator.setBeanNames("luban*");
       beanNameAutoProxyCreator.setInterceptorNames("loggerMethodInterceptor");
       beanNameAutoProxyCreator.setProxyTargetClass(true);
       return beanNameAutoProxyCreator;
    }
    

2.DefaultAdvisorAutoProxyCreator 使用方式

@Bean
public DefaultPointcutAdvisor loggerBeforeAdvisor(){
   DefaultPointcutAdvisor defaultPointcutAdvisor = new DefaultPointcutAdvisor();
   defaultPointcutAdvisor.setAdvice(new LoggerMethodBeforeAdvice());
   return defaultPointcutAdvisor;
}

@Bean
public DefaultPointcutAdvisor loggerAroundAdvisor(){
   DefaultPointcutAdvisor defaultPointcutAdvisor = new DefaultPointcutAdvisor();
   defaultPointcutAdvisor.setAdvice(new LoggerMethodInterceptor());
   return defaultPointcutAdvisor;
}

@Bean
public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator(){
   DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
   defaultAdvisorAutoProxyCreator.setUsePrefix(true);
   defaultAdvisorAutoProxyCreator.setAdvisorBeanNamePrefix("logger");
   defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
   return defaultAdvisorAutoProxyCreator;
}

3.AnnotationAwareAspectJAutoProxyCreator

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WZC2LTcB-1614038688601)(C:\Users\23634\AppData\Roaming\Typora\typora-user-images\image-20210222152327570.png)]

自动代理机制实际上就是Spring在内部new了一个ProxyFactory,通过它创建了一个代理对象。对应的代码就在AbstractAutoProxyCreator中的createProxy方法内,源码如下:

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);   // 复制配置参数
   // 是否指定了必须用cglib进行代理
   if (!proxyFactory.isProxyTargetClass()) {
      // 如果没有指定,那么则判断是不是应该进行cglib代理(判断BeanDefinition中是否指定了要用cglib)
      if (shouldProxyTargetClass(beanClass, beanName)) {
         proxyFactory.setProxyTargetClass(true);
      }
      else {
         // 是否进行jdk动态代理,如果当前beanClass实现了某个接口,那么则会使用JDK动态代理
         evaluateProxyInterfaces(beanClass, proxyFactory); // 判断beanClass有没有实现接口
      }
   }


   // 将commonInterceptors和specificInterceptors整合再一起
   Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);

   proxyFactory.addAdvisors(advisors);    // 向ProxyFactory中添加advisor
   proxyFactory.setTargetSource(targetSource); // 被代理的对象
   customizeProxyFactory(proxyFactory);

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

   // 生成代理对象
   return proxyFactory.getProxy(getProxyClassLoader());
}

核心源码分析

createAopProxy方法分析

@Override
   public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
      // Spring到底何时使用cglib,何时使用jdk动态代理
      // 如果设置的targetClass是一个接口,会使用jdk动态代理
      // 默认情况下(optimize为false, isProxyTargetClass为false), ProxyFactory添加了接口时,也会使用jdk动态代理

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

   /**
    * Determine whether the supplied {@link AdvisedSupport} has only the
    * {@link org.springframework.aop.SpringProxy} interface specified
    * (or no proxy interfaces specified at all).
    */
   private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) {
      Class<?>[] ifcs = config.getProxiedInterfaces();
      return (ifcs.length == 0 || (ifcs.length == 1 && SpringProxy.class.isAssignableFrom(ifcs[0])));
   }

}

getProxy方法分析

分析JdkDynamicAopProxy

image-20200702154037428

@Override
public Object getProxy(@Nullable ClassLoader classLoader) {
   if (logger.isTraceEnabled()) {
      logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
   }
   // 获取生成代理对象所需要实现的接口
   Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);

   // 判断这些接口中有没有定义equals方法,hashcode方法
   findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
   // 针对所指定的接口生成代理对象,包括用户所添加的接口以及SpringProxy、Advised、DecoratingProxy
   // 所以生成的代理对象可以强制转换成任意一个接口类型
   return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}

执行invoke方法

@Override
@Nullable
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;

      //  advised就是ProxyFactory
      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(); // targetSource分为两种:SingletonTargetSource、EmptyTargetSource
      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...
         MethodInvocation invocation =
               new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
         // Proceed to the joinpoint through the interceptor chain.
         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;
      }
      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);
      }
   }
}
  1. 获取整个拦截器链
  2. 开始在拦截器链上执行方法

1.获取整个拦截器链

// 根据当前正在执行的方法和被代理的类查找匹配的Advisor链
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) {
   MethodCacheKey cacheKey = new MethodCacheKey(method);
   List<Object> cached = this.methodCache.get(cacheKey);
   if (cached == null) {
      cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
            this, method, targetClass);
      this.methodCache.put(cacheKey, cached);
   }
   return cached;
}

拦截器链

// We need to create a method invocation...
MethodInvocation invocation =
      new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
//  开始在拦截器链上执行这个方法
retVal = invocation.proceed();

最后的关键代码就落在了ReflectiveMethodInvocationproceed方法

@Nullable
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);
   }
}

版权声明:本文为qq_28852755原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。