AOP 术语
- 1.target:目标类:需要被代理的类. 例如:UserService
- 2.Joinpoin:(连接点):所谓连接点是指那些可能被拦截到的点(方法).例如:所有的方法
- 3.PointCut 切入点: 已经被增强的连接点.例如:addUser()
- 4.advice 通知/增强,增强代码.例如:joinpoint
- 5.Weaving(织入):是指把增强advice应用到目标对象 target 来创建新的代理对象proxy 的过程
- 6.proxy 代理类(一个类被AOP织入增强后,就产生一个结果代理类)
- 7.Aspect(切面):是切入点pointCut和通知advice (引介)的结合
一个切入点和一个通知(增强) 就组成一个特殊的面
2.2.1 JDK动态代理
- JDK动态代理对"装饰者"设计模式简化 .使用前提:必须有接口
1.目标类:接口+实现类
2.切面类:用于存通知 MyAspect
3.工厂类:编写工厂去生成代理
4.测试
2.2.2 CGLIB 字节码增强
- 没有接口,只有实现类.
- 采用字节码增强框架 cglib,在运行时创建目标类的子类,从而对目标类增强.
- 导入jar包:
手动方式:
自动方式:
2.4 Spring 编写代理:半自动
- 让spring 创建代理对象,从spring容器中手动的获取代理对象
<!--创建目标类-->
<bean id="userService" class="com.xft.b_factory_bean.UserServiceImpl"></bean>
<!--创建处理类-->
<bean id="myAspect" class="com.xft.b_factory_bean.MyAspect"></bean>
<!--创建代理类
使用工厂bean FactoryBean,底层调用getObject() 返回特殊bean
ProxyFactoryBean 用于创建代理工厂bean,生成特殊代理对象
interfaces : 需要的接口们
通过<array>可以设置多个值
只有一个值时,value=""
target : 确定目标类
interceptorNames: 通知 切面类的名称,类型是String[],如果设置一个值value=""
optimize:强制使用CGLIB
如果目标类有接口,采用jdk动态代理
如果没有接口,采用cglib字节码增强
如果声明 optimize = true ,无论是否有接口,都采用cglib
-->
<bean id="proxyService" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="interfaces" value="com.xft.b_factory_bean.UserService"></property>
<property name="target" ref="userService"></property>
<property name="interceptorNames" value="myAspect"></property>
<property name="optimize" value="true"></property>
</bean>
2.5 spring aop编程:全自动 [掌握]
- 从spring容器获得目标类,如果配置aop,spring将自动生成代理
- 要确定目标类,aspectj 切入点表达式
<!--创建目标类-->
<bean id="userService" class="com.xft.c_spring_aop.UserServiceImpl"></bean>
<!--创建切面类(通知)-->
<bean id="myAspect" class="com.xft.c_spring_aop.MyAspect"></bean>
<!--3.aop编程
3.1 导入命名空间
3.2 使用 <aop:config> 进行配置
proxy-target-class="true" 声明时使用cglib代理
<aop:pointcut> 切入点,从目标对象获得具体方法
<aop:advisor> 特殊的切面,只有一个通知和一个切入点
advice-ref 通知引用
pointcut-ref 切入点引用
3.3 切入点表达式
execution(* com.xft.c_spring_aop.UserServiceImpl.*.*(..))
选择方法 返回值任意 包 类名任意 方法名任意 参数任意
-->
<aop:config proxy-target-class="true">
<aop:pointcut id="myPointCut" expression="execution(* com.xft.c_spring_aop.*.*(..))" />
<aop:advisor advice-ref="myAspect" pointcut-ref="myPointCut" />
</aop:config>
3 AspectJ
3.1 介绍
- AspectJ 是一个基于Java语言的AOP框架
- Spring2.0以后新增了对AspectJ切点表达式支持
@AspectJ 是AspectJ1.5新增功能通过JDK5 注解技术,允许直接在Bean类中定义切面.新版本Spring框架,建议使用AspectJ方式来开发AOP - 主要用途:自定义开发
3.2 切入点表达式 {掌握}
1. execution() 用于描述方法
语法:execution(修饰符 返回值 包.类.方法(参数)throws 异常)
修饰符,一般省略
public 公共方法
* 任意
返回值,
void 返回没有值
String 返回值字符串
* 任意
包,[省略]
com.xft.xxx 固定包名
com.xft.xxx*.service xxx包下面子包任意 (例如:com.xft.xxx.ssss.service)
com.xft.xxx.. xxx包下面所有子包
com.xft.xxx.*.service.. xxx包下面任意包,固定目录service,service目录任意包
类,[省略]
UserServiceImpl 指定类
*Impl 以Impl结尾
User* 以User开头
* 任意
方法名,不能省略
addUser 固定方法
add* 以add开头
*Do 以Do结尾
* 任意
(参数)
() 无参
(int) 一个整型
(int,int) 两个整型
(..) 任意参数
throw,可以省略,一般不写
综合1
execution(* com.xft.xxx.*.service..*.*(..))
综合2
<aop:pointcut express="execution(* com.xft.*.withCommit*(..))||
execution(* com.xft.*Service.*(..))" id="myPointCut">
2.within:匹配包或者子包中的方法
within(cn.itcaset.aop..*)
3.this:匹配实现接口的代理对象中的方法
this(cn.itcast.aop.user.UserDAO)
4.target:匹配实现接口的目标对象中的方法
target(cn.itcase.aop.user.UserDAO)
5.args:匹配参数格式符号标准的方法
args(int,int )
6.bean(id) 对指定的bean所有的方法
bean('userServiceId')
3.3 AspectJ 通知类型
- aop联盟定义的通知类型,具有特性接口,必须实现,从而确定方法名称
- aspectj 通知类型,只定义类型名称,已经方法格式
- 个数:6种
- before前置通知(应用:各种校验) 在方法执行前执行,如果通知抛出异常,阻止方法运行
- afterReturning:后置通知(应用:常规数据处理) 方法正常返回后执行,如果方法中抛出异常,通知无法执, 必须在方法执行后才执行,所以可以获得方法的返回值
- around:环绕通知(应用:十分强大,可以做任何事) 方法执行前后分别执行,可以阻止方法的执行
- afterThrowing:抛出异常通知(应用:包装异常信息) 方法抛出异常后执行,如果方法没有抛出异常,无法执行
- after:最终通知(应用:清理现场) 方法执行完毕后执行,无论方法中是否出现异常
3.4 基于xml
- 目标类:接口+实现
- 切面类:编写多个通知,采用aspectj通知名称任意(方法名任意)
- aop编程,将通知应用到目标类
- 测试
3.4 基于注解
3.4.1替换bean
<!--创建目标类-->
<bean id="userService" class="com.xft.d_aspect.b_anno.UserServiceImpl"></bean>
<!--创建切面类(通知)-->
<bean id="myAspect" class="com.xft.d_aspect.b_anno.MyAspect"></bean>
aop注解总结
@Aspect 声明切面,修饰切面类,从而获得,通知
通知
@Before 前置
@AfterReturning 后置
@Around 环绕
@AfterThrowing 抛出异常
@After 最终
切入点
@PointCut,修饰方法 private void xxx(){} 之后通过"方法名"获得切入点