Spring(四)【AOP】
动态代理
动态代理是指程序在整个运行过程中根本就不存在目标类的代理类,目标对象的代理对象只是由代理生成工具(非真实定义的类)在程序运行时由JVM根据反射机制等机制动态生成的。代理对象与目标对象的代理关系在程序运行时才确立
动态代理的方式:
1)JDK动态代理:要求是目标类必须实现接口
java语言通过java.lang.reflect包提供三个类支持代理模式:
Proxy:Proxy.newProxyInstance() 创建目标对象的代理对象
Method:method.invoke(target,args) 创建目标方法
InvocationHandler接口:在接口的实现类中,重写invoke(),实现功能的增强


2)cglib动态代理:cglib第三方的工具库,能够生成代理对象
cglib创建代理对象的原理:继承。cglib能够创建目标类的子类,在子类中重写方法,实现功能的增强,该子类就是代理类
cglib的使用要求:目标类不是final的,目标方法也不能是final的
AOP(Aspect Orient Programming):面向切面编程,是基于动态代理的,把动态代理的技术进行了规范,升华。
AOP中可以使用jdk动态代理,也可以使用cglib动态代理
Aspect:切面,指需要增强的功能,包括:常见的事务、日志、方法参数的检查、权限、统计执行时间,切面有一个特点是非业务功能,一般是可以单独使用的
JoinPoint:连接点,指业务方法,这个方法加入了切面的功能
PointCut:切入点,连接点的集合,有0或多个连接点(方法),切入点表示切面执行的位置
目标对象:需要被增强功能的类
Advice:通知,通知表示切面执行的时间,通知也属于增强,是切面在程序中的表示,通知可以是接口也可以是注解
例如:在方法前,或方法后,或方法前和方法后
注意:一个切面执行需要有切入点和通知
理解面向切面的开发:
1)识别切面,从项目中找出能够作为切面的功能,形成单独的模块
2)把切面加入合适的位置,合适的时间
AOP的好处:解耦合:业务功能和非业务功能的耦合,减少重复代码
实现AOP框架的工具
1)Aspectj
Aspectj实现AOP的两个重要概念
a)通知:共分五种:前置、后置、环绕、异常、最终,每种通知都表示一次执行时间
b)切入点表达式:execution(方法的定义),表示切面执行的位置

Aspectj实现AOP的两种方式:
a)使用注解表示通知
b)使用xml配置文件(做事务时使用这种方式)
Aspectj实现AOP的步骤
a)新建Maven
b)加入依赖:spring依赖和Aspectj依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>4.3.16.RELEASE</version>
</dependency>
c)新建业务接口和实现类,要给业务方法增强功能
d)新建切面类
d.1)在类的定义上@Aspect

d.2)在类中自定义实现切面的自定义方法,在方法的上面加入@aspectj中的通知注解,例如@Before

e)新建spring的配置文件
e.1)声明目标类对象
e.2)声明切面类对象
e.3)通过spring和aspectj创建目标对象的代理

f)新建测试类,从spring容器中获取对象,通过这个对象执行业务方法,实现业务功能的增强

通过JoinPoint获取doSome方法在执行时的信息

注意:JoinPoint可以用在所有的通知方法中,但如果通知方法中有多个参数时,JoinPoint必须位于第一个
@AfterReturning:后置通知
属性:
1)value:切入点表达式
2)returning:自定义的变量,表示目标方法的返回值,变量的名称必须和通知方法的参数名一样

特点:
1)在目标方法之后执行的
2)能够获取到目标方法的执行结果
3)修改目标方法不会影响最后的执行结果
注意:当返回结果为基本数据类型和字符串时,在通知方法里对返回值进行修改,不会影响目标方法的返回结果,因为这个值是拷贝过来的。但是如果返回的是对象(如上图),那么返回结果就会发生改变,因为这里返回的是对象的引用,我们通过引用改变了堆内存中对象的属性,就会对目标方法中的返回结果产生影响
@Around:环绕通知
属性:value(切入点表达式)
特点:
1)在目标方法的前后都能增强功能
2)控制目标方法是否执行
3)修改目标方法的执行结果
环绕通知方法的定义:
1)有参数ProceedingJoinPoint,且因为ProceedingJoinPoint继承JoinPoint,因此可以通过pjp获取连接点方法的定义、方法的名称、参数等信息
2)有返回值,推荐使用Object

@AfterThrowing:异常通知
属性:
1)value:切入点表达式
2)throwing:自定义的变量,表示目标方法抛出的异常对象,必须和通知方法参数名一样
特点:
1)在目标方法抛出异常时执行的,可以看作是对目标方法监控
2)不是异常处理程序,异常还是抛出的

@After:最终通知
属性:value(切入点表达式)
特点:
1)在目标方法之后执行的
2)总是会被执行的

@Pointcut:定义和管理切入点
属性:value(切入点表达式)
作用:这个方法的名称就是切入点的别名,其他的通知注解的value属性可以使用方法名称,表示切入点

当目标类有接口时,默认使用的是JDK动态代理,目标类没有接口,默认使用cglib动态代理。
当目标类有接口时,也可以使用cglib动态代理,需要在声明自动代理生成器后边添加proxy-target-class="true",即可

通过xml的方式来实现AOP
1)新建一个类,类里面包含所需要的通知方法
2)在配置文件中声明目标类与切面类对象
3)配置AOP
3.1)声明切入点的位置
3.2)声明切面
3.3)配置通知

2)spring框架使用aop
关键步骤:
1)实现通知的接口,例如环绕通知MethodInterceptor
2)在spring的配置文件中,声明ProxyFactoryBean,创建目标对象的代理,ProxyFactoryBean其作用等同于jdk动态代理中的Proxy
具体步骤:
1)新建Maven
2)加入依赖,只需spring依赖
3)新建业务接口和实现类,要给业务方法增强功能
4)新建实现接口的类,在类中重写方法,实现功能的增强(相当于InvocationHandler)
spring中AOP的可用接口:
前置通知:MethodBeforeAdvice
后置通知:AfterReturningAdvice
环绕通知:MethodInterceptor
异常通知:ThrowsAdvice

5)新建spring配置文件
5.1)声明目标类和切面类对象
5.2)声明ProxyFactoryBean,创建目标对象的代理对象

6)新建测试类,从spring容器中获取对象,通过这个对象执行业务方法,实现功能的增强


浙公网安备 33010602011771号