AOP
AOP:面向切面编程,扩展功能不修改源代码实现。
AOP原理
AOP采取横向抽取机制,取代了传统纵向继承体系重复性代码
纵向抽取机制
当我们有一个添加数据的方法add,此时需求在add方法执行后添加日志功能记录。
方法一:如左图,在add方法中直接添加日志逻辑,此时需要修改源代码。
方法二:如右图,为了不修改源代码,我们单独写一个添加日志的方法writelog,将writelog所在类当作父类,每个需要添加日志的类都继承此类,只需要在add方法最后调用父类的writelog方法,此时优化了方法一的代码,可是还不够好,当父类方法名改变时,子类调用时也需要改,这样又得修改源代码。这种调用父类方法添加功能叫纵向抽取机制,却仍然达不到我们的目的,所以接下来我们使用另一种机制解决。
横向抽取机制
横向抽取机制底层分两种情况实现。
情况一:如左图,当Dao是接口,DaoImpl是接口实现类,即有接口时,采用jdk动态代理创建DaoImpl类(接口实现类)的代理对象,实现功能。
情况二:如右图,只有User一个类,即没有接口时,采用cglib动态代理创建User类子类(父类的子类)的代理对象,通过调用父类方法完成增强。
AOP操作术语
Joinpoint(连接点):类里面可以被增强的方法,这些方法称为连接点。
Pointcut(切入点):所谓切入点是指我们要对哪些Joinpoint进行拦截的定义。
Advice(通知/增强):所谓通知是指拦截到Joinpoint之后所要做的事情就是通知,通知分为前置通知、后置通知、异常通知、最终通知、环绕通知(切面要完成的功能)。
Aspect(切面):是切入点和通知(引介)的结合。
Introduction(引介):引介是一种特殊的通知在不修改类代码的前提下,Introduction可以在运行期为类动态地添加一些方法或Field。
Target(目标对象):代理的目标对象(要增强的类)。
Weaving(织入):是把增强应用到目标的过程,把Advice 应用到 Target的过程。
Proxy(代理):一个类被AOP织入增强后,就产生一个结果代理类。
基于aspectj的XML配置AOP
在Spring里面进行AOP操作,使用aspectj实现。aspectj不是Spring一部分,和Spring一起使用进行aop操作,Spring2.0以后新增了对AspectJ支持。
Aop操作准备
1、除了导入基本的jar包之外,还需要导入aop相关的jar包
2、创建Spring核心配置文件,导入AOP的约束
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
</beans>
切入点表达式
execution ( [方法访问修饰符] 方法返回值 包名.类名.方法名(方法参数) [异常] )
方法返回值:可以用*表示任何返回值,全路径的类名等。
方法名:*代表所有,set*代表以set开头的所有方法。
方法参数:指定方法参数(声明的类型),(..)代表所有参数,(*)代表一个参数,(*,String)代表第一个参数为任何值,第二个为String类型。
public * cn.itcast.spring.dao.*.*(..) public修饰的dao包下所有类的所有方法
* cn.itcast.spring.dao.*.*(..) dao包下所有类的所有方法
* cn.itcast.spring.dao.UserDao+.*(..) dao包下UserDao接口及接口实现类的所有方法
* cn.itcast.spring.dao..*.*(..) dao包下,子孙包下所有方法
* save*(..) 所有save开头的方法
通知的类型
前置通知 <aop:before>:在目标方法执行之前执行
后置通知 <aop:after-returning>:在目标方法执行之后执行
环绕通知 <aop:around>:在目标方法执行前和执行后执行,使用proceedingJoinPoint.proceed();调用目标方法
异常抛出通知<aop:after-throwing>:在目标方法执行出现异常的时候执行
最终通知 <aop:after>:无论目标方法是否出现异常最终通知都会执行
Aop实例
Book类
public class Book {
public void bookp() {
System.out.println("bookp方法运行");
}
}
Order类
public class order() {
public void before() {
System.out.println("before方法运行");
}
public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("bookp方法运行之前");
proceedingJoinPoint.proceed();// 使用point.proceed()调用被增强的方法,抛出异常
System.out.println("bookp方法运行之后");
}
public void after_returning() {
System.out.println("after_returning方法运行");
}
public void after_throwing() {
System.out.println("after-throwing方法运行");
}
public void after() {
System.out.println("after方法运行");
}
}
配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="book" class="org.haiwen.pojo.Book"></bean>
<bean id="order" class="org.haiwen.pojo.Order"></bean>
<aop:config>
<!-- 配置切入点 -->
<aop:pointcut expression="execution(* org.haiwen.pojo.Book.bookp(..))" id="pointcut"></aop:pointcut>
<!-- 配置切入面 -->
<aop:aspect ref="order">
<!-- pointcut-ref与切入点的id匹配 -->
<!-- <aop:before method="before" pointcut-ref="pointcut" /> -->
<!-- <aop:around method="around" pointcut-ref="pointcut" /> -->
<!-- <aop:after-returning method="after_returning" pointcut-ref="pointcut" /> -->
<!-- <aop:after-throwing method="after_throwing" pointcut-ref="pointcut" /> -->
<!-- <aop:after method="after" pointcut-ref="pointcut" /> -->
</aop:aspect>
</aop:config>
</beans>
运行结果
before
before方法运行
bookp方法运行
around
bookp方法运行之前
bookp方法运行
bookp方法运行之后
after_returning
bookp方法运行
after_returning方法运行
after_throwing
bookp方法运行
after
bookp方法运行
after方法运行