千家信息网

Spring如何实现AOP

发表于:2024-11-30 作者:千家信息网编辑
千家信息网最后更新 2024年11月30日,这篇文章主要介绍"Spring如何实现AOP",在日常操作中,相信很多人在Spring如何实现AOP问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答"Spring如何实现A
千家信息网最后更新 2024年11月30日Spring如何实现AOP

这篇文章主要介绍"Spring如何实现AOP",在日常操作中,相信很多人在Spring如何实现AOP问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答"Spring如何实现AOP"的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

1. 从注解入手找到对应核心类

最近工作中我都是基于注解实现AOP功能,常用的开启AOP的注解是@EnableAspectJAutoProxy,我们就从它入手。

上面的动图的流程的步骤就是:
@EnableAspectJAutoProxy
--> AspectJAutoProxyRegistrar
-->AopConfigUtils .registerAspectJAnnotationAutoProxyCreatorIfNecessary
-->AnnotationAwareAspectJAutoProxyCreator.class

AnnotationAwareAspectJAutoProxyCreator查看其中文注释(如下),确定它就是AOP的核心类!--温安适 20191020

/**1.AspectJAwareAdvisorAutoProxyCreator的子类,用于处理当前应用上下文中的注解切面2.任何被AspectJ注解的类将自动被识别。3.若SpringAOP代理模式可以识别,优先使用Spring代理模式。4.它覆盖了方法执行连接点5.如果使用元素,  则只有名称与include模式匹配的@aspectj bean才被视为切面  ,并由spring自动代理。6. Spring Advisors的处理请查阅,org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator */@SuppressWarnings("serial")public class AnnotationAwareAspectJAutoProxyCreator extends AspectJAwareAdvisorAutoProxyCreator {    //...省略实现    }注解切面

虽然找到了核心类,但是并没有找到核心方法!下面我们尝试画类图确定核心方法。

2.画核心类类图,猜测核心方法

AnnotationAwareAspectJAutoProxyCreator的部分类图。

从类图看到了AnnotationAwareAspectJAutoProxyCreator实现了BeanPostProcessor,而AOP功能应该在创建完Bean之后执行,猜测AnnotationAwareAspectJAutoProxyCreator实现BeanPostProcessor的postProcessAfterInitialization(实例化bean后处理)是核心方法。 查看AnnotationAwareAspectJAutoProxyCreator实现的postProcessAfterInitialization方法,实际该方法在其父类AbstractAutoProxyCreator中。

//AbstractAutoProxyCreator中的postProcessAfterInitialization实现@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {   if (bean != null) {      Object cacheKey = getCacheKey(bean.getClass(), beanName);      if (!this.earlyProxyReferences.contains(cacheKey)) {         return wrapIfNecessary(bean, beanName, cacheKey);      }   }   return bean;}

发现发现疑似方法wrapIfNecessary,查看其源码如下,发现createProxy方法。确定找对了地方。

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;   }   if (isInfrastructureClass(bean.getClass())                    || shouldSkip(bean.getClass(), beanName)) {      this.advisedBeans.put(cacheKey, Boolean.FALSE);      return bean;   }   // 创建代理   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;}

即AnnotationAwareAspectJAutoProxyCreator实现BeanPostProcessor的postProcessAfterInitialization方法,在该方法中由wrapIfNecessary实现了AOP的功能。 wrapIfNecessary中有2个和核心方法

  • getAdvicesAndAdvisorsForBean获取当前bean匹配的增强器

  • createProxy为当前bean创建代理
    要想明白核心流程还需要分析这2个方法。

3.读重点方法,理核心流程

3.1 getAdvicesAndAdvisorsForBean获取当前bean匹配的增强器

查看源码如下,默认实现在AbstractAdvisorAutoProxyCreator中。

@Override@Nullableprotected Object[] getAdvicesAndAdvisorsForBean(      Class beanClass, String beanName,       @Nullable TargetSource targetSource) {   List advisors = findEligibleAdvisors(beanClass, beanName);   if (advisors.isEmpty()) {      return DO_NOT_PROXY;   }   return advisors.toArray();}

查阅findEligibleAdvisors方法,就干了3件事

  • 找所有增强器,也就是所有@Aspect注解的Bean

  • 找匹配的增强器,也就是根据@Before,@After等注解上的表达式,与当前bean进行匹配,暴露匹配上的。

  • 对匹配的增强器进行扩展和排序,就是按照@Order或者PriorityOrdered的getOrder的数据值进行排序,越小的越靠前。

protected List findEligibleAdvisors(Class beanClass, String beanName) {   //找所有增强器   List candidateAdvisors = findCandidateAdvisors();   //找所有匹配的增强器   List eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);   extendAdvisors(eligibleAdvisors);   if (!eligibleAdvisors.isEmpty()) {       //排序      eligibleAdvisors = sortAdvisors(eligibleAdvisors);   }   return eligibleAdvisors;}

AnnotationAwareAspectJAutoProxyCreator 重写了findCandidateAdvisors,下面我们看看具体实现了什么

3.1.1findCandidateAdvisors找所有增强器,也就是所有@Aspect注解的Bean

@Overrideprotected List findCandidateAdvisors() {   // Add all the Spring advisors found according to superclass rules.   List advisors = super.findCandidateAdvisors();   // Build Advisors for all AspectJ aspects in the bean factory.   if (this.aspectJAdvisorsBuilder != null) {      //@Aspect注解的类在这里除了      advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());   }   return advisors;}

从该方法我们可以看到处理@Aspect注解的bean的方法是:this.aspectJAdvisorsBuilder.buildAspectJAdvisors()。 这个方法如下:

public List buildAspectJAdvisors() {   List aspectNames = this.aspectBeanNames;   if (aspectNames == null) {      synchronized (this) {         aspectNames = this.aspectBeanNames;         if (aspectNames == null) {            List advisors = new ArrayList<>();            aspectNames = new ArrayList<>();            //找到所有BeanName            String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(                  this.beanFactory, Object.class, true, false);            for (String beanName : beanNames) {               if (!isEligibleBean(beanName)) {                  continue;               }               // 必须注意,bean会提前暴露,并被Spring容器缓存,但是这时还不能织入。               Class beanType = this.beanFactory.getType(beanName);               if (beanType == null) {                  continue;               }               if (this.advisorFactory.isAspect(beanType)) {                  //找到所有被@Aspect注解的类                  aspectNames.add(beanName);                  AspectMetadata amd = new AspectMetadata(beanType, beanName);                  if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {                     MetadataAwareAspectInstanceFactory factory =                           new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);                     //解析封装为Advisor返回                     List 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 advisors = new ArrayList<>();   for (String aspectName : aspectNames) {      List 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;}

这个方法可以概括为:

  • 找到所有BeanName

  • 根据BeanName筛选出被@Aspect注解的类

  • 针对类中被Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class注解的方法,先按上边的注解顺序排序后按方法名称排序,每一个方法对应一个Advisor。

3.2 createProxy为当前bean创建代理。

3.2.1 创建代理的2种方式

众所周知,创建代理的常用的2种方式是:JDK创建和CGLIB,下面我们就看看这2中创建代理的例子。

3.2.1 .1 jdk创建代理的例子
import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;public class JDKProxyMain {    public static void main(String[] args) {        JDKProxyTestInterface target = new JDKProxyTestInterfaceImpl();        // 根据目标对象创建代理对象        JDKProxyTestInterface proxy =         (JDKProxyTestInterface) Proxy         .newProxyInstance(target.getClass().getClassLoader(),                target.getClass().getInterfaces(),                 new JDKProxyTestInvocationHandler(target));        // 调用代理对象方法        proxy.testProxy();    }    interface JDKProxyTestInterface {        void testProxy();    }    static class JDKProxyTestInterfaceImpl                     implements JDKProxyTestInterface {        @Override        public void testProxy() {            System.out.println("testProxy");        }    }   static class JDKProxyTestInvocationHandler                            implements InvocationHandler {        private  Object target;        public JDKProxyTestInvocationHandler(Object target){            this.target=target;        }        @Override        public Object invoke(Object proxy, Method method,                             Object[] args) throws Throwable {            System.out.println("执行前");            Object result=  method.invoke(this.target,args);            System.out.println("执行后");            return result;        }    }
3.2.1 .2 cglib创建代理的例子
import org.springframework.cglib.proxy.Enhancer;import org.springframework.cglib.proxy.MethodInterceptor;import org.springframework.cglib.proxy.MethodProxy;import java.lang.reflect.Method;public class CglibProxyTest {   static class CglibProxyService {        public  CglibProxyService(){        }        void sayHello(){            System.out.println(" hello !");        }    }    static class CglibProxyInterceptor implements MethodInterceptor{        @Override        public Object intercept(Object sub, Method method,             Object[] objects, MethodProxy methodProxy)                                          throws Throwable {            System.out.println("before hello");            Object object = methodProxy.invokeSuper(sub, objects);            System.out.println("after hello");            return object;        }    }    public static void main(String[] args) {        // 通过CGLIB动态代理获取代理对象的过程        Enhancer enhancer = new Enhancer();        // 设置enhancer对象的父类        enhancer.setSuperclass(CglibProxyService.class);        // 设置enhancer的回调对象        enhancer.setCallback(new CglibProxyInterceptor());        // 创建代理对象        CglibProxyService proxy= (CglibProxyService)enhancer.create();        System.out.println(CglibProxyService.class);        System.out.println(proxy.getClass());        // 通过代理对象调用目标方法        proxy.sayHello();    }}
3.2.1 .3 jdk创建代理与cglib创建代理的区别
类型jdk创建动态代理cglib创建动态代理
原理java动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理cglib动态代理是利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理
核心类Proxy 创建代理利用反射机制生成一个实现代理接口的匿名类InvocationHandler 方法拦截器接口,需要实现invoke方法net.sf.cglib.proxy.Enhancer:主要增强类,通过字节码技术动态创建委托类的子类实例net.sf.cglib.proxy.MethodInterceptor:方法拦截器接口,需要实现intercept方法
局限性只能代理实现了接口的类不能对final修饰的类进行代理,也不能处理final修饰的方法

3.2.2 Spring如何选择的使用哪种方式

Spring的选择选择如何代理时在DefaultAopProxyFactory 中。

public class DefaultAopProxyFactory implements AopProxyFactory,                                                         Serializable {   @Override   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);      }   }   //...   }
  • config.isOptimize() 查看源码注释时发现,这个是配置使用cglib代理时,是否使用积极策略。这个值一般不建议使用!

  • config.isProxyTargetClass() 就是@EnableAspectJAutoProxy中的proxyTargetClass属性。

//exposeProxy=true AopContext 可以访问,proxyTargetClass=true CGLIB生成代理 @EnableAspectJAutoProxy(exposeProxy=true,proxyTargetClass=true)

  • hasNoUserSuppliedProxyInterfaces 是否存在可代理的接口

总结下Spring如何选择创建代理的方式:

  1. 如果设置了proxyTargetClass=true,一定是CGLIB代理

  2. 如果proxyTargetClass=false,目标对象实现了接口,走JDK代理

  3. 如果没有实现接口,走CGLIB代理

4.总结

Spring如何实现AOP?,您可以这样说:

  1. AnnotationAwareAspectJAutoProxyCreator是AOP核心处理类

  2. AnnotationAwareAspectJAutoProxyCreator实现了BeanProcessor,其中postProcessAfterInitialization是核心方法。

  3. 核心实现分为2步
    getAdvicesAndAdvisorsForBean获取当前bean匹配的增强器 createProxy为当前bean创建代理

  4. getAdvicesAndAdvisorsForBean核心逻辑如下
    a. 找所有增强器,也就是所有@Aspect注解的Bean
    b. 找匹配的增强器,也就是根据@Before,@After等注解上的表达式,与当前bean进行匹配,暴露匹配上的。
    c. 对匹配的增强器进行扩展和排序,就是按照@Order或者PriorityOrdered的getOrder的数据值进行排序,越小的越靠前。

  5. createProxy有2种创建方法,JDK代理或CGLIB
    a. 如果设置了proxyTargetClass=true,一定是CGLIB代理
    b. 如果proxyTargetClass=false,目标对象实现了接口,走JDK代理
    c. 如果没有实现接口,走CGLIB代理

到此,关于"Spring如何实现AOP"的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注网站,小编会继续努力为大家带来更多实用的文章!

0