1.AOP(Aspect-Oriented Programming)面向切面编程
OOP(Object-Oriented Programming)面向对象编程
AOP不是OOP的替代品,而是OOP的补充,采用横向抽取机制,完成对分散但却相同代码的使用
2.AOP术语
切面 | 封装横切到系统功能(例如事务处理)的类 |
连接点 | 程序运行时的一些时间点,如方法的调用或异常的抛出 |
切入点 | 需要处理的连接点(所有方法执行都是连接点,切入点是一个描述信息,修饰的是连接点) |
通知 | 由切面添加到特定的连接点(满足切入点规则)的一段代码 即在定义好的切入点处所有执行的程序代码,理解为切面开启后切面的方法,因此通知是切面的具体实现 |
引入 | 允许在现有的实现类中添加自定义的方法和属性 |
目标对象 | 指所有被通知的对象 |
代理 | 通知应用导目标对象之后被动态创建的对象 |
织入 | 将切面代码插入到目标对象上,从而生成代理对象的过程 |
3.动态代理
JDK与CGLIB
JDK动态代理:java.lang.reflect.*包提供的方式,必须借助一个接口才能产生代理对象
a.创建应用;b.创建接口及实现类(把实现类作为目标类,在代理类中对其进行增强处理);c.创建切面类(该类中可以定义多个通知(增强处理的功能方法));d.创建代理类(必须实现java.lang.reflect.InvocationHandler接口,并编写代理方法,在代理方法中需要通过Proxy实现动态代理);e.创建测试类(创建代理对象和目标对象,然后从代理对象中获取对目标对象增强后的对象,最后调用该对象的添加修改和删除方法 )
CGLIB动态代理:CGLIB(Code Generation Library)是一个高性能开源的代码生成包,采用非常底层的字节码技术,对指定的目标类生成一个子类,并对子类进行增强
4.基于代理类的AOP实现
在Spring中默认使用JDK动态代理实现AOP编程
使用org.springframework.aop.framework.ProxyFactoryBean创建代理是Spring AOP实现的最基本方式
通知类型(根据通知在目标类方法中的连接点位置划分)
环绕通知 | 在目标方法执行前和执行后实施增强,可应用于日志记录、事务处理等 |
前置通知 | 在目标方法执行前和执行后实施增强,可应用于权限管理 |
后置返回通知 | 在目标方法成功执行后实施增强,可应用于关闭流、删除临时文件等功能 |
后置通知 | 在目标方法执行后实施增强,与后置返回不同的是,不管是否发生异常都要执行该类通知,该类通知可应用于释放资源 |
异常通知 | 在方法抛出异常后实施增强,可应用于处理异常、记录日志等功能 |
引入通知 | 在目标类中添加一些新的方法和属性,可用于修改目标类(增强类) |
ProxyFactoryBean:
是org.springframework.beans.factory.FactoryBean接口的实现类
FactoryBean负责实例化一个Bean实例
ProxyFactoryBean负责为其他Bean实例创建代理实例
ProxyFactoryBean类的常用属性
target | 代理的目标对象 |
proxyInterfaces | 代理需要实现的接口列表 |
interceptorNames | 需要织入目标的Advice |
proxyTargetClass | 是否对类代理而不是接口,默认为false,使用JDK代理,为true时,使用CGLIB动态代理 |
singleton | 返回的代理实例是否为单例,默认为true |
基于XML配置开发AspectJ
AspectJ是一个基于Java语言的AOP框架
使用AspectJ实现Spring AOP的方式有两种:基于XML配置开发AspectJ;基于注解开发AspectJ
基于XML配置文件开发AspectJ:通过XML配置文件定义切面、切入点、通知
所有定义均在<aop:config>元素内
<aop:config> | 开发AspectJ的顶层配置元素 |
<aop:aspect> | 配置一个切面,属性ref指定切面的定义 |
<aop:pointcut> | 配置切入点,属性expression指定通知增强哪些方法 |
<aop:before> | 配置前置通知,属性method指定前置通知方法,属性pointcut-ref指定关联的切入点 |
<aop:after-returning> | 配置后返回通知,属性method指定后置返回通知方法,属性pointcut-ref指定关联的切入点 |
<aop:around> | 配置环绕通知,属性method指定环绕通知方法,属性pointcut-ref指定关联的切入点 |
<aop:after-throwing> | 配置异常通知,属性method指定异常通知方法,属性pointcut-ref指定关联的切入点 |
<aop:after> | 配置后置(最终),属性method指定后置(最终)通知方法,属性pointcut-ref指定关联的切入点 |
在配置文件中
<aop:pointcut expression="execution(* dynamic.jdk.*.*(..))" id="myPointCut"/>
该切入点表达式的含义是匹配dynamic.jdk包中任意类的任意方法的执行
其中第一个 * 表示返回类型,使用 * 表示所有类型
dynamic.jdk表示需要对应的包名
第二个 * 表示类名,使用 * 表示匹配包中所有类
第三个 * 表示方法,使用 * 表示匹配包中所有方法
后面的(..)表示方法的参数,其中(..)表示任意参数
基于注解开发AspectJ(实际开发更常用)
@Aspect | 用于定义一个切面,注解在切面类上 |
@Pointcut | 用于定义切入点表达式。使用时需要定义一个切入点方法(方法为返回值void 且方法体为空的方法 ) |
@Before | 用于定义前置通知,使用时为其指定value属性值,该值可以为是已有的切入点,也可以直接定义切入点表达式 |
@AfterReturning | 用于定义后置返回通知,使用时为其指定value属性值,该值可以为是已有的切入点,也可以直接定义切入点表达式 |
@Around | 用于定义环绕通知,使用时为其指定value属性值,该值可以为是已有的切入点,也可以直接定义切入点表达式 |
@AfterThrowing | 用于定义异常通知,使用时为其指定value属性值,该值可以为是已有的切入点,也可以直接定义切入点表达式 |
@After | 用于定义后置(最终)通知,使用时为其指定value属性值,该值可以为是已有的切入点,也可以直接定义切入点表达式 |
具体步骤:
创建切面类,并进行注解(在此类中编写各种类型通知)
注解目标类
创建配置文件
创建测试类