这篇文章主要介绍“Spring如何实现AOP”,在日常操作中,相信很多人在Spring如何实现AOP问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Spring如何实现AOP”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!
最近工作中我都是基于注解实现AOP功能,常用的开启AOP的注解是@EnableAspectJAutoProxy,我们就从它入手。
上面的动图的流程的步骤就是:
@EnableAspectJAutoProxy
--> AspectJAutoProxyRegistrar
-->AopConfigUtils .registerAspectJAnnotationAutoProxyCreatorIfNecessary
-->AnnotationAwareAspectJAutoProxyCreator.class
AnnotationAwareAspectJAutoProxyCreator查看其中文注释(如下),确定它就是AOP的核心类!--温安适 20191020
/** 1.AspectJAwareAdvisorAutoProxyCreator的子类 ,用于处理当前应用上下文中的注解切面 2.任何被AspectJ注解的类将自动被识别。 3.若SpringAOP代理模式可以识别,优先使用Spring代理模式。 4.它覆盖了方法执行连接点 5.如果使用<aop:include>元素, 则只有名称与include模式匹配的@aspectj bean才被视为切面 ,并由spring自动代理。 6. Spring Advisors的处理请查阅, org.springframework.aop .framework.autoproxy.AbstractAdvisorAutoProxyCreator */ @SuppressWarnings("serial") public class AnnotationAwareAspectJAutoProxyCreator extends AspectJAwareAdvisorAutoProxyCreator { //...省略实现 }注解切面
虽然找到了核心类,但是并没有找到核心方法!下面我们尝试画类图确定核心方法。
AnnotationAwareAspectJAutoProxyCreator的部分类图。
从类图看到了AnnotationAwareAspectJAutoProxyCreator实现了BeanPostProcessor,而AOP功能应该在创建完Bean之后执行,猜测AnnotationAwareAspectJAutoProxyCreator实现BeanPostProcessor的postProcessAfterInitialization(实例化bean后处理)是核心方法。 查看AnnotationAwareAspectJAutoProxyCreator实现的postProcessAfterInitialization方法,实际该方法在其父类AbstractAutoProxyCreator中。
//AbstractAutoProxyCreator中的postProcessAfterInitialization实现 @Override public 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个方法。
查看源码如下,默认实现在AbstractAdvisorAutoProxyCreator中。
@Override @Nullable 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方法,就干了3件事
找所有增强器,也就是所有@Aspect注解的Bean
找匹配的增强器,也就是根据@Before,@After等注解上的表达式,与当前bean进行匹配,暴露匹配上的。
对匹配的增强器进行扩展和排序,就是按照@Order或者PriorityOrdered的getOrder的数据值进行排序,越小的越靠前。
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; }
AnnotationAwareAspectJAutoProxyCreator 重写了findCandidateAdvisors,下面我们看看具体实现了什么
@Override 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. if (this.aspectJAdvisorsBuilder != null) { //@Aspect注解的类在这里除了 advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors()); } return advisors; }
从该方法我们可以看到处理@Aspect注解的bean的方法是:this.aspectJAdvisorsBuilder.buildAspectJAdvisors()。 这个方法如下:
public List<Advisor> buildAspectJAdvisors() { List<String> aspectNames = this.aspectBeanNames; if (aspectNames == null) { synchronized (this) { aspectNames = this.aspectBeanNames; if (aspectNames == null) { List<Advisor> 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<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; }
这个方法可以概括为:
找到所有BeanName
根据BeanName筛选出被@Aspect注解的类
针对类中被Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class注解的方法,先按上边的注解顺序排序后按方法名称排序,每一个方法对应一个Advisor。
众所周知,创建代理的常用的2种方式是:JDK创建和CGLIB,下面我们就看看这2中创建代理的例子。
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; } }
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(); } }
类型 | jdk创建动态代理 | cglib创建动态代理 |
---|---|---|
原理 | java动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理 | cglib动态代理是利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理 |
核心类 | Proxy 创建代理利用反射机制生成一个实现代理接口的匿名类InvocationHandler 方法拦截器接口,需要实现invoke方法 | net.sf.cglib.proxy.Enhancer:主要增强类,通过字节码技术动态创建委托类的子类实例net.sf.cglib.proxy.MethodInterceptor:方法拦截器接口,需要实现intercept方法 |
局限性 | 只能代理实现了接口的类 | 不能对final修饰的类进行代理,也不能处理final修饰的方法 |
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如何选择创建代理的方式:
如果设置了proxyTargetClass=true,一定是CGLIB代理
如果proxyTargetClass=false,目标对象实现了接口,走JDK代理
如果没有实现接口,走CGLIB代理
Spring如何实现AOP?,您可以这样说:
AnnotationAwareAspectJAutoProxyCreator是AOP核心处理类
AnnotationAwareAspectJAutoProxyCreator实现了BeanProcessor,其中postProcessAfterInitialization是核心方法。
核心实现分为2步
getAdvicesAndAdvisorsForBean获取当前bean匹配的增强器 createProxy为当前bean创建代理
getAdvicesAndAdvisorsForBean核心逻辑如下
a. 找所有增强器,也就是所有@Aspect注解的Bean
b. 找匹配的增强器,也就是根据@Before,@After等注解上的表达式,与当前bean进行匹配,暴露匹配上的。
c. 对匹配的增强器进行扩展和排序,就是按照@Order或者PriorityOrdered的getOrder的数据值进行排序,越小的越靠前。
createProxy有2种创建方法,JDK代理或CGLIB
a. 如果设置了proxyTargetClass=true,一定是CGLIB代理
b. 如果proxyTargetClass=false,目标对象实现了接口,走JDK代理
c. 如果没有实现接口,走CGLIB代理
到此,关于“Spring如何实现AOP”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注亿速云网站,小编会继续努力为大家带来更多实用的文章!
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。