1.AOP概述
简介:
AOP(Aspect Oriented Programming)面向切面编程,而面向切面编程是一种代码设计思想;
AOP的作用:
在不修改目标对象的情况下添加新的业务逻辑,增强方法
实现原理:
底层使用了动态代理技术实现AOP的面向切面编程思想
AOP中的术语:
1.连接点,即被代理对象中的所有方法
2.切入点,即被代理对象中需要被增强的方法
3.通知,目标对象需要增强的内容,或方法
4.切面,即由切入点和通知组成的一个关系网,也就是一个关系表
2.切入点表达式
指示符 | 示例 | 作用(细粒度) |
---|---|---|
bean | bean(accountService) | 精确到IOC容器的bean |
within | within(com.pkx.xml.service.impl.AccountServiceImpl) | 精确到类 |
execution | execution(public void com.pkx…save(…)) | 精确到方法 |
概述:
使用切入点表达式准确控制所有切入点,可以根据需要命名,这样的话方便管理切入点和通知之间的关系也就是方便管理切面;
特殊符号的使用:
符号 | 说明 |
---|---|
* | 匹配任意字符串 |
? | 修饰符,表示一个或这0个 |
.. | 匹配多层目录 |
execution:
execution(modififiers-pattern? ret-type-pattern declaring-type-pattern?name-pattern(param-pattern) throws-pattern?)
- modififiers-pattern: 权限访问修饰符 (可填)
- ret-type-pattern: 返回值类型 (必填)
- declaring-type-pattern: 全限定类名 (可填)
- name-pattern: 方法名 (必填)
- param-pattern: 参数名 (必填)
- throws-pattern: 异常类型 (可填)
XML配置:
配置位置:
<!--即xml文件中的这个标签下-->
<aop:config>
<aop:pointcut expression="bean(配置内容)">
</aop:config>`
类型 | 配置内容 |
---|---|
bean | <aop:config> <aop:pointcut expression="bean(配置内容)"> </aop:config> |
within | <aop:config> <aop:pointcut expression="within(配置内容)"> </aop:config> |
execution | <aop:config> <aop:pointcut expression="execution(配置内容)"> </aop:config> |
3.AOP通知
伪代码理解:
try{
[前置通知]
// 执行目标对象方法..
targer.method(..);
[后置通知]
} catch (Exception e){
[异常通知]
} finally {
[最终通知]
}
分类:
前置通知
后置通知
异常通知
最终通知
环绕通知
环绕通知
可以根据自己的需要设置通知
4.XML配置AOP
配置切入点:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean class="com.ps.service.AccountService" id="service"></bean>
<bean class="com.ps.log.LogService" id="logService"></bean>
<!--配置AOP
proxy-target-class:配置选择那种代理模式,默认是自动选择,那个合适选择那个,也可以理解为是否强制使用cglib
true:cglib动态代理模式
false:jdk动态代理模式
-->
<aop:config proxy-target-class="true">
<!--配置切入点,即配置要增强的方法
id:切入点的名称
expression:切入点表达式,即设置要增强的是那个类的那个方法,配置的是具体的方法
-->
<aop:pointcut id="pt"
expression="execution(void com.ps.service.AccountService.get())"/>
<!--
bean:切入点表达式,配置之后该类下的所有方法都是切入点,都需要增强
*通配符依旧可以表示所有,所有的service结尾的bean下的所有方法都需要增强
-->
<aop:pointcut id="ppt"
expression="bean(*service)"/>
<aop:pointcut id="pppt" expression="within(com.ps.service.AccountService)"/>
<!--配置切面,即配置切入点和通知(增强)的关系
ref:配置命名空间,也就是配置增强方法的类,这个类必须是IOC容器管理的类,也就是必须配置好的类
-->
<aop:aspect ref="logService">
<!--后置通知,或者后置增强,也就是切入点方法执行之后执行-->
<!--
method:增强方法,或者通知方法
pointcut-ref:引入的切入点,也就是要增强的那个方法
-->
<aop:after method="log" pointcut-ref="pt"></aop:after>
</aop:aspect>
</aop:config>
</beans>
通知配置:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean class="com.ps.service.AccountService" id="service"></bean>
<bean class="com.ps.log.LogService" id="logService"></bean>
<aop:config>
<aop:pointcut id="pt" expression="execution(void com.ps.service.AccountService.get())"/>
<aop:aspect ref="logService">
<!--配置顺序为:前置,后置,异常,最终通知-->
<!-- <aop:before method="before" pointcut-ref="pt"></aop:before>
<aop:after-returning method="later" pointcut-ref="pt"></aop:after-returning>
<aop:after-throwing method="exception" pointcut-ref="pt"></aop:after-throwing>
<aop:after method="finalLog" pointcut-ref="pt"></aop:after>-->
<!--环绕通知-->
<aop:around method="around" pointcut-ref="pt"></aop:around>
</aop:aspect>
</aop:config>
</beans>
5.注解配置AOP
package com.ps.log;
import com.ps.service.AccountService;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import org.springframework.test.annotation.Commit;
@Component
@Aspect
public class LogService {
public void log() {
System.out.println("记录日志信息");
}
@Pointcut("execution(void com.ps.service.AccountService.get())")
public void pt() {
}
// @Before("execution(void com.ps.service.AccountService.get())")
public void before() {
System.out.println("before");
}
// @AfterReturning("within(com.ps.service.AccountService)")
public void later() {
System.out.println("later");
}
// @AfterThrowing("pt()")
public void exception() {
System.out.println("exception");
}
public void finalLog() {
System.out.println("finalLog");
}
/**
* 演示: 环绕通知
* 优点:
* 1. 通用: 可以代替前后异常最终四大通知
* 2. 而且没有顺序BUG
* 3. 可以获取到切入点 (权限很大)
* 缺点:
* 需要自己创建类类实现
*/
@Around("pt()")
public Object around(ProceedingJoinPoint point) {
try {
before();
Object[] args = point.getArgs();
Object result=point.proceed(args);
later();
return result;
} catch (Throwable throwable) {
exception();
} finally {
finalLog();
}
return null;
}
}