Spring-AOP

参考雷丰阳老师的视频

IOC 整合其他框架

AOP(面向切面编程) 声明式事务 jdbcTemplate

面向切面编程:基于oop基础之上的新的编程思想
指在程序运行期间,将某段代码动态的切入到指定方法的指定位置进行运行的这种编程方式,面向切面编程

场景:计算器运行计算方法的时候进行日志记录
加日志:
1)直接编写在方法内部:不推荐,修改维护麻烦;
日志记录:系统的辅助功能
业务逻辑:核心功能
高耦合

2)业务逻辑,日志模块在核心功能运行期间,自己动态的加载
可以使用动态代理将日志代码动态的在目标方法执行前后进行执行

jdk动态代理
为传入进来的参数对象创建一个动态代理对象
public static Calculator getProxy(Calculator calvulator){}

动态代理:
jdk默认的动态代理 如果目标对象没有实现任何接口 是无法为他创建代理对象

Sprig实现了aop 底层就是动态代理
实现简单,而且没有强制要求必须实现接口

将某段代码(日志)动态的切入(不把日志代码写死在业务逻辑方法中)到指定方法的指定位置
(spring简化了面向切面编程)

切面类
连接点:每一个方法的每一个位置都是连接点
切人点:每一个方法正需要执行日志记录的地方
切入点表达式

如何将日志类(切面类)中的这些方法(通知方法)动态的在目标方法运行的各个位置切入

AOP:
1.导入包
2.写配置
1)将目标类和切面类(封装了通知方法(在目标方法执行前后执行的方法))加入容器中
@Serivce
@Component
2)@Aspect 告诉spring 到底哪个方法是切面类 @Aspect
3)告诉spring 切面类的每一个方法,都是何时何地执行
@Before(execution(访问权限符 方法返回值 方法签名))
@Before 在目标方法之前运行
@After 在目标方法结束之后
@AfterReturning 在目标方法正常返回之后
@AfterThrowing 在目标方法抛出异常之后运行
@Around ,环绕

executuon(访问权限符 返回值类型 方法签名)
@Before("execution(public int com.shucheng.demo.service.impl.MyCalculator.add(int ,int ))")
4)开启基于注解的AOP模式
3,测试
从ioc容器中拿到目标对象 如果使用类型,一定要用接口类型
AOP的底层就是动态代理 容器中保存的组件就是他的代理对象
容器中没有切面对象时 加入的是本身对象 有 是代理对象

cgllib动态代理 :加强版的面向切面编程:即使象没有实现任何接口也能创建
cglib 可以为没有接口的组件创建代理对象
//通过类型
MyCalculator myCalculator = (MyCalculator) ioc.getBean(MyCalculator.class);
//通过id查找
MyCalculator myCalculator = (MyCalculator) ioc.getBean("myCalculator");
如果有接口就转成接口类型 没接口就转成类的类型

切入点表达式(通配符)
@Before("execution(public int com.sundear.demo.service.impl.MyCalculator.add(int,int))")
*
1)匹配1个或多个字符
@Before("execution(public int com.sundear.demo.service.impl.MyCalcul*or.*(int,int))")
2)匹配任意一个参数 方法参数重载
@Before("execution(public int com.sundear.demo.service.impl.MyCalculator.*(int,*))")
匹配两个参数一个int 一个任意
3)任意包(只能匹配一层路径)
@Before("execution(public int com.sundear.*.service.impl.MyCalculator.*(int,*))")
4)也可以匹配返回值,但是权限位置不能使用* 权限可以写可以不写
..
1)匹配任意多个参数
@Before("execution(public int com.sundear.demo.service.impl.MyCalculator.*(..))")
2)匹配多层路径
@Before("execution(public int com.sundear..service.impl.MyCalculator.*(int,*))")

&& || !
最模糊execution(* *.*(..))

通知方法的执行顺序
before after afterReturning
before after afterThrowing

获取通知方法的详细信息 JoinPoint
方法参数 Arrays.asList(joinPoint.getArgs())
方法名 joinPoint.getSignature().getName()

获取返回值
@AfterReturning(value = "execution(public int com.sundear.demo.service.impl.MyCalculator.sub(int,*))",
returning = "object")
public static void returns(Object object){}
获取异常 throwing="exception"

spring对通知方法的约束
通知方法是spring利用反射调用的 ,每次方法调用都得确定这个方法的参数表的值
参数表上的每一个参数,Spring都得知道是什么
Exception 指定Spring可以接收哪些异常

环绕通知 @Around
抽取可重用的切入点表达式
随便声明一个没有实现的返回void 的空方法
给方法上标注@Pointcut注解
value="方法名"就能重用
@AfterReturning(value = “方法名()”)


环绕通知 @Around
@Around("execution(public int com.shucheng.demo.service.impl.MyCalculator.add(int,int))")
public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
Object[] args = proceedingJoinPoint.getArgs();
Object proceed=null;
try{
//利用反射执行目标方法
System.out.println("环绕前置通知");
proceed = proceedingJoinPoint.proceed(args);
System.out.println("环绕返回通知");
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);//异常也要抛出去
}
//返回值一定要返回出去
return proceed;
}
通知顺序:
环绕前置通知
普通前置通知
方法执行
环绕返回通知/环绕异常通知
环绕后置通知
普通通知结束
普通通知返回

环绕通知优于普通通知先执行

多切面运行参数
先进后出
@Order(1)赋值小优先级高
环绕只影响当前切面类
示例:
Log 加环绕
Log 在va执行之前

环绕前置
log前置
va前置
目标方法执行
va后置
va返回
环绕返回
环绕后置
log后置
log返回

AOP的使用场景:
1。AOP加日志保存到数据库
2。AOP做权限验证 环绕通知
3。AOP做安全检查
4。AOP做事务控制 :前置通知获取连接,设为非自动提交,方法正常执行完,返回通知进行提交,如果出现异常,异常通知的话进行回滚。


基于注解的AOP
1,将目标类和切面类加入到ioc容器中
2, 告诉spring 哪个是切面类@Aspect
3. 在切面类中使用五个通知注解来配置切面中的这些通知方法在何时何地运行
4. 开启基于注解的AOP功能

基于配置的AOP
利用aop注解 进行上述四个步骤
前置通知和环绕前置通知 哪个配置得早 哪个先

注解和配置
注解 快速简单
配置 功能完善 重要的用配置 不重要的用注解

原文地址:https://www.cnblogs.com/yxj808/p/15343260.html