简单描述Sping的AOP就是动态代理加拦截器链实现面向切面编程。当然AOP肯定没有这么简单,但是如果能自己实现AOP然后再去看源码的话是不是会更轻松点呢。
众所周知,Sping中AOP之所以能起作用就是我们在目标类的基础上定义了很多通知,例如before(前置通知),after-returning(后置通知),after(最终通知),after-throwing(异常通知),around(后置通知)等,那么我们就可以先从这里入手定义自己的通知
public interface FilterChain { /** * 目标方法执行之前执行 * * @timestamp Feb 17, 2016 2:41:59 PM */ public void before(Object target, Matcher[] matchers); /** * 目标方法执行之后执行 * * @timestamp Feb 17, 2016 2:42:12 PM */ public void after(Object target, Matcher[] matchers); }
target是目标类,matchers是匹配规则,它是个Matcher数组。之后可以再定义它的子接口扩展一下通知的功能
public interface FilterChainSub extends FilterChain { /** * 处理catch中的异常 * * @timestamp Feb 17, 2016 5:57:09 PM * @param exception * @param target */ public void operateException(Exception exception, Object target); /** * 释放资源,相当于finally中的逻辑 * * @timestamp Feb 17, 2016 4:25:53 PM * @param target */ public void destroy(Object target); }
现在通知定义好了,下一步就要决定是什么机制调用了实现这些接口的实体。
ApplicationFilterChain.java 由于这个源码比较多就不贴了,把链接放这了。下面来看一下这个类的主要字段
/** * 实现过滤器链 */ private List<FilterChain> filterChainList = new ArrayList<>(); /** * 索引计数器 */ private int index = 0; /** * 目标方法 */ private Method method = null; /** * 目标对象 */ private Object target = null; /** * 参数 */ private Object[] args = null; /** * 匹配规则 */ private Matcher[] matchers;
这个其实就是一个过滤器链,在Spring中是拦截器链。拦截器与过滤器的最主要的区别就是拦截器是动态代理实现的,而过滤器是函数的回调实现的。所以总感觉这里Filter好一些。也许设计AOP的大牛们是从整体上来看的,他就是一个Interceptor。不管什么了能实现功能再说。filterChainList是之后要添加的通知集合。下面来看一下核心代码
public Object invoke(ApplicationFilterChain chain) { if (filterChainList.size() < 0) return null; if (chain.size() == chain.index()) { Object obj = null; try { obj = method.invoke(target, args); } catch (Exception e) { throw new RuntimeException(e); } return obj; } // 获取过滤链中当前索引所指向的节点 FilterChain f = chain.get(chain.index); Object obj = null; f.before(target, matchers); // 过滤链中当前索引+1 this.index++; obj = invoke(this); f.after(target, matchers); return obj; }
外界要调用这个invoke方法就要传进来一个ApplicationFilterChain实例,如果传入的这个chain中通知集合元素的个数等于它的index的话就执行目标方法。否则就根据索引从链中获取通知然后执行前置通知,执行this.index++;重新调用invoke方法,再调用后置通知。这里为什么可以成this.index++不是chain吗?是因为我在外面调invoke的对象和传入的参数是一个对象,所以chain和this就是一个对象。使用哪个都可以,如果感觉别扭的话可以把this换成chain。再者就是invoke方法的调用会形成一个递归,知道index==size时就会跳出递归。现在知道了通知是怎么被调用的。下一步就可以讨论整体结构是怎么形成的了。
public class Interceptor implements InvocationHandler { /** * 目标对象 */ private Object target = null; /** * 过滤器链 */ private ApplicationFilterChain filterChain = null; private String[] regular; /** * * @param target * 目标类 * @param filterChain * 过滤器链 * @param regular * 匹配规则 */ public Interceptor(Object target, ApplicationFilterChain filterChain, String... regular) { super(); this.target = target; this.filterChain = filterChain; this.regular = regular; } /** * 执行目标方法 */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { try { // 设置目标方法,目标类,参数 filterChain.setMethod(method); filterChain.setTarget(target); filterChain.setArgs(args); filterChain.setRegular(regular); return filterChain.invoke(filterChain); } catch (Exception e) { filterChain.operateException(e); } finally { filterChain.destroy(target); } return null; } }
这里我定义了一个拦截器类然后让它实现了InvocationHandler接口,如果不知道InvocationHandler是什么作用的话可以先看一下动态代理,这里就不说了。这个拦截器类有一个构造函数接收三个参数分别是被代理的目标类,过滤器链,匹配规则。之后在代理方法中分别对ApplicationFilterChain的必要参数进行了设置然后调用filterChain.invoke(filterChain);现在知道了上面的那个invoke是在哪被调用了,再者就是这个代理方法中的try,catch块也是很有必要的,在invoke抛出异常时,会被catch接住,然后调用filterChain的operateException。看一下这个方法。
public void operateException(Exception e) { for (FilterChain f : filterChainList) { if (f instanceof FilterChainSub) { ((FilterChainSub) f).operateException(e, target); } } }
它会在通知链中找到可以处理异常的通知然后处理掉他。这是一个很大的隐患,时间原因就不改了,有兴趣的朋友可以试着改改。例如可以使用FilterChain出错时的index作索引,取出通知实例然后调用它的处理异常的方法。destroy是同样的思路也有同样的毛病。下面是测试代码
public class TestAop { public static void main(String[] args) { ApplicationFilterChain chain = new ApplicationFilterChain(); chain.addChain(new Transactional()); ServiceImpl impl = new ServiceImpl(); Interceptor inte = new Interceptor(impl, chain, "^save*"); Service s = (Service) Proxy.newProxyInstance(// TestAop.class.getClassLoader(), // impl.getClass().getInterfaces(), // inte); s.save(); } }
源码地址:SpingAOP小实现
有兴趣的话也可以看一下这个小demo的具体应用场景:its智能交通系统。还有这个系统的反思。下一步SpingAOP源码走起!
相关推荐
NULL 博文链接:https://zhang-yingjie-qq-com.iteye.com/blog/319927
AOP的意思就是面向切面编程。本文主要是通过梳理JDK中自带的反射机制,实现 AOP动态代理模式,这也是Spring AOP 的实现原理
Spring AOP的实现机制中文版,动态代理及原理,自定义类加载器
spring ioc容器初始化流程图 spring ioc容器依赖注入流程图 spring aop实现原理流程图
Spring AOP面向方面编程原理Spring AOP面向方面编程原理Spring AOP面向方面编程原理Spring AOP面向方面编程原理Spring AOP面向方面编程原理Spring AOP面向方面编程原理Spring AOP面向方面编程原理
springAOP配置实现动态代理,有利于熟悉动态代理原理,深入了解spring。
一、适合人群 1、具备一定Java编程基础,初级开发者 ...(需要知道原理的请看spring aop源码,此处不做赘述) 3、可在现有源码上快速进行功能扩展 4、spring boot,mybatis,druid,spring aop的使用
Spring Aop的底层实现技术 --- Jdk动态代理原理 很不错的一篇文章
通过详细解析Spring AOP的源码,本文揭示了其背后的核心原理和实现机制。Spring AOP主要基于动态代理模式,它允许开发者在不改变原有代码结构的情况下,增加额外的行为。这主要通过定义“切面(Aspects)”和“通知...
NULL 博文链接:https://arne3166.iteye.com/blog/1046340
spring aop详解,详细地讲述了spring中aop的实现,实现原理,实现过程。
Spring框架系列(9) - Spring AOP实现原理详解之AOP切面的实现.doc
Spring框架系列(11) - Spring AOP实现原理详解之Cglib代理实现.doc
主要介绍了SpringAOP切点函数实现原理详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
这两种代理方式在Spring AOP中起到关键作用,用于实现横切关注点的切面编程。通过学习它们的原理和实际应用,您将能够更好地理解和利用Spring AOP来提高您的应用程序的可维护性和可扩展性。 内容亮点: JDK动态...
spring中动态代理机制的实现原理及AOP实现原理,JDK的反射,cglib类。
IoC原理分析 ... Spring AOP原理分析 Spring AOP基于XML和注解的实现 Spring应用之Spring JDBC实现 Spring应用之JdbcDaoSupport Spring应用之事务支持 Spring与Mybatis整合
如果一个类实现了一个或多个接口,那么Spring就会使用默认的JDK动态代理,如果没有实现任何接口,就会使用cglib来代理。当然我们也可以手动改变这些设置。这也是比较容易掉坑的部分,如果设置错了代理方式,那么在...
AOP(Aspect-OrientedProgramming,面向方面编程),可以说是OOP(Object-Oriented Programing,面向对象编程)的补充和完善。本文给大家介绍Spring 的aop实现原理,感兴趣的朋友一起学习吧
本代码通过使用spring aop+ehcache的技术,实现了方法级别的查询缓存,主要原理是 方法的完整路径+方法参数值,作为key,放入cache中,下次访问时先判断cache中是否有该key.