# 第三章:Spring AOP ## 复习知识 ### 1.从java角度出发实现代理 JDK动态代理 和 CGLIB代理 的区别: (1)被代理对象不同 (2)产生代理对象的类不同 ### 2.从Spring角度出发实现代理: (1)导包:7个包: 5个核心包:commons-logging spring-context spring-beans spring-core spring-expression 2个包:spring-aop aoplliance (2)创建被代理对象,实现了某个接口的类 (3)切面类实现接口 (4)产生代理对象方式:xml文件 (5)测试 ### 3.AOP术语:7个 切面类:MyAspect 连接点: addUser() deleteUser() 调用前或后 切入点:就是连接点 增强处理/通知:就是切面中的方法 check_permission() log() 目标对象: 被代理对象 代理:代理对象 织入:生成代理对象的过程 ### 4.1和2中实现的代理有一个共同的特点(缺点): 代理对象不管调用哪一个目标方法,都会切入切面类中的方法 ### 5.有没有一种手段:让代理对象自由地选择调用哪一个目标方法时才切入切面类中的方法? —————————————————————————————————————————————————— ## 基于AspectJ实现AOP(实现代理) ### 一、基于xml (1)导包:5个核心包:commons-logging spring-context spring-core spring-beans spring-expression 2个包:spring-aspects aspectjweaver (2) 创建被代理对象 (3) 创建切面类 (4) 创建代理对象:xml文件使用aop编程 (5) 测试 代码实现如下: ```java package com.aspectj.xml; public interface UserDao { void addUser(); void deleteUser(); } ``` ```java package com.aspectj.xml; public class UserDaoImpl implements UserDao { @Override public void addUser() { System.out.println("添加用户"); // 模拟异常 // System.out.println(1/0); } @Override public void deleteUser() { System.out.println("删除用户"); } } ``` ```java package com.aspectj.xml; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; public class MyAspect { //前置通知 public void myBefore(JoinPoint joinPoint){ System.out.print("前置通知:模拟执行权限检查...,"); System.out.print("目标类是:"+joinPoint.getTarget()); System.out.println(",被植入增强处理的目标方法为:"+joinPoint.getSignature().getName()); } //后置通知 public void myAfterRturning(JoinPoint joinPoint) { System.out.print("后置通知:模拟记录日志..."); System.out.println("被植入增强处理的目标方法为:" + joinPoint.getSignature().getName()); } // 环绕通知 // ProceedingJoinPoint 是 JoinPoint 子接口,表示可以执行目标方法 // 1.必须是 Object 类型的返回值 // 2.必须接收一个参数,类型为 ProceeddingJoinPoint // 3.必须 throws Throwable public Object myAround(ProceedingJoinPoint proceedingJoinPoint)throws Throwable{ //开始 System.out.println("环绕开始:执行目标方法之前,模拟开始事务..."); // 执行当前目标方法 Object obj = proceedingJoinPoint.proceed(); //结束 System.out.println("环绕结束:执行目标方法之后,模拟关闭事物..."); return obj; } //异常通知 public void myAfterThrowing(JoinPoint joinPoint,Throwable e){ System.out.println("异常通知:"+"出错了"+e.getMessage()); } //最终通知 public void myAfter(){ System.out.println("最终通知:模拟方法结束后的释放资源..."); } } ``` ```java ``` ```java package com.aspectj.xml; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class XmlTest { public static void main(String[] args) { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("a.xml"); UserDao userDao = (UserDao) applicationContext.getBean("userDao"); userDao.addUser(); System.out.println("_______________"); userDao.deleteUser(); } } ``` 正常运行结果: ![image-20220328214914512](https://lsky.hhdxw.top/imghub/img/image-20220328214914512.png) 运行发生异常截图:出现结果为零异常 ![image-20220328214954611](https://lsky.hhdxw.top/imghub/img/image-20220328214954611.png) ### 二、基于注解(Annotation)-------减少xml中的代码量 (1) 导包 5个核心包:commons-logging spring-context spring-core spring-beans spring-expression 2个包:spring-aspects aspectjweaver (2) 创建被代理对象 (3) 创建切面类 注意:切面类中的注解相当于a.xml文件中的哪一句代码 (4) 创建xml文件:扫描所有的注解和开启AspectJ实现AOP ```java package com.aspectj.annotation; public interface UserDao { void addUser(); void deleteUser(); } ``` ```java package com.aspectj.annotation; import org.springframework.stereotype.Repository; //注解实现 //@Repository("userDao") public class UserDaoImpl implements UserDao { @Override public void addUser() { System.out.println("添加用户"); // 模拟异常 // System.out.println(1/0); } @Override public void deleteUser() { System.out.println("删除用户"); } } ``` ```java package com.aspectj.annotation; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.*; import org.springframework.stereotype.Component; //切面类,在此类中编写通知 @Aspect @Component public class MyAspect { // 定义切入点表达式 @Pointcut("execution(* com.aspectj.annotation.*.*(..))") // 使用一个返回值为 void 、方法体为空的方法来命名切入点 private void myPointCut(){} // 前置通知 @Before("myPointCut()") public void myBefore(JoinPoint joinPoint){ System.out.println("前置通知:模拟执行权限检查...,"); System.out.print("目标类是:"+joinPoint.getTarget()); System.out.println(",被植入增强处理的目标方法为:"+joinPoint.getSignature().getName()); } //后置通知 @AfterReturning("myPointCut()") public void myAfterReturning(JoinPoint joinPoint){ System.out.println("后置通知:模拟记录日志..."); System.out.println("被植入增强处理的目标方法为:" + joinPoint.getSignature().getName()); } //环绕通知 @Around("myPointCut()") public Object myAround(ProceedingJoinPoint proceedingJoinPoint)throws Throwable{ //开始 System.out.println("环绕开始:执行目标方法之前,模拟开始事务..."); //执行当前目标方法 Object obj = proceedingJoinPoint.proceed(); //结束 System.out.println("环绕结束:执行目标方法之后,模拟关闭事物..."); return obj ; } //异常通知 @AfterThrowing(value = "myPointCut()",throwing = "e") public void myAfterThrowing(JoinPoint joinPoint,Throwable e){ System.out.println("异常通知:"+"出错了"+e.getMessage()); } //最终通知 @After("myPointCut()") public void myAfter(){ System.out.println("最终通知:模拟方法结束后的释放资源..."); } } ``` ```java ``` ```java package com.aspectj.annotation; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class AnnotationTest { public static void main(String[] args) { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("b.xml"); UserDao userDao = (UserDao) applicationContext.getBean("userDao"); userDao.deleteUser(); userDao.addUser(); } } ``` 运行截图: ![image-20220328215304530](https://lsky.hhdxw.top/imghub/img/image-20220328215304530.png)