[Spring+SpringMVC+Mybatis]框架学习笔记(四):Spring实现AOP
上一章:[Spring+SpringMVC+Mybatis]框架学习笔记(三):Spring实现JDBC
下一章:[Spring+SpringMVC+Mybatis]框架学习笔记(五):SpringAOP_顾问
第4章 Spring实现AOP
4.1 AOP的概念
AOP: Aspect Oriented Programming 面向切面编程
AOP的实现可以把业务逻辑和系统级的服务进行隔离,使业务逻辑跟各个系统级服务的耦合度降低,提高系统的重用性和开发效率。
业务逻辑:某个类的某个方法本身要实现的功能。
系统级的服务:系统的日志、事务、权限验证
举例:六七十年代,村支书要通知一个事情,原来要一家一家逐个告诉他们;有了广播(AOP)以后,只需要用广播,大家就知道了。
4.2 AOP的实现
AOP底层实现的原理:动态代理
动态代理有两种方式:
- jdk动态代理(只能代理实现了接口的类)
- cglib动态代理(都可以) ----> 字节码生成器
4.3 AOP的一些专业术语
- 切面(Aspect):交叉在各个业务逻辑中的系统服务,例如:安全验证、事务处理、日志记录等
- 织入(weaving):将切面代码插入到目标对象的某个方法的过程,相当于jdk动态代理中的InvacationHandler接口方法的内容。
- 连接点(JointPoint):理论上可以被切面织入的所有方法,例如addStudent(),delStudent()...通常所有方法都可以被称为连接点。
- 切入点(PointCut): 实际上被切面织入的方法。
- 目标对象(target):就是切入点所属的类,如:StudentService类
- 通知(Advice):就是切面的实现,切面织入的目标对象,方法,时间点(方式执行前、后、前后、异常)以及内容。
- 顾问(Advisor):就是通知的封装和延伸。可以将通知以更复杂的方式织入到某些方法中。
把前5个术语串联起来:
将切面织入到目标对象的连接点方法中,使连接点成为切入点。
4.4 Spring实现AOP的步骤
1)搭建SpringAOP开发环境需要引入的jar包;
aopalliance-1.0.jar
spring-aop-4.2.1.RELEASE.jar
2)实现通知
- 前置通知 implements org.springframework.aop.MethodBeforeAdvice
- 后置通知 implements org.springframework.aop.AfterReturningAdvice
- 环绕通知 implements org.aopalliance.intercept.MethodInterceptor
- 异常通知 implements org.springframework.aop.ThrowsAdvice
3)注册目标类
4)注册通知
5)注册代理生产器,并注入目标类和通知
ps:通知的注意点:
- 代理生产器配置时,目标类接口可以省略;
- 后置通知是在目标方法执行之后才执行,它可以得到目标方法的返回值,但是不能改变它;
- 环绕通知有在目标方法执行之前的代码,也有在目标方法执行之后的代码;可以得到目标方法的返回值,且可以改变它。
4.5 Spring实现AOP实例
4.5.1 目标类接口
package com.steven.spring.sysmgr.service;
import java.util.List;
import com.steven.spring.sysmgr.entity.Student;
public interface IStudentService {
public boolean addStudent(Student student);
public boolean delStudent(Integer studentId);
public boolean updateStudent(Student student);
public List<Student> getStudentList();
}
4.5.2 目标类
package com.steven.spring.sysmgr.service.impl;
import java.util.ArrayList;
import java.util.List;
import com.steven.spring.sysmgr.entity.Student;
import com.steven.spring.sysmgr.service.IStudentService;
public class StudentService implements IStudentService{
@Override
public boolean addStudent(Student student) {
System.out.println("执行增加功能");
return true;
}
@Override
public boolean delStudent(Integer studentId) {
//模拟异常,在异常通知中使用
int i = 1 / 0;
System.out.println("执行删除功能");
return true;
}
@Override
public boolean updateStudent(Student student) {
System.out.println("执行修改功能");
return true;
}
@Override
public List<Student> getStudentList() {
System.out.println("执行增加功能");
return new ArrayList<Student>();
}
}
4.5.3 实现通知
a) 前置通知
package com.steven.spring.sysmgr.advice;
import java.lang.reflect.Method;
import org.springframework.aop.MethodBeforeAdvice;
/**
* 前置通知
* @author chenyang
*
*/
public class MyBeforeAdvice implements MethodBeforeAdvice {
@Override
public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable {
// TODO Auto-generated method stub
System.out.println("这是前置通知,应该在方法执行之前打印出来");
}
}
b) 后置通知
package com.steven.spring.sysmgr.advice;
import java.lang.reflect.Method;
import org.springframework.aop.AfterReturningAdvice;
/**
* 后置通知
* @author chenyang
*
*/
public class MyAfterAdvice implements AfterReturningAdvice {
//该方法中的代码就是要织入到目标类方法的切面代码
@Override
public void afterReturning(Object returnValue, Method paraMethod,
Object[] paramArrayOfObject, Object target) throws Throwable {
System.out.println("方法执行的结果:" + returnValue);
System.out.println("这是后置通知,应该在方法执行之后打印出来");
}
}
c) 环绕通知
package com.steven.spring.sysmgr.advice;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
/**
* 环绕通知
* @author chenyang
*
*/
public class MyAroundAdvice implements MethodInterceptor {
// 环绕通知可以改变方法的返回值
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("这是环绕通知的前面执行部分");
Object result = invocation.proceed();
System.out.println("方法的执行结果是:" + result);
System.out.println("这是环绕通知的后面执行部分");
result = false;
return result;
}
}
d) 异常通知
package com.steven.spring.sysmgr.advice;
import org.springframework.aop.ThrowsAdvice;
/**
* 异常通知
* @author chenyang
*
*/
public class MyThrowingAdvice implements ThrowsAdvice {
public void afterThrowing(Exception e){
System.out.println("发生的异常:" + e);
}
}
4.5.4 配置文件:注册目标类、通知、代理生成器
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.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>
<!-- 注册前置通知的代理生成器,注入目标类接口、目标类、通知 -->
<bean id="myBeforeProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="studentService"/>
<property name="interfaces" value="com.steven.spring.sysmgr.service.IStudentService"/>
<property name="interceptorNames" value="beforeAdvice"/>
</bean>
<!-- 注册后置通知的代理生成器,注入目标类、通知 -->
<bean id="myAfterProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="studentService"/>
<!-- 这里省略了目标类接口的实现类,因为系统能自己找到 -->
<property name="interceptorNames" value="afterAdvice"/>
</bean>
<!-- 注册环绕通知的代理生成器,注入目标类、通知 -->
<bean id="myAroundProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="studentService"/>
<property name="interceptorNames" value="aroundAdvice"/>
</bean>
<!-- 注册异常通知的代理生成器,注入目标类、通知 -->
<bean id="myThrowingProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="studentService"/>
<property name="interceptorNames" value="throwingAdvice"/>
</bean>
</beans>
ps:
教你什么时候用value,什么时候用ref?
ref是引用(指针),value是布尔、string等得值。
用ref还是value,需要看源码中这个name是什么类型。 全选name的引号中的值,alt + / , 若弹出的类的参数是对象,就用ref;若不是,就用value。


4.5.5 测试
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 AdviceTest {
private ApplicationContext ac = null;
@Before
public void init(){
ac = new ClassPathXmlApplicationContext("applicationContext.xml");
}
//测试前置通知,预期目标:将前置通知打印的内容出现在目标方法内容的前面
@Test
public void testBeforeAdvice(){
IStudentService studentService = (IStudentService) ac.getBean("myBeforeProxy");
studentService.addStudent(new Student());
}
//测试后置通知
@Test
public void testAfterAdvice(){
IStudentService studentService = (IStudentService) ac.getBean("myAfterProxy");
studentService.addStudent(new Student());
}
//测试环绕通知
@Test
public void testAroundAdvice(){
IStudentService studentService = (IStudentService) ac.getBean("myAroundProxy");
studentService.addStudent(new Student());
}
//测试异常通知
@Test
public void testThrowingAdvice(){
IStudentService studentService = (IStudentService) ac.getBean("myThrowingProxy");
studentService.delStudent(1);
}
}
上一章:[Spring+SpringMVC+Mybatis]框架学习笔记(三):Spring实现JDBC
下一章:[Spring+SpringMVC+Mybatis]框架学习笔记(五):SpringAOP_顾问
[Spring+SpringMVC+Mybatis]框架学习笔记(四):Spring实现AOP的更多相关文章
- [Spring+SpringMVC+Mybatis]框架学习笔记(六):事务
第7讲 事务 7.1 事务的概念 事务是一系列作为一个逻辑单元来执行的操作集合. 它是数据库维护数据一致性的单位,它讲数据库从一个一致状态,转变为新的另外一个一致状态.说的简单一点就是:如果一组处理步 ...
- 用IntelliJ IDEA 开发Spring+SpringMVC+Mybatis框架 分步搭建四:配置springmvc
在用IntelliJ IDEA 开发Spring+SpringMVC+Mybatis框架 分步搭建三:配置spring并测试的基础上 继续进行springmvc的配置 一:配置完善web.xml文件
- Spring+SpringMVC+MyBatis集成学习笔记【一】
一,首先要清楚,SpringMVC其实就是Spring的一个组件 例如我们知道Spring中有类似于,AOP TX等等类似的组件,所以SpringMVC其实就是Spring的一个组件,是S ...
- 搭建Spring + SpringMVC + Mybatis框架之三(整合Spring、Mybatis和Spring MVC)
整合Spring和SpringMVC 之前已经整合了spring和mybatis,现在在此基础上整合SSM. 项目目录: 思路:SpringMVC的配置文件独立,然后在web.xml中配置整合. (1 ...
- 用IntelliJ IDEA 开发Spring+SpringMVC+Mybatis框架 分步搭建三:配置spring并测试
这一部分的主要目的是 配置spring-service.xml 也就是配置spring 并测试service层 是否配置成功 用IntelliJ IDEA 开发Spring+SpringMVC+M ...
- Spring+SpringMVC+MyBatis深入学习及搭建(四)——MyBatis输入映射与输出映射
转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/6878529.html 前面有讲到Spring+SpringMVC+MyBatis深入学习及搭建(三)——My ...
- Spring+SpringMVC+MyBatis深入学习及搭建(十四)——SpringMVC和MyBatis整合
转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/7010363.html 前面讲到:Spring+SpringMVC+MyBatis深入学习及搭建(十三)--S ...
- Spring+SpringMvc+Mybatis框架集成搭建教程
一.背景 最近有很多同学由于没有过SSM(Spring+SpringMvc+Mybatis , 以下简称SSM)框架的搭建的经历,所以在自己搭建SSM框架集成的时候,出现了这样或者那样的问题,很是苦恼 ...
- Spring+SpringMVC+MyBatis深入学习及搭建(二)——MyBatis原始Dao开发和mapper代理开发
转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/6869133.html 前面有写到Spring+SpringMVC+MyBatis深入学习及搭建(一)——My ...
- Spring+SpringMVC+MyBatis深入学习及搭建(三)——MyBatis全局配置文件解析
转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/6874672.html 前面有写到Spring+SpringMVC+MyBatis深入学习及搭建(二)——My ...
随机推荐
- Java学习笔记09
1. 多态 1.1 多态 多态是指同一种行为具有多种不同的表现形式. 前提 有继承或者实现关系 有方法重写(没有重写多态就没有意义) 父类引用指向子类对象 格式 父类类型 变量名 = new 子类 ...
- 使用Go语言操作HDFS
HDFS(Hadoop分布式文件系统)是Hadoop生态系统的一部分,它是一个可扩展的分布式文件系统,被设计用于在大规模数据集上运行的应用程序 安装相关package: $ go get github ...
- java中的装箱 拆箱 以及 字符串与基本数据类型的转化
java中的装箱 拆箱 装箱就是 自动将基本数据类型转换为包装器类型:拆箱就是 自动将包装器类型转换为基本数据类型 ; Integer i =5;//装箱 int j=i;//拆箱 在装箱的时候自动调 ...
- LLM(大语言模型)解码时是怎么生成文本的?
Part1配置及参数 transformers==4.28.1 源码地址:transformers/configuration_utils.py at v4.28.1 · huggingface/tr ...
- chatgpt接口开发笔记1:completions接口
chatgpt接口开发笔记1:completions接口 个人博客地址: https://note.raokun.top 拥抱ChatGPT,国内访问网站:https://www.playchat.t ...
- 笔记:linux必备网络基础概念和以太网技术基础
笔记:linux必备网络基础概念和以太网技术基础 由于后面可能需要对交换机进行一些配置,所以也是临时学习一下iptables的相关配置,以及一些基本的网络知识,下面就是我看到一些资料做的一些总结,希望 ...
- Linux期末佛脚指南
Linux的期末佛脚复习 常用文件操作命令 touch (创建文件) cat (查看文件内容) head (查看文件开头) tail (查看文件结尾) cp (复制文件) mv (移动文件) ls ( ...
- 2020-10-28:go中,好几个go程,其中一个go程panic,会产生什么问题?
福哥答案2020-10-28: 1.运行时恐慌,当panic被抛出异常后,如果我们没有在程序中添加任何保护措施的话,程序就会打印出panic的详细情况之后,终止运行.2.有panic的子协程里的def ...
- 2021-01-06:mysql中,我存十亿个手机号码,考虑存储空间和查询效率,用什么类型的字段去存?
福哥答案2021-01-06: [答案来自此链接:](https://www.zhihu.com/question/438078173)首先提出假设:考虑一下这几个问题:手机号码都是数字吗?都是中国的 ...
- 2022-04-19:A*算法, 过程和Dijskra高度相处, 有到终点的预估函数, 只要预估值<=客观上最优距离,就是对的。 预估函数是一种吸引力: 1)合适的吸引力可以提升算法的速度; 2)吸引
2022-04-19:A*算法, 过程和Dijskra高度相处, 有到终点的预估函数, 只要预估值<=客观上最优距离,就是对的. 预估函数是一种吸引力: 1)合适的吸引力可以提升算法的速度; 2 ...