Spring——AOP思想、AOP开发、Pointcut语法、注解配置AOP

淡淡的烟草味﹌ 2023-07-10 08:56 88阅读 0赞

目录

  • 一、AOP思想

    • 1、AOP术语
    • 2、Pointcut语法
  • 二、AOP开发

    • 1、导入依赖
    • 2、配置AOP(XML方式)
    • 3、各种时机的增强细节
    • 4、注解配置AOP

在这里插入图片描述

Spring系列

  1. Spring — Spring简介、入门、配置 , IoC和DI思想
  2. Spring — IoC核心(基于XML)、DI核心(基于XML)
  3. Spring — 使用IoC和DI模拟注册案例、注解配置IoC和DI
  4. Spring — 静态代理、动态代理、拦截器思想
  5. Spring — AOP思想、AOP开发、Pointcut语法、注解配置AOP
  6. Spring — DAO层、Spring JDBC、Spring事务控制
  7. Spring — XML配置事务、注解+XML、纯注解的配置方式
  8. Spring整合MyBatis
  9. Spring Java Config — 组件注册相关注解
  10. Spring Java Config — 常用注解

一、AOP思想

跳转到目录
在这里插入图片描述

在开发中,为了给业务方法中增加日志记录,权限检查,事务控制等功能,此时我们需要去修改业务方法代码,考虑到代码的重用性,我们可以考虑使用OOP的继承或组合关系来消除重复, 但是无论怎么样, 我们都会在业务方法中纵向地增加这些功能方法的调用代码。

此时,既不遵循开闭原则,也会为后期系统的维护带来很大的麻烦。这些零散存在于业务方法中的功能代码,我们称之为横切面关注点,横切面关注点不属于业务范围,应该从业务代码中剥离出来。为了解决该问题, OOP思想是不行了,得使用AOP思想。

AOP(Aspect Oritention Programming): (在不修改源代码就能做到功能增强)

把一个个的横切关注点放到某个模块中去,称之为切面。那么每一个的切面都能影响业务的某一种功能,切面的目的就是功能增强,如日志切面就是一个横切关注点,应用中许多方法需要做日志记录的只需要插入日志的切面即可。
在这里插入图片描述
在这里插入图片描述
这种面向切面编程的思想就是AOP思想;

1、AOP术语

跳转到目录

  • Joinpoint : 连接点,被拦截到需要被增强的方法。where :去哪里做增强
  • Pointcut : 切入点,哪些包中的哪些类中的哪些方法,可认为是连接点的集合。where:去哪些地方做增强
  • Advice : 增强(额外功能),当拦截到Joinpoint之后,在方法执行的什么时机( when )做什么样(what)的增强。根据时机分为:前置增强、后置增强、异常增强、最终增强、环绕增强;
  • Aspect : 切面, Pointcut+ Advice ,去哪些地方+在什么时机+做什么增强
  • Target : 目标对象,被代理的目标对象
  • Weaving : 织入,把Advice加到Target.上之后,创建出Proxy对象的过程。
  • Proxy : 一个类被AOP织入增强后,产生的代理类
  • Advice : (增强)执行时机:

在这里插入图片描述

2、Pointcut语法

跳转到目录

  • AOP的规范本应该由SUN公司提出,但是被AOP联盟捷足先登。AOP联盟在制定AOP规范时,首先就要解决一个问题: 怎么表示切入点。也就是说怎么表达需要在哪些方法上做增强。这是一个如何表示WHERE的问题。
  • AOP规范后,面向切面编程的框架AspectJ也就应运而生了, 同时也确定如何去表达这个WHERE。
AspectJ切入点语法如下(表示在哪些包下的哪些类中的哪些方法上做切入增强):
  1. execution(modifiers-pattern? ret-type-pattern declaring-type-pattern?name-pattern(param-pattern)throws-pattern?)
  2. execution(<修饰符>? <返回类型> <声明类型>? <方法名><参数>) <异常>?)

? 表示可写可不写

在这里插入图片描述

切入点表达式中的通配符:
  • * : 匹配任何部分,但是只能表示一个单词
  • .. : 可用于全限定名中和方法参数中,分别表示 包以及子包 和 0到N个参数。

常见的写法:(对应表达式从后往前看)
execution(* cn.sunny.wms.service.*.*(..)) : 表示对service包下的所有类所有方法做增强
execution(* cn.sunny.wms.service.*Serice.*(..)) : 表示对service包下所有以Service为后缀的类的所有方法做增强
execution(* cn.sunny..service.*Service.*(..) : 表示对sunny包及其子包下的service包中的以Service为后缀的类的所有方法做增强

在这里插入图片描述

二、AOP开发

跳转到目录

1、导入依赖

跳转到目录
首先导入AOP织入–>Maven依赖

  1. <!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
  2. <dependency>
  3. <groupId>org.aspectj</groupId>
  4. <artifactId>aspectjweaver</artifactId>
  5. <version>1.9.4</version>
  6. </dependency>

2、配置AOP(XML方式)

跳转到目录
代码

  1. // domain
  2. public class Employee1 {
  3. }
  4. // ----------------------------------------------
  5. // dao包
  6. public interface EmployeeDao1 {
  7. void save(Employee1 emp);
  8. void update(Employee1 emp);
  9. }
  10. public class EmployeeDaoImpl1 implements EmployeeDao1 {
  11. public void save(Employee1 emp) {
  12. System.out.println("保存员工");
  13. }
  14. public void update(Employee1 emp) {
  15. System.out.println("修改员工信息");;
  16. }
  17. }
  18. // ----------------------------------------------
  19. // service包
  20. public interface EmployeeService1 {
  21. void save(Employee1 emp);
  22. void update(Employee1 emp);
  23. }
  24. public class EmployeeServiceImpl1 implements EmployeeService1 {
  25. private EmployeeDao1 dao1;
  26. public void setDao1(EmployeeDao1 dao1) {
  27. this.dao1 = dao1;
  28. }
  29. public void save(Employee1 emp) {
  30. dao1.save(emp);
  31. System.out.println("保存成功");
  32. }
  33. public void update(Employee1 emp) {
  34. dao1.update(emp);
  35. throw new RuntimeException("故意出错");
  36. }
  37. }
  38. // ----------------------------------------------
  39. // 事务管理器(模拟)
  40. public class TransactionManager2 {
  41. public void begin(){
  42. System.out.println("开启事务");
  43. }
  44. public void commit(){
  45. System.out.println("提交事务");
  46. }
  47. public void rollback(){
  48. System.out.println("回滚事务");
  49. }
  50. public void close(){
  51. System.out.println("释放资源");
  52. }
  53. }

xml文件

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <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 https://www.springframework.org/schema/aop/spring-aop.xsd">
  3. <bean id="employeeDao1" class="com.sunny._02_dynamic_proxy.dao.impl.EmployeeDaoImpl1"/>
  4. <bean id="employeeService1" class="com.sunny._02_dynamic_proxy.service.impl.EmployeeServiceImpl1">
  5. <property name="dao1" ref="employeeDao1"/>
  6. </bean>
  7. <!--AOP配置: 在什么地点 + 什么时机 + 做什么增强-->
  8. <!--1. WHAT: 做什么增强-->
  9. <bean id="transactionManager2" class="com.sunny._02_dynamic_proxy.tx.TransactionManager2"/>
  10. <aop:config > <!--proxy-target-class="false" 使用CGLIB的方式-->
  11. <!--配置一个AOP切面: ①在什么地点 + ②什么时机 + ③做什么增强-->
  12. <aop:aspect ref="transactionManager2"> <!--关联WHAT-->
  13. <!--2. WHERE: 在那些包中的哪些类中的哪些方法上做增强-->
  14. <aop:pointcut id="txPoint" expression="execution(* com.sunny._02_dynamic_proxy.service.*Service1.*(..))"/>
  15. <!--3. WHEN: 在方法执行的什么时机做增强-->
  16. <aop:before method="begin" pointcut-ref="txPoint"/>
  17. <aop:after-returning method="commit" pointcut-ref="txPoint"/> <!--业务方法执行完毕后-->
  18. <aop:after-throwing method="rollback" pointcut-ref="txPoint"/>
  19. <aop:after method="close" pointcut-ref="txPoint"/>
  20. <!--和上面完成的功能相同-->
  21. <!--<aop:around method="aroundMethod" pointcut-ref="txPoint"/>-->
  22. </aop:aspect>
  23. </aop:config>
  24. </beans>

测试类

  1. @RunWith(SpringJUnit4ClassRunner.class)
  2. @ContextConfiguration("classpath:applicationContext.xml")
  3. public class JdkDynamicProxyTest {
  4. // com.sun.proxy.$Proxy14
  5. @Autowired
  6. private EmployeeService1 service1;
  7. @Test
  8. public void testSave(){
  9. System.out.println(service1.getClass());
  10. service1.save(new Employee1());
  11. }
  12. @Test
  13. public void testUpdate(){
  14. service1.update(new Employee1());
  15. }
  16. }

在这里插入图片描述

3、各种时机的增强细节

跳转到目录

3.1、各种增强

增强的时机
在这里插入图片描述
根据增强的时机不同,化为多种增强
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3.2、增强的参数配置

在这里插入图片描述

代码

  1. // TransactionManager类
  2. public class TransactionManager1 {
  3. // 使用JoinPoint类获取被增强方法的信息
  4. // 必须作为增强方法的第一个参数
  5. public void begin(JoinPoint jp){
  6. System.out.println("代理对象:" + jp.getThis().getClass());
  7. System.out.println("目标对象:" + jp.getTarget().getClass());
  8. System.out.println("被增强方法的参数:" + Arrays.toString(jp.getArgs()));
  9. System.out.println("连接点方法签名:" + jp.getSignature());
  10. System.out.println("当前连接点的类型:" + jp.getKind());
  11. System.out.println("开启事务");
  12. }
  13. public void commit(JoinPoint jp){
  14. System.out.println("提交事务");
  15. }
  16. public void rollback(JoinPoint jp, Throwable exception){
  17. System.out.println("回滚事务: " + "异常信息:" + exception);
  18. }
  19. public void close(JoinPoint jp){
  20. System.out.println("释放资源");
  21. }
  22. public Object aroundMethod(ProceedingJoinPoint jpj){
  23. Object ret = null;
  24. System.out.println("开启事务");
  25. try {
  26. //System.out.println(".....执行真实对象中的方法");
  27. ret = jpj.proceed(); // 调用真实对象的方法
  28. System.out.println("提交事务");
  29. } catch (Throwable e){
  30. System.out.println("回滚事务:" + "异常信息:" + e.getMessage());
  31. } finally {
  32. System.out.println("释放资源");
  33. }
  34. return ret;
  35. }
  36. }

xml文件

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <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 https://www.springframework.org/schema/aop/spring-aop.xsd">
  3. <bean id="employeeDao1" class="com.sunny._02_dynamic_proxy.dao.impl.EmployeeDaoImpl1"/>
  4. <bean id="employeeService1" class="com.sunny._02_dynamic_proxy.service.impl.EmployeeServiceImpl1">
  5. <property name="dao1" ref="employeeDao1"/>
  6. </bean>
  7. <!--AOP配置: 在什么地点 + 什么时机 + 做什么增强-->
  8. <!--1. WHAT: 做什么增强-->
  9. <bean id="transactionManager1" class="com.sunny._02_dynamic_proxy.tx.TransactionManager1"/>
  10. <aop:config > <!--proxy-target-class="false" 使用CGLIB的方式-->
  11. <!--配置一个AOP切面: ①在什么地点 + ②什么时机 + ③做什么增强-->
  12. <aop:aspect ref="transactionManager1"> <!--关联WHAT-->
  13. <!--2. WHERE: 在那些包中的哪些类中的哪些方法上做增强-->
  14. <aop:pointcut id="txPoint" expression="execution(* com.sunny._02_dynamic_proxy.service.*Service1.*(..))"/>
  15. <!--3. WHEN: 在方法执行的什么时机做增强-->
  16. <!--<aop:before method="begin" pointcut-ref="txPoint"/> <aop:after-returning method="commit" pointcut-ref="txPoint"/> <!–业务方法执行完毕后–> <aop:after-throwing method="rollback" pointcut-ref="txPoint" throwing="exception"/> <aop:after method="close" pointcut-ref="txPoint"/>-->
  17. <!--和上面完成的功能相同-->
  18. <aop:around method="aroundMethod" pointcut-ref="txPoint"/>
  19. </aop:aspect>
  20. </aop:config>
  21. </beans>

4、注解配置AOP

跳转到目录

  1. // domain
  2. public class Employee1 {
  3. }
  4. // ----------------------------------------------
  5. // dao包
  6. public interface EmployeeDao1 {
  7. void save(Employee1 emp);
  8. void update(Employee1 emp);
  9. }
  10. @Repository
  11. public class EmployeeDaoImpl1 implements EmployeeDao1 {
  12. public void save(Employee1 emp) {
  13. System.out.println("保存员工");
  14. }
  15. public void update(Employee1 emp) {
  16. System.out.println("修改员工信息");;
  17. }
  18. }
  19. // ----------------------------------------------
  20. // service包
  21. public interface EmployeeService1 {
  22. void save(Employee1 emp);
  23. void update(Employee1 emp);
  24. }
  25. @Service
  26. public class EmployeeServiceImpl1 implements EmployeeService1 {
  27. @Autowired
  28. private EmployeeDao1 dao1;
  29. public void save(Employee1 emp) {
  30. dao1.save(emp);
  31. System.out.println("保存成功");
  32. }
  33. public void update(Employee1 emp) {
  34. dao1.update(emp);
  35. throw new RuntimeException("故意出错");
  36. }
  37. }
  38. // ----------------------------------------------
  39. // 事务管理器(模拟)
  40. @Component // IoC注解
  41. @Aspect // 配置一个切面
  42. public class TransactionManager1 {
  43. // 配置在哪些包中的哪些类中的哪些方法上做增强
  44. //XML: <aop:pointcut id="txPoint"expression="execution(* com.sunny.aop_annotation.service.*Service1.*(..))"/>
  45. @Pointcut("execution(* com.sunny._02_dynamic_proxy.service.*Service1.*(..))")
  46. public void txPoint(){
  47. }
  48. @Before("txPoint()")
  49. public void begin(JoinPoint jp){
  50. System.out.println("开启事务");
  51. }
  52. @AfterReturning("txPoint()") // 操作完成之后
  53. public void commit(){
  54. System.out.println("提交事务");
  55. }
  56. @AfterThrowing(value = "txPoint()", throwing = "exception")
  57. public void rollback(Throwable exception){
  58. System.out.println("回滚事务: " + "异常信息:" + exception);
  59. }
  60. @After("txPoint()")
  61. public void close(){
  62. System.out.println("释放资源");
  63. }
  64. //@Around("txPoint()") // 可以替代上面的几个注解
  65. public Object aroundMethod(ProceedingJoinPoint jpj){
  66. Object ret = null;
  67. System.out.println("开启事务");
  68. try {
  69. //System.out.println(".....执行真实对象中的方法");
  70. ret = jpj.proceed(); // 调用真实对象的方法
  71. System.out.println("提交事务");
  72. } catch (Throwable e){
  73. System.out.println("回滚事务:" + "异常信息:" + e.getMessage());
  74. } finally {
  75. System.out.println("释放资源");
  76. }
  77. return ret;
  78. }
  79. }

xml文件

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <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" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
  3. <!--配置DI注解解析器-->
  4. <context:annotation-config/>
  5. <!--配置IoC注解解析器-->
  6. <context:component-scan base-package="com.sunny._02_dynamic_proxy"/>
  7. <!--配置AOP注解解析器-->
  8. <aop:aspectj-autoproxy/> <!--默认就是jdk的动态代理-->
  9. <!--<aop:aspectj-autoproxy proxy-target-class="true"/>--> <!--使用的是cglib的动态代理-->
  10. </beans>

在这里插入图片描述

发表评论

表情:
评论列表 (有 0 条评论,88人围观)

还没有评论,来说两句吧...

相关阅读