AOP介绍
AOP 是什么
AOP(Aspect Oriented Programing)面向切面编程,它是一种设计思想,的目的就是在不修改源代码的基础上,对原有功能进行增强。
思路分析
编写目标对象:AcccountServiceImpl
编写增强功能(通知): Logger
配置切面:描述通知和切点之间的关系,增强功能添加到哪个位置
切点表示式
切入点表达式是一个快速匹配方法的通配格式,类似于正则表达式
切点表达式的组成:
-
关键字(访问修饰符 返回值 包名.类名.方法名(参数)异常名)
-
关键字:描述表达式的匹配模式
- execution表达式可以用于明确切面粒度最小是达到方法级别(重要)
-
-
访问修饰符:方法的访问控制权限修饰符(一般会省略)
-
返回值类型::* ,表示任意类型
-
路径:方法所在的类(此处也可以配置接口名称)
通配符
*:单个独立的任意符号,可以独立出现,也可以作为前缀或者后缀的匹配符出现
.. :多个连续的任意符号,可以独立出现,常用于简化包名与参数的书写
切点数量和位置
切点表达式可以配置在不同位置:公共切点、局部切点、私有切点
通知类型
AOP的通知类型共5种
- 前置通知:原始方法执行前执行,如果通知中抛出异常,阻止原始方法运行 应用:数据校验
<aop:before> - 后置通知:原始方法执行后执行,无论原始方法中是否出现异常,都将执行通知 应用:资源释放(线程关闭、连接关闭)
<aop:after> - 返回后通知:原始方法正常执行完毕并返回结果后执行,如果原始方法中抛出异常,无法执行 应用:返回值相关数据处理
<aop:after-returning> - 抛出异常后通知:原始方法抛出异常后执行,如果原始方法没有抛出异常,无法执行 应用:对原始方法中出现的异常信息进行处理
<aop:after-throwing> - 环绕通知:在原始方法执行前后均有对应执行执行,能够实现前面4个类型通知的功能 应用:十分强大,可以做前4种类型通知
通知的执行顺序(了解)
当同一个切入点配置了多个通知时,通知会存在运行的先后顺序,该顺序以通知配置顺序为优先 注解:顺序无法调换,固定
<aop:config>
<!--配置切点-要对哪些方法增强-->
<!--aop:pointcut:配置切点表达式-->
<!--expression: 表达式,表示后面是配置切点表达式-->
<!--
方法所在的路径
com.eponine.aop.service.impl.AccountServiceImpl.*: 匹配AccountServiceImpl中的所有方法
com.eponine.aop.service.impl.*.* : 对service.impl包下所以类中的所有方法都匹配
com.eponine..impl.*.* : ..在这里表示0-N个包
com.eponine..impl.*.update*(..): 此时update* 表示对update开头的方法进行匹配
方法的参数列表:
(..): ..表示忽略参数的数量还有类型 () (String str) (Integer id,Account account)
(*) : 此时表示参数个数只有1个,但是忽略类型 ()这个是不行的,(Account account)OK (String str)OK (Integer id,Account account)不行
-->
<!--公共切点:所有切面都可以使用-->
<aop:pointcut id="pt"
expression="
execution(
public * com.eponine.AOP.service.impl.AccountServiceImpl.*(..)
)"/>
<aop:aspect ref="myLogger">
<!--局部切点:只能当前切面配置可以使用-->
<aop:pointcut id="pt3" expression="execution(* com.eponine.AOP.service.impl.AccountServiceImpl.*(..))"/>
<!--私有的切点:只有当前通知可以使用-->
<aop:before method="beforeTime" pointcut-ref="pt" pointcut="execution(* com.itheima.aop.service.impl.AccountServiceImpl.*(..))">></aop:before>
<aop:after-returning method="afterReturnningTime" pointcut-ref="pt"></aop:after-returning>
<aop:after-throwing method="throwingMethod" pointcut-ref="pt"></aop:after-throwing>
<aop:after method="afterMethod" pointcut-ref="pt"></aop:after>
<aop:around method="arountMethod" pointcut-ref="pt"></aop:around>
</aop:aspect>
</aop:config>
AOP注解版
增强类中完成注解配置
- AccountServiceImpl加上@Service注解,此步骤省略
- 增强类MyLogger注解配置
@EnableAspectJAutoProxy开启AOP注解支持- 使用注解
@Aspect表示这是一个增强类 - 配置切点方法
- 配置通知注解
public class TxManager {
ThreadLocal<Connection> threadLocal = new ThreadLocal<>();
@Autowired
private DataSource dataSource;
@Pointcut("execution(* com.eponine.spring.service.impl.*ServiceImpl.*(..))")
public void pt(){}
@Around("pt()")
public Object arroundTran(ProceedingJoinPoint pjp){
Object result = null;
try {
start();
result = pjp.proceed();
commit();
}catch (Throwable throwable) {
throwable.printStackTrace();
rollBack();
} finally {
close();
}
return result;
}
//获取连接
public Connection getConnection(){
Connection connection = threadLocal.get();
if (connection==null) {
try {
connection = dataSource.getConnection();
threadLocal.set(connection);
} catch (SQLException e) {
e.printStackTrace();
}
}
return connection;
}
//设置手动提交事务
public void start(){
Connection connection = threadLocal.get();
if (threadLocal.get()==null){
try {
connection = dataSource.getConnection();
threadLocal.set(connection);
} catch (SQLException e) {
e.printStackTrace();
}
}
try {
threadLocal.get().setAutoCommit(false);
} catch (SQLException e) {
e.printStackTrace();
}
}
//提交事务
public void commit(){
try {
threadLocal.get().commit();
} catch (SQLException e) {
e.printStackTrace();
}
}
//回滚事务
public void rollBack(){
try {
threadLocal.get().rollback();
} catch (SQLException e) {
e.printStackTrace();
}
}
//关闭资源
public void close(){
try {
threadLocal.get().close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}