【博学谷学习记录】超强总结,用心分享|Java基础分享-Spring AOP(补充)

目录

1、基于 PointcutAdvisor 的 AOP 开发

2、自动代理

 

 

1、基于 PointcutAdvisor 的 AOP 开发

PointCutAdvisor 是 Adivsor 接口的子接口,用来表示带切点的切面。使用它,我们可以通过包名、类名、方法名等信息更加灵活的定义切面中的切入点,提供更具有适用性的切面。

Spring 提供了多个 PointCutAdvisor 的实现,其中常用实现类如如下。
  • NameMatchMethodPointcutAdvisor:指定 Advice 所要应用到的目标方法名称,例如 hello* 代表所有以 hello 开头的所有方法。
  • RegExpMethodPointcutAdvisor:使用正则表达式来定义切点(PointCut),RegExpMethodPointcutAdvisor 包含一个 pattern 属性,该属性使用正则表达式描述需要拦截的方法。

示例 

下面我们就通过一个简单的实例,演示下切点切面的 AOP 开发。

1.1. 在 my-spring-aop-demo 的 net.biacheng.c.dao 包下,创建一个名为 OrderDao,代码如下。
  1. package net.biancheng.c.dao;
  2. public class OrderDao {
  3. public void add() {
  4. System.out.println("正在执行 UserDao 的 add() 方法……");
  5. }
  6. public void adds() {
  7. System.out.println("正在执行 UserDao 的 adds() 方法……");
  8. }
  9. public void delete() {
  10. System.out.println("正在执行 UserDao 的 delete() 方法……");
  11. }
  12. public void modify() {
  13. System.out.println("正在执行 UserDao 的 modify() 方法……");
  14. }
  15. public void get() {
  16. System.out.println("正在执行 UserDao 的 get() 方法……");
  17. }
  18. }

1.2. 在 net.biancheng.c.advice 包下,创建一个名为 OrderDaoAroundAdvice 的环绕增强类,代码如下。
  1. package net.biancheng.c.advice;
  2. import org.aopalliance.intercept.MethodInterceptor;
  3. import org.aopalliance.intercept.MethodInvocation;
  4. /**
  5. * 增强代码
  6. * 环绕增强
  7. *
  8. * @author c语言中文网 c.biancheng.net
  9. */
  10. public class OrderDaoAroundAdvice implements MethodInterceptor {
  11. @Override
  12. public Object invoke(MethodInvocation methodInvocation) throws Throwable {
  13. System.out.println("环绕增强前********");
  14. //执行被代理对象中的逻辑
  15. Object result = methodInvocation.proceed();
  16. System.out.println("环绕增强后********");
  17. return result;
  18. }
  19. }

1.3. 在 Beans.xml 中添加以下配置。
  1. <!--带切点的切面-->
  2. <!-- 定义目标(target)对象 -->
  3. <bean id="orderDao" class="net.biancheng.c.dao.OrderDao"></bean>
  4. <!-- 定义增强 -->
  5. <bean id="aroundAdvice" class="net.biancheng.c.advice.OrderDaoAroundAdvice"></bean>
  6. <!--定义切面-->
  7. <bean id="myPointCutAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
  8. <!--定义表达式,规定哪些方法进行拦截 .* 表示所有方法-->
  9. <!--<property name="pattern" value=".*"></property>-->
  10. <property name="patterns" value="net.biancheng.c.dao.OrderDao.add.*,net.biancheng.c.dao.OrderDao.delete.*"></property>
  11. <property name="advice" ref="aroundAdvice"></property>
  12. </bean>
  13. <!--Spring 通过配置生成代理-->
  14. <bean id="orderDaoProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
  15. <!-- 配置目标 -->
  16. <property name="target" ref="orderDao"></property>
  17. <!-- 针对类的代理,该属性默认取值为 false(可省略), 表示使用 JDK 动态代理;取值为 true,表示使用 CGlib 动态代理-->
  18. <property name="proxyTargetClass" value="true"></property>
  19. <!-- 在目标上应用增强 -->
  20. <property name="interceptorNames" value="myPointCutAdvisor"></property>
  21. </bean>

1.4. 修改 MainApp 类 main 方法的代码。
  1. package net.biancheng.c;
  2. import net.biancheng.c.dao.OrderDao;
  3. import org.springframework.context.ApplicationContext;
  4. import org.springframework.context.support.ClassPathXmlApplicationContext;
  5. public class MainApp {
  6. public static void main(String[] args) {
  7. //获取 ApplicationContext 容器
  8. ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
  9. //获取代理对象
  10. OrderDao orderDao = context.getBean("orderDaoProxy", OrderDao.class);
  11. //调用 OrderDao 中的各个方法
  12. orderDao.add();
  13. orderDao.adds();
  14. orderDao.delete();
  15. orderDao.get();
  16. orderDao.modify();
  17. }
  18. }

1.5. 执行 MainApp 中的 main() 方法,控制台输出如下。
环绕增强前********
正在执行 OrderDao 的 add() 方法……
环绕增强后********
环绕增强前********
正在执行 OrderDao 的 adds() 方法……
环绕增强后********
环绕增强前********
正在执行 OrderDao 的 delete() 方法……
环绕增强后********
正在执行 OrderDao 的 get() 方法……
正在执行 OrderDao 的 modify() 方法……

2、自动代理

在前面的案例中,所有目标对象(Target Bean)的代理对象(Proxy Bean)都是在 XML 配置中通过 ProxyFactoryBean 创建的。但在实际开发中,一个项目中往往包含非常多的 Bean, 如果每个 Bean 都通过 ProxyFactoryBean 创建,那么开发和维护成本会十分巨大。为了解决这个问题,Spring 为我们提供了自动代理机制。

Spring 提供的自动代理方案,都是基于后处理 Bean 实现的,即在 Bean 创建的过程中完成增强,并将目标对象替换为自动生成的代理对象。通过 Spring 的自动代理,我们在程序中直接拿到的 Bean 就已经是 Spring 自动生成的代理对象了。

Spring 为我们提供了 3 种自动代理方案:
  • BeanNameAutoProxyCreator:根据 Bean 名称创建代理对象。
  • DefaultAdvisorAutoProxyCreator:根据 Advisor 本身包含信息创建代理对象。
  • AnnotationAwareAspectJAutoProxyCreator:基于 Bean 中的 AspectJ 注解进行自动代理对象。

本节我们就通过两个简单的实例,对 BeanNameAutoProxyCreator 和 DefaultAdvisorAutoProxyCreator 进行演示,至于 AnnotationAwareAspectJAutoProxyCreator,我们会在后续的教程中进行讲解。

根据 Bean 名称创建代理对象

2.1. 在 my-spring-aop-demo 工程的 src 目录下,创建一个名为 Beans2.xml 的配置文件,配置内容如下。
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xmlns:context="http://www.springframework.org/schema/context"
  5. xsi:schemaLocation="http://www.springframework.org/schema/beans
  6. http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
  7. http://www.springframework.org/schema/context
  8. http://www.springframework.org/schema/context/spring-context.xsd">
  9. <!-- 定义目标(target)对象 -->
  10. <bean id="userDao" class="net.biancheng.c.dao.impl.UserDaoImpl"></bean>
  11. <bean id="orderDao" class="net.biancheng.c.dao.OrderDao"></bean>
  12. <!-- 定义增强 -->
  13. <bean id="beforeAdvice" class="net.biancheng.c.advice.UserDaoBeforeAdvice"></bean>
  14. <bean id="aroundAdvice" class="net.biancheng.c.advice.OrderDaoAroundAdvice"></bean>
  15. <!--Spring 自动代理:根据 Bean 名称创建代理独享-->
  16. <bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
  17. <property name="beanNames" value="*Dao"></property>
  18. <property name="interceptorNames" value="beforeAdvice,aroundAdvice"></property>
  19. </bean>
  20. </beans>

2.2. 修改 MainApp 中 main 方法,代码如下。
  1. package net.biancheng.c;
  2. import net.biancheng.c.dao.OrderDao;
  3. import net.biancheng.c.dao.UserDao;
  4. import org.springframework.beans.factory.annotation.Autowired;
  5. import org.springframework.context.ApplicationContext;
  6. import org.springframework.context.support.ClassPathXmlApplicationContext;
  7. public class MainApp {
  8. public static void main(String[] args) {
  9. //获取 ApplicationContext 容器
  10. ApplicationContext context = new ClassPathXmlApplicationContext("Beans2.xml");
  11. //获取代理对象
  12. UserDao userDao = context.getBean("userDao", UserDao.class);
  13. //获取代理对象
  14. OrderDao orderDao = context.getBean("orderDao", OrderDao.class);
  15. //调用 UserDao 中的各个方法
  16. userDao.add();
  17. userDao.delete();
  18. userDao.modify();
  19. userDao.get();
  20. //调用 OrderDao 中的各个方法
  21. orderDao.add();
  22. orderDao.adds();
  23. orderDao.delete();
  24. orderDao.get();
  25. orderDao.modify();
  26. }
  27. }

2.3. 执行 MainApp 中的 main() 方法,控制台输出如下。
正在执行前置增强操作…………
环绕增强前********
正在执行 UserDao 的 add() 方法……
环绕增强后********
正在执行前置增强操作…………
环绕增强前********
正在执行 UserDao 的 delete() 方法……
环绕增强后********
正在执行前置增强操作…………
环绕增强前********
正在执行 UserDao 的 modify() 方法……
环绕增强后********
正在执行前置增强操作…………
环绕增强前********
正在执行 UserDao 的 get() 方法……
环绕增强后********
正在执行前置增强操作…………
环绕增强前********
正在执行 OrderDao 的 add() 方法……
环绕增强后********
正在执行前置增强操作…………
环绕增强前********
正在执行 OrderDao 的 adds() 方法……
环绕增强后********
正在执行前置增强操作…………
环绕增强前********
正在执行 OrderDao 的 delete() 方法……
环绕增强后********
正在执行前置增强操作…………
环绕增强前********
正在执行 OrderDao 的 get() 方法……
环绕增强后********
正在执行前置增强操作…………
环绕增强前********
正在执行 OrderDao 的 modify() 方法……
环绕增强后********

根据切面中信息创建代理对象

1. 修改 Beans2.xml 中的配置,配置内容如下。
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xmlns:context="http://www.springframework.org/schema/context"
  5. xsi:schemaLocation="http://www.springframework.org/schema/beans
  6. http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
  7. http://www.springframework.org/schema/context
  8. http://www.springframework.org/schema/context/spring-context.xsd">
  9. <!-- 定义目标(target)对象 -->
  10. <bean id="userDao" class="net.biancheng.c.dao.impl.UserDaoImpl"></bean>
  11. <bean id="orderDao" class="net.biancheng.c.dao.OrderDao"></bean>
  12. <!-- 定义增强 -->
  13. <bean id="beforeAdvice" class="net.biancheng.c.advice.UserDaoBeforeAdvice"></bean>
  14. <bean id="aroundAdvice" class="net.biancheng.c.advice.OrderDaoAroundAdvice"></bean>
  15. <!--定义切面-->
  16. <bean id="myPointCutAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
  17. <!--定义表达式,规定哪些方法进行拦截 .* 表示所有方法-->
  18. <!--<property name="pattern" value=".*"></property>-->
  19. <property name="patterns"
  20. value="net.biancheng.c.dao.OrderDao.add.*,net.biancheng.c.dao.OrderDao.delete.*"></property>
  21. <property name="advice" ref="aroundAdvice"></property>
  22. </bean>
  23. <!--Spring 自动代理:根据切面 myPointCutAdvisor 中信息创建代理对象-->
  24. <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"></bean>
  25. </beans>

2. 执行 MainApp 中的 main() 方法,控制台输出如下。
正在执行 UserDao 的 add() 方法……
正在执行 UserDao 的 delete() 方法……
正在执行 UserDao 的 modify() 方法……
正在执行 UserDao 的 get() 方法……
环绕增强前********
正在执行 OrderDao 的 add() 方法……
环绕增强后********
环绕增强前********
正在执行 OrderDao 的 adds() 方法……
环绕增强后********
环绕增强前********
正在执行 OrderDao 的 delete() 方法……
环绕增强后********
正在执行 OrderDao 的 get() 方法……
正在执行 OrderDao 的 modify() 方法……
posted @   后来--  阅读(27)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
点击右上角即可分享
微信分享提示