AOP并不是 age of Putin 普丁的年龄,而是 Aspect Oriented Programming 面向切面编程。
就是一种代理模式,将非核心业务剥离出来。例如,打印计算前后的数据,如果每个类都要手动添加那就太累了。这就需要一个代理。
分为静态代理和动态代理。静态代理我们不用,因为它就是手动去写代理类,还是很繁琐。
动态代理分为JDK动态代理(拜把子接口模式),Cglib动态代理(认干爹模式,生成子类来使用)
而AOP框架又对动态代理进行了简化。编写增强类 + 注解来解决插入的问题
面向对象(OOP)的垂直开发模式,出现了 非核心代码冗余的问题,不方便管理。
面向切面编程(AOP)是一种横向开发模式
/**
* 增强类的内部要存储增强代码
*
* 1. 定义方法存储增强代码,具体定义几个根据插入位置定
* 2. 使用注解配置 指定插入目标方法的位置
* 前置 @Before
* 后置 @AfterReturning
* 异常 @AfterThrowing
* 最后 @After
* 环绕 @Around
*
* try{
* //前置 @Before
* 目标方法执行
* //后置 @AfterReturning
* }catch (Exception e)
* {
* //异常 @AfterThrowing
* }finally{
* //最后 @After
* }
*
* 3. 配置切点表达式 【选中插入的方法 切点】
* 4. 补全注解@Component 和@Aspect
*
* spring AOP --- 重点是配置 --> jdk/Cglib
*
* 5. 开启aspect注解的支持
*/
@Component
@Aspect
public class LogAdvice {
@Before("execution(* com.atguigu.service.impl.*.*(..))")
public void start(){
System.out.println("方法开始了");
}
@After("execution(* com.atguigu.service.impl.*.*(..))")
public void after(){
System.out.println("方法结束了");
}
@AfterThrowing("execution(* com.atguigu.service.impl.*.*(..))")
public void error(){
System.out.println("方法报错了");
}
}
@Component
@Aspect
public class TxAroundAdvice {
/**
* 环绕通知,需要你在通知中,定义目标方法的执行!
* @param pjp 目标方法
* @return 目标方法的返回值
* @throws Throwable
*/
@Around("com.atguigu.pointcut.MyPointCut.pointCut()")
public Object transaction(ProceedingJoinPoint pjp){
Object[] args = pjp.getArgs();
Object result=null;
try{
//增强代码
System.out.println("开启事务");
result = pjp.proceed(args);
System.out.println("事务结束");
}catch (Exception e){
System.out.println("事务回滚");
} catch (Throwable e) {
throw new RuntimeException(e);
} finally {
System.out.println("finally最后执行.....");
}
return null;
}
}
@Component
@Aspect
@Order(1) //设置优先级,数字越小优先级越大
public class TxAdvice {
@Before("com.atguigu.pointcut.MyPointCut.pointCut()")
public void begin(){
System.out.println("开启事务....");
}
@AfterReturning("com.atguigu.pointcut.MyPointCut.pointCut()")
public void commit(){
System.out.println("事务提交.....");
}
@AfterThrowing("com.atguigu.pointcut.MyPointCut.pointCut()")
public void rollBack(){
System.out.println("事务回滚......");
}
}
第一种
@Pointcut("execution(* com..impl.*.*(..))")
public void pointCut(){}
@AfterReturning(value = "pointCut()",returning = "result")//正常结束会走这里
public void afterReturning(JoinPoint joinPoint,Object result){
}
第二种
/**
* 定义一个存放切点的类,里面的方法使用切点表达式
* 使用全限定修饰符定位到类然后再.方法()同样实现切点的复用引用
*/
package com.atguigu.pointcut;
import org.aspectj.lang.annotation.Pointcut;
public class MyPointCut {
@Pointcut("execution(* com..impl.*.*(..))")
public void pointCut(){
}
@Pointcut("execution(* com..impl.*.*(..))")
public void mPc(){
}
}
@Component
@Aspect
public class LogAdvice {
@Before("com.atguigu.pointcut.MyPointCut.pointCut()")
public void start(){
System.out.println("方法开始了");
}
@After("com.atguigu.pointcut.MyPointCut.pointCut()")
public void after(){
System.out.println("方法结束了");
}
@AfterThrowing("com.atguigu.pointcut.MyPointCut.pointCut()")
public void error(){
System.out.println("方法报错了");
}
}
/**
* 定义四个增强方法获取对象的方法信息,返回值,异常对象
* (JoinPoint joinPoint)
* joinPoint中就包含目标方法的信息
*
* 1. 定义方法 - 增强代码
* 2. 使用注解 - 指定对应的位置
* 3. 切点表达式,选中方法
* 4. 切面和ioc的配置
* 5. 开启aspect注解的支持
*
* 增强中获取目标信息
* 1. 全部增强方法中获取,获取目标方法的信息 包括方法名 参数 访问修饰符 所属类的信息
* (JoinPoint joinPoint)
* * joinPoint中就包含目标方法的信息
* 2. 返回的结果,只在AfterReturning中
* (Object result)
* @AfterReturning(value = "execution(* com..impl.*.*(..))",returning = "result")//正常结束会走这里
* //代表result接收返回结果
* 3. 获取异常信息,只在afterThrowing
* (JoinPoint joinPoint,Throwable throwable)
* @AfterReturning(value = "execution(* com..impl.*.*(..))",returning = "result")//正常结束会走这里
*
*/
@Aspect
@Component
public class MyAdvice {
@Before("execution(* com..impl.*.*(..))")
public void before(JoinPoint joinPoint){
//1. 获取方法所属类的信息
String simpleName = joinPoint.getTarget().getClass().getSimpleName();
//2. 获取方法名称
int modifiers = joinPoint.getSignature().getModifiers();
String modifier = Modifier.toString(modifiers);
String methodName = joinPoint.getSignature().getName();
//3. 获取参数列表
Object[] args = joinPoint.getArgs(); //获取目标方法参数
}
@AfterReturning(value = "execution(* com..impl.*.*(..))",returning = "result")//正常结束会走这里
public void afterReturning(JoinPoint joinPoint,Object result){
}
@After("execution(* com..impl.*.*(..))")
public void after(JoinPoint joinPoint){
}
@AfterThrowing(value = "execution(* com..impl.*.*(..))",throwing = "throwable")
public void afterThrowing(JoinPoint joinPoint,Throwable throwable){
}
}
正常从IOC获取目标对象就行(IOC实际存储的是代理对象),注意使用接口来拿对象,具体实现类不可以,然后使用方法。
@SpringJUnitConfig(value = JavaConfiguration.class)
public class SpringAopTest {
//aop - 代理技术 - 因为实现类有接口,选择jdk代理 - 根据接口生成代理类 - 代理对象和目标对象是拜把子关系 - 必须使用接口接值
//aop - ioc - 真正存储的是代理对象,而不是目标对象了
@Autowired
private Calculator calculator;
@Test
public void test(){
int result = calculator.add(1, 0);
System.out.println("result = " + result);
}
}
推荐阅读: