文章目录
前言
在实际开发中我们需要添加一些非业务的代码,例如提交事务,记录日志等等,当你遇到这样的问题的时候,你会是什么想法呢,是各写一个记录日志的工具类和提交事务的工具类吗?如果是这样的话,会导致这两个工具类侵入到了业务逻辑的代码中,影响了业务逻辑代码的可读性,降低了代码的可维护性,同时也增加了开发难度。这个时候aop就要登场了啊.
叙述
AOP简介
AOP(Aspect Orient Programming),面向切面编程,是面向对象编程 OOP 的一种补充。在运行时,动态地将代码切入到类的指定方法、指定位置上的编程思想就是面向切面的编程。例如转账功能,在转账代码的前后需要一些非业务方面的处理,权限控制,记录日志,事务的开启与结束,这些代码就可以使用AOP将其切入到转账代码的前后,这样就可以很好地分离业务代码和非业务代码。
AOP的优点就是降低代码之间的耦合,提高代码的复用性。
根据上面aop的特点,正好也解决了开头我们所遇到的问题.把日志/安全/事务这样的代码和业务代码完全隔离开来,因为他们的关注点和业务代码的关注点完全不同 ,他们之间应该是正交的,他们之间的关系
应该是这样的:
如果把这个业务功能看成一层层面包的话, 这些日志/安全/事务 像不像一个个“切面”(Aspect) ?
如果我们能让这些“切面“能和业务独立, 并且能够非常灵活的“织入”到业务方法中, 那就实现了面向切面编程(AOP)!
底层原理
spring底层就是采用动态代理模式实现AOP的。采用了两种代理:
- JDK 的动态代理,如果被代理了实现了接口,会默认使用jdk的动态代理。
- CGLIB的动态代理,如果类没有实现接口,会使用CGLIB动态代理。
spring之所以会引入这两种方式是因为其各有优缺点,
- 从性能上讲,使用字节码处理的CGLIB要比使用反射的JDK动态代理好。
- 从耦合度上讲,jdk要好于额外需要依赖字节码处理框架ASM的CGLIB。
AOP的术语
(1)目标对象(Target)
目标对象指 将要被增强的对象。即包含主业务逻辑的类的对象。上例中的UserDaoImpl 的对象若被增强,则该类称为目标类,该类对象称为目标对象。当然,不被增强,也就无所谓目标不目标了。
(2)切面(Aspect)
切面泛指非业务逻辑。上例中的事务处理、日志处理就可以理解为切面。常用的切面有通知,实际就是对业务逻辑的一种增强。
(3)连接点(JoinPoint)
连接点指可以被切面织入的方法。通常业务接口中的方法均为连接点。
(4)切入点(Pointcut)
切入点指切面具体织入的方法。在 UserDaoImpl 类中,若 addUser()被增强,而doOther()不被增强,则 addUser()为切入点,而 doOther()仅为连接点。 被标记为 final 的方法是不能作为连接点与切入点的,因为是不能被修改的,不能被增强的。
(5)通知(Advice)
通知是切面的一种实现,可以完成简单织入功能(织入功能就是在这里完成的)。上例中的MyInvocationHandler 就可以理解为是一种通知。换个角度来说,通知定义了增强代码切入到目标代码的时间点,是目标方法执行之前执行,还是之后执行等。通知类型不同,切入时间不同。切入点定义切入的位置,通知定义切入的时间。Advice有下面几种,这里使用常用的AspectJ方式:
- 前置通知(Before advice):在连接点之前执行,即目标方法执行之前执行。
- 后置通知(After returning advice):在连接点正常结束之后执行,如果连接点抛出异常,则不执行。
- 异常通知(After throwing advice):在连接点抛出异常后执行
- 最终通知(After (finally) advice):在连接点结束之后执行,无论是否抛出异常,都会执行。
- 环绕通知(Around advice):在连接点之前和之后均执行。
(6)织入(Weaving)
织入是指将切面代码插入到目标对象的过程。上例中 MyInvocationHandler 类中的 invoke()
方法完成的工作,就可以称为织入。
(7)aop代理(AOP proxy)
spring中的aop代理有两种:jdk自带的动态代理和CGLIB代理。
小结
通过这篇文章的讲解,不知道您对aop的了解是否有那么一点亲切感了呢.
感谢您的阅读~~