前言
之前介绍了spring的ioc的整个启动流程,接下来研究下spring的另一个核心模块AOP。
正文
aop的思想
第一节曾简单介绍过aop的思想和优点,本文再回顾一下aop的使用场景。
上图描述的就是未采用AOP思想设计的程序,当我们红色框中圈定的方法时,会带来大量的重复劳动。程序中充斥着大量的重复代码,使我们程序的独立性很差。
而下图中是采用了AOP思想设计的程序,它把红框部分的代码抽取出来的同时,运用动态代理技术,在运行期对需要使用的业务逻辑方法进行增强。
aop的相关术语
连接点:方法开始时、结束时、正常运行完毕时、方法异常时等这些特殊的时机点,我们称之为连接点,项目中每个方法都有连接点,连接点是一种候选点
切入点:指定AOP思想想要影响的具体方法是哪些,描述感兴趣的方法
Advice增强:
第一个层次:指的是横切逻辑
第二个层次:方位点(在某一些连接点上加上横切逻辑,那么这些连接点就叫做方位点,描述的是具体的特殊时机)
Aspect切面:切面概念是对上述概念的一个综合
Aspect切口= 切入点+增强
= 切入点(锁定方法) + 方位点(锁定方法中的特殊时机)+ 横切逻辑
众多的概念,目的就是为了锁定要在哪个地方插入什么横切逻辑代码
Spring中AOP的代理选择
Spring 实现AOP思想使用的是动态代理技术
默认情况下,Spring会根据被代理对象是否实现接口来选择使用JDK还是CGLIB。当被代理对象没有实现任何接口时,Spring会选择CGLIB。当被代理对象实现了接口,Spring会选择JDK官方的代理技术,不过我们可以通过配置的方式,让Spring强制使用CGLIB。
Spring中AOP的配置方式和实现
在Spring的AOP配置中,也和IoC配置一样,支持3类配置方式。
第一类:使用XML配置
第二类:使用XML+注解组合配置
第三类:使用纯注解配置
简单讲讲注解模式的实现
- 开启spring对注解AOP的支持
@Configuration
@ComponentScan("com.test")
@EnableAspectJAutoProxy //开启spring对注解AOP的支持
public class SpringConfiguration {
}
- 在需要拦截的类上添加注解
/**
* 模拟记录⽇志
*/
@Component
@Aspect
public class LogUtil {
/**
* 第⼀步:编写⼀个⽅法
* 第⼆步:在⽅法使⽤@Pointcut注解
* 第三步:给注解的value属性提供切⼊点表达式
* 细节:
* 1.在引⽤切⼊点表达式时,必须是⽅法名+(),例如"pointcut()"。
* 2.在当前切⾯中使⽤,可以直接写⽅法名。在其他切⾯中使⽤必须是全限定⽅法名。
*/
@Pointcut("execution(* com.service.impl.*.*(..))")
public void pointcut(){}
@Before("pointcut()")
public void beforePrintLog(JoinPoint jp){
Object[] args = jp.getArgs();
System.out.println("前置通知:beforePrintLog,参数是:"+
Arrays.toString(args));
}
@AfterReturning(value = "pointcut()",returning = "rtValue")
public void afterReturningPrintLog(Object rtValue){
System.out.println("后置通知:afterReturningPrintLog,返回值
是:"+rtValue);
}
@AfterThrowing(value = "pointcut()",throwing = "e")
public void afterThrowingPrintLog(Throwable e){
System.out.println("异常通知:afterThrowingPrintLog,异常是:"+e);
}
@After("pointcut()")
public void afterPrintLog(){
System.out.println("最终通知:afterPrintLog");
}
/**
* 环绕通知
* @param pjp
* @return
*/
@Around("pointcut()")
public Object aroundPrintLog(ProceedingJoinPoint pjp){
//定义返回值
Object rtValue = null;
try{
//前置通知
System.out.println("前置通知");
//1.获取参数
Object[] args = pjp.getArgs();
//2.执⾏切⼊点⽅法
rtValue = pjp.proceed(args);
//后置通知
System.out.println("后置通知");
}catch (Throwable t){
//异常通知
System.out.println("异常通知");
t.printStackTrace();
}finally {
//最终通知
System.out.println("最终通知");
}
return rtValue;
}
}
后话
本文介绍了spring的aop思想和实现方式及相关知识,下一节将研究其代码实现。