AOP
1、动态代理
实现方式:JDK动态代理,使用jdk中的Proxy,Method,InvocationHandler创建代理
JDK动态代理要求目标类必须实现接口
cglib动态代理:是第三方的工具库,创建代理对象,原理是继承,通过继承目标类,创建子类
子类就是代理对象,要求目标类不能是final,方法也不能是final
2、动态代理的作用:
1)在目标类源代码不改变的情况下,增加功能
2)减少代码的重复
3)专注业务逻辑代码
4)解耦合,让你的业务功能和日志,事务非业务功能分离
3、AOP(Aspect Orient Programming)面向切面编程
Aspect: 切面,给你的目标类增加的功能,就是切面,像上面的日志、事务都是切面
切面的特点:一般都是非业务方法,独立使用的
Orient: 面向,对着
Programming: 编程
OOP: 面向对象编程
4、怎样理解面向切面编程?
1)需要在分析项目功能时,找出切面;
2)合理的安排切面的执行时间(在目标方法前,还是在目标方法后)
3)合理的安全切面执行的位置,在哪个类?哪个方法?增强功能
术语:
*Aspect:切面,表示增强的功能,就是一堆代码,完成某个功能。非业务功能,常见的切面功能
有日志,事务,统计信息,参数检查,权限验证。
JoinPoint:连接点,连接业务方法和切面的位置,就某类中的一个业务方法
*Pointcut:切入点,指多个连接点方法的集合,多个方法
目标对象,给哪个类的方法增加功能,这个类就是目标对象
* Advice:通知,通知表示切面功能执行的时间
切面三个关键要素
切面的功能代码====切面能干什么
切面的执行位置====使用Pointcut表示切面执行的位置
切面的执行时间====使用Advice表示时间,在目标方法之前,还是目标方法之后
aop的实现
aop是一个规范,是动态的一个规范化,一个标准
aop的技术实现框架:
1、spring:spring在内部实现了aop规范,能做aop的工作
spring主要在事务处理时使用aop,
我们项目开发中很少使用spring的aop实现,因为spring的aop比较笨重
2、aspectJ:一个开源的,专门做aop的框架,spring框架中集成了aspectJ框架,可以通过spring使用其功能
aspectJ框架实现aop有两种方式:
1、使用xml的配置文件
2、使用注解,我们在项目中做aop功能,一般都使用注解,aspectJ有5个注解。
学习aspectJ框架的使用
1、切面的执行时间,执行时间在规范中叫做Advice(通知、增强),
在aspectJ框架中使用注解表示,也可以使用xml配置文件中的标签
1)@Before
2)@AfterReturning
3)@Around
4)@AfterThrowing
5)@After
2、切面执行的位置,使用的是切入点表达式。
execution(访问权限 方法返回值 方法声明(参数) 异常类型)
每个部分用空格分开,访问权限和异常类型可以省略
* 表示多个字符
.. 用在参数时表示多个参数,用在包名时表示当前包及其子包路径
+ 用在类名后,表示当前类及子类,用在接口后,表示当前接口及实现类
举例:
//指定切入点为:任意公共方法:
execution(public * *(..))
//任何一个以set开始的方法
execution(* set*(..))
//定义在service包里的任意类的任意方法
execution(* service.*.*(..))
//定义在service包或子包里的任意类的任意方法
execution(* service..*.*(..))
//指定所有包下的service子包下所有类所有方法
execution(* *..service.*.*(..))
前置通知
//@Aspect作用:表示当前类是切面类
//切面类:是用来给业务方法增加功能的类,这个类中有切面的功能代码
//位置:在类定义的上面
@Aspect
public class MyAspectJ{
/*定义方法:方法是实现切面功能的。
方法的定义要求:
1.公共方法public
2.方法返回void
3.方法名称自定义
4.方法可以有参数,也可以没有参数。
如果有参数,参数不是自定义的,有几个参数类型可以使用
-----------------------------------------------------------------------------------------
@Before:前置通知注解
属性:value,是切入点表达式 ,表示切面的功能执行的位置。
位道:在方法的上面
特点:
1.在目标方法之前先执行的
2.不会改变目标方法的执行结果
3.不会影响目标方法的执行。*/
@Before(value="execution(* *..SomeServiceImpl.*(..))")
public void isBefore(JoinPoint jp){
------------------------------------------------------------------------------------
/*
指定通知方法中的参数: JoinPoint
JoinPoint:业务方法,要加入切面功能的业务方法
作用:可以在通知方法中获取方法执行时的信息,例如方法名称, 方法的参数列表。
如果你的切面功能中需要用到方法的信息,就加入JoinPoint
这个Joinpoint参数的值是由框架赋予,必须是 第一个位置的参数 */
jp.getSignature();//方法的全限定名称
jp.getSignature().getName();//方法名
Object args[] = jp.getArgs();//方法的参数列表
}
}
后置通知
后置通知定义方法,方法是实现切面功能的。
方法的定义要求:
1.公共方法public
2.方法没有返回值
3.方法名称自定义
4.方法有参数的,推荐是object, 参数名自定义
/*
@AfterReturning
属性:: 1.value切入点表达式
2. returning自定义的变量,表示目标方法的返回值的。
自定义变量名必须和通知方法的形参名一样。
位置:在方法定义的上面
特点: 1.在目标方法之后执行的。
2.能够获取到目标方法的返回值,可以根据这个返回值做不同的处理功能
3.可以修改这个返回值
*/
@AfterReturning(value = "execution(* *..SomeServiceImpl.*(..))",
returning = "res")
public void myAfterReturning(Object res){
Student stu = (Student)res;
stu.setName("李四");//如果返回值是一个引用类型,可以通过后置方法来修改返回值
}
环绕通知
环绕通知方法的定义格式
1.方法是公共的,public
2.必须有一个返回值,推荐使用object
3.方法名称自定义
4.方法有参效,固定的参数ProceedingJoinpoint
@Around:环绕通知
属性:value切入点表达式
位置:在方法的定义什么
特点:
1.它是功能最强的通知
2.在目标方法的前和后都能增强功能。
3.控制目标方法是否被调用执行
4.修改原来的目标方法的执行结果。 影响最后的调用结果
环绕通知,等同于jdk动态代理的,InvocationHandler接口
参数: ProceedingJoinPoint 就等同于Method
作用:执行目标方法的
返回值:就是目标方法的执行结果 ,可以被修改
@Around(value = "execution(* *..SomeServiceImpl.doFirst(..))")
public Object myAround(ProceedingJoinPoint pjp) throws Throwable {
//实现环绕通知
//方法之前执行,开始事务
Object args[] = pjp.getArgs();
for (Object arg: args){
if("zhangsan".equals(arg)){//控制业务方法的执行
pjp.proceed();//执行方法
}
}
//方法之前执行,提交事务
return "abc";//改变方法的返回值
}
异常通知
异常通知方法的定义格式
1.public
2.没有返回值
3.方法名称自定义
4.方法有个一个Exception,如果还有是JoinPoint,
/*
@AfterThrowing:异常通知
属性:
1.value 切入点表达式
2.throwinng 自定义的变量,表示目标方法抛出的异常对象。
3.变量名必须和方法的参数名一样
特点:
1.在目标方法抛出异常时执行的
2.可以做异常的监控程序,监控目标方法执行时是不是有异常。
3.如果有异常,可以发送邮件,短信进行通知
-------------------------------------------------------------------------*/
@AfterThrowing(value =” execution(* *. . SomeServiceImpl . doSecond(..))",
throwing = "ex" )
public void myAfterThrowing(Exception ex) {
System.out .println("异常通知:方法发生异常时,执行: "+ex. getMessage());
//发送邮件,短信, 通知开发人员
最终通知
最终通知方法的定义格式
1.public
2.没有返回值
3.方法名称自定义
4.方法没有参数,如果有就是JoinPoint,
@After :最终通知
属性: value切入点表达式
位置:在方法的上面
特点:
1.总是会执行
2.在目标方法之后执行的
3.一般用来做资源清除工作
PointCut
用途:定义和管理切入点, 如果项目中有多个重复的切入点表达式,可以使用PointCut进行代码复用。
属性:value切入点表达式
位置:在自定义的方法上面
特点:
当使用@Pointcut定义在一个方法的上面, 此时这个方法的名称就是切入点表达式的别名。
其它的通知中, value属性就可以使用这个方法名称,代替切入点表达式
@Around(value = "mypt())")
@Pointcut(value =”execution(* * .. SomeserviceImpl. doThird(..))" )
public void mypt(){
//无需代码
}