引入SpringAOP:
当我们存在许多的功能,比如订单管理,用户管理灯光模块的功能,要为这些模块添加日志功能,事务管理等功能,我们可以在这些模块中添加相应的代码。但是这种添加代码的方式,不利于代码的复用,也会直接修改的原先的代码结构。或者将日志,事务等抽离成为一个方法。在这些模块中调用这些方法从而达到代码复用的目的。但即使抽离相同的部分,在后续修改功能,或者取消日志这些功能,添加功能上,还是需要从代码本身去修改。这样还是一个高耦合的程序。
怎样使之成为一个高内聚低耦合的程序呢?
AOP的作用:
面向切面编程,用于日志处理,性能统计,安全控制,事务处理等方面,实现公共功能性的重复使用。
AOP的特点:
- 降低模块和模块之间的耦合度,提高业务代码的聚合度(高内聚,低耦合)
- 提高代码复用性
- 提高系统的扩展性(高版本兼容低版本)
- 可以在不影响原有功能基础上添加新功能
AOP底层实现: JDK动态代理+CGLIB动态代理
SpringAOP术语:
- 连接点:类里面可以被增强的方法,称为连接点
- 切入点:类里面,实际被增强的方法,称为切入点
- 通知:实际增强的逻辑部分称为通知
- 切面:通知+切入点
通知的分类:
- 前置通知:方法前执行
- 后置通知:方法后执行
- 异常通知:方法异常执行
- 最终通知:方法有没有异常最终都执行
- 环绕通知:类似于四个通知组合的结果
3:SpringAOP实现
1:环境搭建
maven引入依赖:
<!--aop-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.9</version>
</dependency>
<!--cglib-->
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.2.2</version>
</dependency>
添加Spring.XML配置
引入aop名称空间:
xmlns:aop="http://www.springframework.org/schema/aop"
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
开启AOP代理:
<aop:aspectj-autoproxy/>
2:注解实现
- @Aspect:当前类为切面类
- @Pointcut(value = “execution + 表达式”) 定义切入点
- 前置通知@Before(value = “切入点方法名”)
- 返回通知@AfterReturning(value = “切入点方法名”)
- 异常通知@AfterThrowing(value = “切入点方法名”)
- 最终通知@After(value = “切入点方法名”)
- 环绕通知@Around(value = “切入点方法名”)
@Aspect//切面注解:表示当前类为切面类
@Component//将对象交给IOC管理
public class LogCut {
/**
* 切入点:规定声明方法被拦截 需要处理什么方法
* 定义切入点:@PointCut()
*/
@Pointcut(value = "execution(* com.lk.service..*.*(..))")
public void cut(){}
@Before(value = "cut()")
public void before(){
System.out.println("前置通知,在方法执行前通知");
}
@AfterReturning(value = "cut()")
public void afterReturning(){
System.out.println("返回通知,在方法正常结束通知");
}
@After(value = "cut()")
public void after(){
System.out.println("最终通知,无论抛出异常都通知");
}
@AfterThrowing(value = "cut()",throwing = "e")
public void afterThrowing(Exception e){
System.out.println("异常通知,在方法抛出异常通知");
System.out.println(e.getMessage());
}
//可代替其它通知
@Around(value = "cut()")
public Object around(ProceedingJoinPoint pjp){
//前置通知
System.out.println("环绕通知的前置通知");
Object proceed = null;
try {
//必须写这个语句,否则切入点的方法不执行
proceed = pjp.proceed();
//返回通知
System.out.println("环绕通知的返回通知");
} catch (Throwable throwable) {
throwable.printStackTrace();
//异常通知
System.out.println("环绕通知的异常通知");
}
//最终通知
System.out.println("环绕通知的最终通知");
return proceed;
}
}
3:XML实现
将一个类交给IOC管理:通过xml配置该类为切面类
<!--aop配置-->
<aop:config>
<!--选择切面类-->
<aop:aspect ref="logCou02">
<!--切入点-->
<aop:pointcut id="cut" expression="execution(* com.lk.dao.UserDao.test())"/>
<!--通知-->
<aop:before method="before" pointcut-ref="cut"/>
<aop:after-returning method="afterReturning" pointcut-ref="cut"/>
<aop:after method="after" pointcut-ref="cut"/>
<!--异常 e-->
<aop:after-throwing method="afterThrowing" throwing="e" pointcut-ref="cut"/>
<aop:around method="around" pointcut-ref="cut"/>
</aop:aspect>
</aop:config>