上一章:[Spring+SpringMVC+Mybatis]框架学习笔记(四):Spring实现AOP

下一章:[Spring+SpringMVC+Mybatis]框架学习笔记(六):Spring_AspectJ实现AOP

第5章 SpringAOP_顾问

对第4章Spring实现AOP的缺点的思考:

  • 一个代理只能代理一个bean,意味着在实际应用中要定义多个代理;(通过默认advisor自动代理生成器来解决)
  • 从容器中获取对象是通过代理的bean的id,而不是我们在容器中定义的目标对象的id;(通过默认advisor自动代理生成器来解决)
  • 通知只能切入到目标类的所有的方法,不能指定某些方法。(通过顾问对通知的封装实现)

5.1 顾问Advisor

它将通知进行了包装,根据通知的不同类型,在不同的时间点,将切面织入到指定的目标对象的某些连接点。

PointCutAdvisor 顾问的一种,它是一个接口,有两个实现类:

  • NameMatchMethodPointCutAdvisor 名称匹配方法切入点顾问
  • RegexpMethodPointCutAdvisor 正则表达式方法切入点顾问

复习正则表达式:

(*) 星号:匹配前面的子表达式任意次 例如:ao* 能匹配 a ao aoo aooooo

(+) 加号:匹配前面的子表达式一次或多次 例如:ao+ 能匹配 ao aoo aooooo

(.) 点 :匹配任意字符 除“\r\n”之外

.* 代表任意的一个字符串 .*add.* 代表包含add字符的任意字符串

实例:

利用实例4.5的目标类接口、目标类、通知,实现切入到目标类的指定的方法。

1)配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- 注册服务类,并描述依赖关系 -->
<bean id="studentService" class="com.steven.spring.sysmgr.service.impl.StudentService"></bean> <!-- 注册前置通知 -->
<bean id="beforeAdvice" class="com.steven.spring.sysmgr.advice.MyBeforeAdvice"></bean> <!-- 注册后置通知 -->
<bean id="afterAdvice" class="com.steven.spring.sysmgr.advice.MyAfterAdvice"></bean> <!-- 注册环绕通知 -->
<bean id="aroundAdvice" class="com.steven.spring.sysmgr.advice.MyAroundAdvice"></bean> <!-- 注册异常通知 -->
<bean id="throwingAdvice" class="com.steven.spring.sysmgr.advice.MyThrowingAdvice"></bean> <!-- 注册一个名称匹配方法切入点顾问 -->
<!-- 顾问Advisor比通知Advice多了一个指定方法的步骤 -->
<bean id="beforeAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
<property name="advice" ref="beforeAdvice"/>
<!-- 限定单个目标方法 -->
<property name="mappedName" value="addStudent"/>
<!-- 限定多个目标方法 -->
<!-- 方法1 -->
<!-- <property name="mappedNames" value="addStudent,updateStudent"/> -->
<!-- 方法2 -->
<!-- <property name="mappedNames">
<array>
<value>addStudent</value>
<value>updateStudent</value>
</array>
</property> -->
<!-- 方法3 -->
<!-- <property name="mappedNames" value="*Student"/> --> </bean> <!-- 注册前置顾问代理生成器 -->
<bean id="myBeforeAdvisorProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="studentService"/>
<property name="interceptorNames" value="beforeAdvisor"/>
</bean> <!-- 注册一个正则表达式方法切入点顾问 -->
<bean id="afterAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<property name="advice" ref="afterAdvice"/>
<!--限定单种方法-->
<property name="pattern" value=".*add.*"/>
<!-- 限定多种 -->
<property name="patterns" value=".*add.*,.*del.*"/>
</bean> <!-- 注册后置顾问代理生成器 -->
<bean id="myAfterAdvisorProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="studentService"/>
<property name="interceptorNames" value="afterAdvisor"/>
</bean> </beans>

2)测试

package com.steven.spring.sysmgr.test;

import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; import com.steven.spring.sysmgr.entity.Student;
import com.steven.spring.sysmgr.service.IStudentService; /**
* 测试顾问
* @author chenyang
*
*/
public class AdvisorTest {
private ApplicationContext ac = null; @Before
public void init(){
ac = new ClassPathXmlApplicationContext("applicationContext.xml");
} //测试前置顾问,指定某些方法,使用名称匹配切入点方法顾问来实现
@Test
public void testBeforeAdvisor(){
IStudentService studentService = (IStudentService) ac.getBean("myBeforeAdvisorProxy");
studentService.addStudent(new Student());
studentService.updateStudent(new Student());//修改功能的前置通知不能被打印
} //测试后置顾问,指定某些方法,使用正则表达式切入点方法顾问来实现
@Test
public void testAfterAdvisor(){
IStudentService studentService = (IStudentService)ac.getBean("myAfterAdvisorProxy");
studentService.addStudent(new Student());
studentService.delStudent(1);
studentService.updateStudent(new Student());
} }

5.2 自动代理生成器

Spring提供了自动代理生成器来解决要定义多个代理生成器的问题,有两种方式:

  • 默认advisor自动代理生成器(目标对象为配置文件中配置的所有的目标对象bean,而且为配置文件里面所有的advisor自动生成代理); ---> 笼统
  • bean名称自动代理生成器(可以指定某些目标对象(bean),而且可以指定某些切面的实现(advise/advisor)) 。 ---> 精确

总结:

第4-5章中各种技术的运用,无非是为了一个目标:将我们编写的切面的实现(通知/顾问)织入到某些类的某些方法中。

实例:

利用实例4.5的目标类接口、目标类、通知,实现切入到目标类的指定的方法。

1)配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- 注册服务类,并描述依赖关系 -->
<bean id="studentService" class="com.steven.spring.sysmgr.service.impl.StudentService"></bean> <!-- 注册前置通知 -->
<bean id="beforeAdvice" class="com.steven.spring.sysmgr.advice.MyBeforeAdvice"></bean> <!-- 注册后置通知 -->
<bean id="afterAdvice" class="com.steven.spring.sysmgr.advice.MyAfterAdvice"></bean> <!-- 注册环绕通知 -->
<bean id="aroundAdvice" class="com.steven.spring.sysmgr.advice.MyAroundAdvice"></bean> <!-- 注册异常通知 -->
<bean id="throwingAdvice" class="com.steven.spring.sysmgr.advice.MyThrowingAdvice"></bean> <!-- 注册一个名称匹配方法切入点顾问 -->
<!-- 顾问Advisor比通知Advice多了一个指定方法的步骤 -->
<bean id="beforeAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
<property name="advice" ref="beforeAdvice"/>
<property name="mappedName" value="addStudent"/>
</bean> <!-- 注册一个正则表达式方法切入点顾问 -->
<bean id="afterAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<property name="advice" ref="afterAdvice"/>
<property name="pattern" value=".*add.*"/>
</bean> <!-- 默认Advisor自动代理生成器,目标对象为配置文件中注册的所有的目标对象,advisor为配置文件中所有的advisor -->
<!-- <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"></bean> --> <!-- bean名称自动代理生成器,不仅可以指定目标对象,还可以指定advise/advisor(注意:这里都可以!) -->
<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="beanNames" value="studentService"/>
<property name="interceptorNames" value="beforeAdvisor"/>
</bean> </beans>

2)测试默认Advisor自动代理生成器

package com.steven.spring.sysmgr.test;

import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; import com.steven.spring.sysmgr.entity.Student;
import com.steven.spring.sysmgr.service.IStudentService; public class DefaultAdvisorAutoProxyCreator {
private ApplicationContext ac = null; @Before
public void init(){
ac = new ClassPathXmlApplicationContext("applicationContextForAutoProxy.xml");
} //测试默认顾问自动代理生成器
@Test
public void testDefaultAdvisorAutoProxyCreator(){
// 注意:这里是直接取容器中定义的目标对象的id,不再使用代理生成器的id
IStudentService studentService = (IStudentService) ac.getBean("studentService");
studentService.addStudent(new Student());
studentService.updateStudent(new Student());//修改功能的前置通知不能被打印
}
}

3)测试bean名称自动代理生成器

package com.steven.spring.sysmgr.test;

import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; import com.steven.spring.sysmgr.entity.Student;
import com.steven.spring.sysmgr.service.IStudentService; public class BeanNameAutoProxyCreator {
private ApplicationContext ac = null; @Before
public void init(){
ac = new ClassPathXmlApplicationContext("applicationContextForAutoProxy.xml");
} //测试bean名称自动代理生成器
@Test
public void testBeanNameAutoProxyCreator(){
IStudentService studentService = (IStudentService) ac.getBean("studentService");
studentService.addStudent(new Student());
studentService.updateStudent(new Student());
}
}

上一章:[Spring+SpringMVC+Mybatis]框架学习笔记(四):Spring实现AOP

下一章:[Spring+SpringMVC+Mybatis]框架学习笔记(六):Spring_AspectJ实现AOP

[Spring+SpringMVC+Mybatis]框架学习笔记(五):SpringAOP_顾问的更多相关文章

  1. [Spring+SpringMVC+Mybatis]框架学习笔记(六):事务

    第7讲 事务 7.1 事务的概念 事务是一系列作为一个逻辑单元来执行的操作集合. 它是数据库维护数据一致性的单位,它讲数据库从一个一致状态,转变为新的另外一个一致状态.说的简单一点就是:如果一组处理步 ...

  2. Spring+SpringMVC+MyBatis集成学习笔记【一】

    一,首先要清楚,SpringMVC其实就是Spring的一个组件       例如我们知道Spring中有类似于,AOP TX等等类似的组件,所以SpringMVC其实就是Spring的一个组件,是S ...

  3. Spring+SpringMVC+MyBatis深入学习及搭建(五)——动态sql

    转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/6908763.html 前面有讲到Spring+SpringMVC+MyBatis深入学习及搭建(四)——My ...

  4. Spring+SpringMVC+MyBatis深入学习及搭建(十五)——SpringMVC注解开发(基础篇)

    转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/7065294.html 前面讲到:Spring+SpringMVC+MyBatis深入学习及搭建(十四)--S ...

  5. Spring+SpringMVC+MyBatis深入学习及搭建(十六)——SpringMVC注解开发(高级篇)

    转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/7085268.html 前面讲到:Spring+SpringMVC+MyBatis深入学习及搭建(十五)——S ...

  6. Spring+SpringMvc+Mybatis框架集成搭建教程

    一.背景 最近有很多同学由于没有过SSM(Spring+SpringMvc+Mybatis , 以下简称SSM)框架的搭建的经历,所以在自己搭建SSM框架集成的时候,出现了这样或者那样的问题,很是苦恼 ...

  7. Spring+SpringMVC+MyBatis深入学习及搭建(二)——MyBatis原始Dao开发和mapper代理开发

    转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/6869133.html 前面有写到Spring+SpringMVC+MyBatis深入学习及搭建(一)——My ...

  8. Spring+SpringMVC+MyBatis深入学习及搭建(三)——MyBatis全局配置文件解析

    转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/6874672.html 前面有写到Spring+SpringMVC+MyBatis深入学习及搭建(二)——My ...

  9. Spring+SpringMVC+MyBatis深入学习及搭建(六)——MyBatis关联查询

    转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/6923464.html 前面有将到:Spring+SpringMVC+MyBatis深入学习及搭建(五)--动 ...

  10. Spring+SpringMVC+MyBatis深入学习及搭建(八)——MyBatis查询缓存

    转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/6956206.html 前面讲到:Spring+SpringMVC+MyBatis深入学习及搭建(七)——My ...

随机推荐

  1. 2023 年十大 API 管理趋势

    本文探讨了 API 管理在数字化转型中的重要性,以及 API 管理面临的挑战和发展机遇.文章重点介绍了十大 API 管理发展趋势,包括 API 安全性.API 标准化.云端 API 管理解决方案.低代 ...

  2. 在 plist 中轻松转换两种格式

      在 plist 中,有两种常见的格式:.plist 和 .plistx.这两种格式有什么区别?它们之间如何相互转换?本文将为您详细解答. 在 iOS 上架时,需要将 plist 文件上传到苹果的 ...

  3. 数据库mysql8.0安装+Navicat12

    第一次写博客,准备坚持下去把每天学习到的东西记录下来,刚好安装mysql8.0过程中遇到了一些问题并解决,系统win10.致敬博客 首先先粘贴一段mysql的百度百科词条:MySQL是一个关系型数据库 ...

  4. vue中点击其他任意位置关闭弹框

    mounted() { //点击任意位置关闭区域弹窗 document.addEventListener('click', (e) => { //获取弹窗对象 const userCon = d ...

  5. 2021-02-21:手写代码:高性能路由,也就是一个字符串和多个匹配串进行模糊匹配。一个数组arr里是["*a*","moonfdd"],字符串"moonfdd"能匹配到,理由是arr里有。字符串"xayy"也能匹配到,理由是arr里的"*a*",第1个星对应"x",第2个星对应"yy"。

    2021-02-21:手写代码:高性能路由,也就是一个字符串和多个匹配串进行模糊匹配.一个数组arr里是["a","moonfdd"],字符串"moo ...

  6. 【GiraKoo】C++多线程消息分发架构

    [开源需求]C++多线程消息分发架构 项目[gi_messager] 在多线程环境中,为每个线程提供独立的消息队列 MessageLoop.注:主线程默认自动创建消息队列. MessageLoopCe ...

  7. Docker安装Airflow

    环境 系统:Ubuntu 22.04.2 LTS docker Version:20.10.21 docker-compose version 1.29.2, python3 --version Py ...

  8. 自定义组件模拟v-model

    在项目中常常会遇到一个组件中引入好几个子组件的情况,而引入的子组件和子组件之间又需要有数据交互,如果使用父组件作为桥梁进行数据交互这个也是可以的,只是有些麻烦,so最理想的是子组件和子组件自己去交互, ...

  9. 【RocketMQ】NameServer总结

    NameServer是一个注册中心,提供服务注册和服务发现的功能.NameServer可以集群部署,集群中每个节点都是对等的关系(没有像ZooKeeper那样在集群中选举出一个Master节点),节点 ...

  10. 代码随想录算法训练营Day31 贪心算法| 122.买卖股票的最佳时机II 55. 跳跃游戏 45.跳跃游戏II

    代码随想录算法训练营 122.买卖股票的最佳时机II 题目链接:122.买卖股票的最佳时机II 给定一个数组,它的第 i个元素是一支给定股票第 i 天的价格. 设计一个算法来计算你所能获取的最大利润. ...