AOP
通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
Aop中常用名词解释
Aspect(切面):切入点+通知。
joinPoint(连接点):目标对象,所有可以增强的方法。
Advice(通知/增强):增强代码。
PointCut(切入点):目标对象,将要和已经增强的方法。
Introduction(引入):声明某个方法或字段。
Target(目标对象):被代理的对象
AOP 代理(AOp Proxy) AOP框架创建的对象用来实现切面。
Weaving(织入):将通知应用到切入点的过程。
具体工作流程
编写核心代码->公用代码抽取->和业务层(其他代码)之间进行联系
Spring配置
<aop:config>
<aop:aspect id="logAdvice" ref="logger">
<aop:before method="printLog" pointcut="execution(public void com.Service.impl.AccountService.saveAccount())"></aop:before>
<aop:after-returning method="printLog1" pointcut="execution(public void com.Service.impl.AccountService.saveAccount())"></aop:after-returning>
<aop:after-throwing method="printLog2" pointcut="execution(public void com.Service.impl.AccountService.saveAccount())"></aop:after-throwing>
<aop:after method="printLog3" pointcut="execution(public void com.Service.impl.AccountService.saveAccount())"></aop:after>
</aop:aspect>
</aop:config>
- before:前置通知
- after-returing:后置通知
- after-throwing:异常通知
- after:最终通知
后置通知和异常通知只能出现一个~
表达式execution的通配符书写规范
需要添加包
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.10</version>
</dependency>
<aop:config>
<aop:aspect id="logAdvice" ref="logger">
<aop:before method="printLog" pointcut="execution(* *..*.*(..))"></aop:before>
</aop:aspect>
</aop:config>
execution标准书写是(访问修饰符,返回值,包名…,类名,方法名,参数)
- 全通配写法
* *..*.*(..)
- 访问修饰符可以省略
- 包名可以用通配符
*
代替,但是有几个就要写几个,或者在通配符*
后点两个点*..
可以获得当前包下所有子包 - 方法名也可以用*来代替
- 参数列表基础参数类型可以直接写,或者是(java.xxx.xxx),使用
..
代表任意类型并且可有可无,*
任意类型但必须要有
<aop:config>
<aop:aspect id="logAdvice" ref="logger">
<aop:before method="printLog" pointcut-ref="exe"></aop:before>
<aop:pointcut id="exe" expression="execution(public void com.Service.impl.AccountService.saveAccount())"/>
</aop:aspect>
</aop:config>
使用<aop:pointcut>
可以定义表达式,后期调用即可,大大减少了代码量,注意使用范围,只有当前标签内才可以使用
环绕通知的切换
<aop:config>
<aop:aspect id="logAdvice" ref="logger">
<aop:around method="printLog" pointcut-ref="exe"></aop:around>
<aop:pointcut id="exe" expression="execution(public void com.Service.impl.AccountService.saveAccount())"/>
</aop:aspect>
</aop:config>
这样配置完成后无法执行业务代码需要在类中进行进一步的设置ProceedingJoinPoit.proceed
,明确环绕通知的切入点,是Spring提供的方法
public void printLog(ProceedingJoinPoint pjp){
try{
Object []args=pjp.getArgs();//方法执行所需要的参数
System.out.println("前开始记录日志了");
pjp.proceed(args);//明确调用业务层方法(切入点方法)
System.out.println("后开始记录日志了");
}catch (Exception e){
e.printStackTrace();
System.out.println("异常开始记录日志了");
} catch (Throwable throwable) {
throwable.printStackTrace();
} finally {
System.out.println("终了开始记录日志了");
}
}
通过所在的位置来决定通知输出的内容
注解的方法
注解的方法可能会出现通知顺序出错的问题
@Pointcut
定义execution表达式
@EnableAspectJAutoProxy
不使用XML配置方式