三、spring的AOP
AOP的基本认识
Aspect Oriented Programming,面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术
利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率
AOP的实现原理
Spring内部是使用动态代理的方式实现AOP
- JDK动态代理:只能对实现接口的类产生代理
- 产生代理对象的方法:Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
- Class<?>[] interfaces用来指明生成哪个对象的代理对象,通过接口指定,所以JDK动态代理只能对实现接口的类适用
- Cglib动态代理:可以对没有实现接口的类产生代理
- 继承这个类,生成该类的子类对象
- 所以这个类不能是final修饰的(无法继承)
- Spring实现AOP时,如果这个类实现了接口,默认使用JDK动态代理;如果这个类没实现接口,就使用Cglib产生代理
AOP的核心概念
- 横切关注点:对哪些方法进行拦截,拦截后怎么处理,这些关注点称之为横切关注点
- joinpoint:连接点,可以被拦截的点
- Spring中只支持方法类型的连接点,所以在Spring中连接点指的就是可以被拦截到的方法
- pointcut:切入点,对连接点进行拦截的定义,也就是真正被拦截的点
- 前置通知
- 后置通知
- 环绕通知
- 异常通知
- 最终通知
- introduction:引介,指的是类层面的增强 (用的比较少)
- 在不修改代码的前提下,引介可以在运行期为类动态地添加一些方法或属性
- target:目标对象,需要被代理的那个类,也就是需要被增强的那个类
- proxy:代理对象,就是目标类被增强了之后就产生了一个结果代理对象
- weave:织入,将通知(advice)应用到目标对象(target)并导致代理对象创建的过程
- aspect:切面,是对横切关注点的抽象,其实就是切入点和通知的组合
advice:方法层面的增强(也叫通知),就是指拦截到连接点之后要执行的代码
AOP的简单使用
Spring有两套AOP开发的方式,一套是传统的Spring的AOP开发方式,十分繁琐,现在已经被弃用;目前Spring进行AOP开发使用的都是基于AspectJ的方式
XML方式
简单实现
- 导入相应jar,除spring开发的基础jar外,还应额外导入几个jar
- com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
- com.springsource.org.aopalliance-1.0.0.jar
- spring-aop-4.2.4.RELEASE.jar
- spring-aspects-4.2.4.RELEASE.jar
- 编写目标类、切面类
- 切面类
- package com.qf.aop.demo;
- public class MyAspectJ {
- public void advice() {
- System.out.println("========通知========");
- }
- }
- 目标类
- package com.qf.aop.demo;
- public interface TestDao {
- void add();
- void delete();
- void update();
- void query();
- }
- package com.qf.aop.demo;
- public class TestDaoImpl implements TestDao {
- @Override
- public void add() {
- System.out.println("add()");
- }
- @Override
- public void delete() {
- System.out.println("delete()");
- }
- @Override
- public void update() {
- System.out.println("update()");
- }
- @Override
- public void query() {
- System.out.println("query()");
- }
- }
- 切面类
- 配置文件编写
- 引入aop的约束
- <?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: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
- http://www.springframework.org/schema/aop/spring-aop.xsd">
- </beans>
- <?xml version="1.0" encoding="UTF-8"?>
- 具体aop配置
- <?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: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
- http://www.springframework.org/schema/aop/spring-aop.xsd">
- <!-- 配置spring管理需要被增强的目标对象 -->
- <bean id="testDao" class="com.qf.aop.demo.TestDaoImpl"></bean>
- <!-- 配置spring管理切面对象 -->
- <bean id="aspect" class="com.qf.aop.demo.MyAspectJ"></bean>
- <!-- 配置aop,实现对目标类产生代理 -->
- <aop:config>
- <!-- expression:具体哪个类的哪个方法需要增强 -->
- <aop:pointcut expression="execution(* com.qf.aop.demo.TestDaoImpl.delete(..))" id="pointcut01"/>
- <!-- 配置切面 -->
- <aop:aspect ref="aspect">
- <!-- method:选择使用切面中的哪一个增强 -->
- <aop:after method="advice" pointcut-ref="pointcut01"/>
- </aop:aspect>
- </aop:config>
- </beans>
- <?xml version="1.0" encoding="UTF-8"?>
- 引入aop的约束
- 测试
- 测试类
- package com.qf.aop.demo;
- import javax.annotation.Resource;
- import org.junit.Test;
- import org.junit.runner.RunWith;
- import org.springframework.test.context.ContextConfiguration;
- import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
- @RunWith(SpringJUnit4ClassRunner.class)
- @ContextConfiguration("classpath:applicationContext.xml")
- public class TestDemo {
- @Resource(name="testDao")
- private TestDao testDao;
- @Test
- public void test() {
- testDao.add();
- testDao.delete();
- testDao.update();
- testDao.query();
- }
- }
- 测试结果
- add()
- delete()
- ========通知========
- update()
- query()
- add()
- 测试类
通知类型
- 前置通知:在目标方法之前进行操作
- 切面的增强方法中可以获得连接点信息
- 切面中的增强方法
- public void advice(JoinPoint joinPoint) {
- System.out.println("========通知========"+joinPoint);
- }
- public void advice(JoinPoint joinPoint) {
- 配置文件
- <aop:before method="advice" pointcut-ref="pointcut01"/>
- 切面中的增强方法
- 切面的增强方法中可以获得连接点信息
- 后置通知:在目标方法之后进行操作
- 可以获得目标方法的返回值
- 目标方法
- @Override
- public String delete() {
- System.out.println("delete()");
- return "testResult";
- }
- @Override
- 切面中的增强方法
- public void advice(Object obj) {
- System.out.println("========通知========"+obj);
- }
- public void advice(Object obj) {
- 配置文件,returning属性值和增强方法中的参数名称必须一致
- <aop:after-returning method="advice" pointcut-ref="pointcut01" returning="obj"/>
- 目标方法
- 可以获得目标方法的返回值
- 环绕通知:在目标方法之前和之后都进行操作
- 切面中的增强方法
- public Object advice(ProceedingJoinPoint pjp) throws Throwable {
- System.out.println("========环绕前通知========");
- Object object = pjp.proceed();
- System.out.println("========环绕后通知========");
- return object;
- }
- public Object advice(ProceedingJoinPoint pjp) throws Throwable {
- 配置文件
- <aop:around method="advice" pointcut-ref="pointcut01" />
- 异常通知:在目标方法出现异常时,进行操作
- 可以获取异常信息
- 目标方法中设置一个异常
- public String delete() {
- System.out.println("delete()");
- int a = 1/0;
- return "testResult";
- }
- public String delete() {
- 切面中的增强方法
- public void advice(Throwable e) {
- System.out.println("======异常通知=="+e.getMessage());
- }
- public void advice(Throwable e) {
- 配置文件
- <aop:after-throwing method="advice" pointcut-ref="pointcut01" throwing="e"/>
- 目标方法中设置一个异常
- 可以获取异常信息
- 最终通知:无论代码是否有异常,都会操作
- <aop:after method="advice" pointcut-ref="pointcut01" />
切入表达式
- 基于execution函数
- 语法:[访问修饰符] 返回值 包名.类名.方法名(方法参数)
- *:通配符,* com.qf.test.*.*(..)表示com.qf.test包下的所有类的所有方法
- +:* com.qf.test.TestDao+.add(..)表示TestDao类和其子类下的add方法
- ..:* com.qf..*.*(..)表示com.qf包以及其子包下的所有类的所有方法
注解方式
简单实现
- 导入jar包,和XML方式的jar一致
- 编写目标类和切面类
- 编写目标类
- package com.qf.aop.demo;
- public class TestDaoImpl implements TestDao {
- @Override
- public void add() {
- System.out.println("add()");
- }
- @Override
- public String delete() {
- System.out.println("delete()");
- return "testResult";
- }
- @Override
- public void update() {
- System.out.println("update()");
- }
- @Override
- public void query() {
- System.out.println("query()");
- }
- }
- 编写切面类
- package com.qf.aop.demo;
- import org.aspectj.lang.annotation.Aspect;
- import org.aspectj.lang.annotation.Before;
- import org.aspectj.lang.annotation.Pointcut;
- @Aspect
- public class MyAspectJ {
- //方式一:
- /*@Before(value="execution(* com.qf.aop.demo.TestDaoImpl.query(..))")
- public void advice() {
- System.out.println("======before通知==");
- }*/
- //方式二:
- @Pointcut(value="execution(* com.qf.aop.demo.TestDaoImpl.query(..))")
- private void pointcut() {};
- @Before("MyAspectJ.pointcut()")
- public void advice() {
- System.out.println("======before通知==");
- }
- }
- 编写目标类
- 编写配置文件
- 配置Spring管理bean,开启AOP注解
- <?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: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
- http://www.springframework.org/schema/aop/spring-aop.xsd">
- <!-- 配置spring管理需要被增强的目标对象 -->
- <bean id="testDao" class="com.qf.aop.demo.TestDaoImpl"></bean>
- <!-- 配置spring管理切面对象 -->
- <bean id="aspect" class="com.qf.aop.demo.MyAspectJ"></bean>
- <!-- 配置打开aop注解 -->
- <aop:aspectj-autoproxy/>
- </beans>
- <?xml version="1.0" encoding="UTF-8"?>
- 配置Spring管理bean,开启AOP注解
- 测试
- 测试类
- package com.qf.aop.demo;
- import javax.annotation.Resource;
- import org.junit.Test;
- import org.junit.runner.RunWith;
- import org.springframework.test.context.ContextConfiguration;
- import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
- @RunWith(SpringJUnit4ClassRunner.class)
- @ContextConfiguration("classpath:applicationContext.xml")
- public class TestDemo {
- @Resource(name="testDao")
- private TestDao testDao;
- @Test
- public void test() {
- testDao.add();
- testDao.delete();
- testDao.update();
- testDao.query();
- }
- }
- 测试结果
- add()
- delete()
- update()
- ======before通知==
- query()
- add()
- 测试类
三、spring的AOP的更多相关文章
- 深入浅出学习Spring框架(三):AOP 详解
AOP的英文解释——AOPAspect Oriented Programming面向切面编程.主要目的是通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术. 在反 ...
- Spring AOP源码分析(三)创建AOP代理
摘要: 本文结合<Spring源码深度解析>来分析Spring 5.0.6版本的源代码.若有描述错误之处,欢迎指正. 目录 一.获取增强器 1. 普通增强器的获取 2. 增加同步实例化增强 ...
- 10 Spring框架 AOP (三) Spring对AspectJ的整合
上两节我们讲了Spring对AOP的实现,但是在我们的开发中我们不太使用Spring自身的对AOP的实现,而是使用AspectJ,AspectJ是一个面向切面的框架,它扩展了Java语言.Aspect ...
- spring 学习(三):aop 学习
spring 学习(三):aop 学习 aop 概念 1 aop:面向切面(方面)编程,扩展功能不修改源代码实现 2 AOP采取横向抽取机制,取代了传统纵向继承体系重复性代码 3 aop底层使用动态代 ...
- 死磕Spring之AOP篇 - Spring AOP自动代理(三)创建代理对象
该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读. Spring 版本:5.1 ...
- spring学习三:Spring的Aop、代理
ref:https://mp.weixin.qq.com/s/J77asUvw8FcnF-6YlX6AAw AOP相关术语: Joinpoint(连接点):类里面可以被增强的方法,这些方法称为连 ...
- 基于spring注解AOP的异常处理
一.前言 项目刚刚开发的时候,并没有做好充足的准备.开发到一定程度的时候才会想到还有一些问题没有解决.就比如今天我要说的一个问题:异常的处理.写程序的时候一般都会通过try...catch...fin ...
- Spring基于AOP的事务管理
Spring基于AOP的事务管理 事务 事务是一系列动作,这一系列动作综合在一起组成一个完整的工作单元,如果有任何一个动作执行失败,那么事务 ...
- spring的AOP
最近公司项目中需要添加一个日志记录功能,就是可以清楚的看到谁在什么时间做了什么事情,因为项目已经运行很长时间,这个最初没有开来进来,所以就用spring的面向切面编程来实现这个功能.在做的时候对spr ...
随机推荐
- Django 高级配置
目录 Django 信号 信号系统三要素: 信号的分类: Django 内置信号: 具体 Django 信号内容 定义信号 发送信号 接收信号 信号接收器 防止重复信号 Django 内置信号操作步骤 ...
- 四 shell基本命令
一 内置命令 hlep 命令 帮助 help test help -s printf 显示内置命令的语法格式 echo 用来显示一行文字 echo "hello world&quo ...
- 关于.net中使用reportview所需注意
参考文章链接:http://www.cnblogs.com/watercold/p/5258608.html 这段时间在做一个winform的小项目时,发现使用.net中的ReportViewer插件 ...
- VMware Tool的新手简单安装
1.打开工具栏的虚拟机,点击安装VMware tool2.打开根目录的media文件夹,打开用户名命名的文件夹,复制VMxxx.tar.gz的压缩包3.粘贴到Home,4.在终端输入tar -zxvf ...
- 生成RSA公钥密钥
非对称加密就不做详细解释了,它的过程简单来说呢,就是A与B通讯,A公布了一个公开密钥,而且A手里还有一个私有的钥匙,叫密钥.B使用A给的公钥将内容进行加密,然后传递给A.A拿到加密后的内容后,用私钥解 ...
- Codeforces Global Round 1 (CF1110) (未完结,只有 A-F)
Codeforces Global Round 1 (CF1110) 继续补题.因为看见同学打了这场,而且涨分还不错,所以觉得这套题目可能会比较有意思. 因为下午要开学了,所以恐怕暂时不能把这套题目补 ...
- [Luogu2170]选学霸
这一道题,由于他说,"如果实力相当的人中,一部分被选上,另一部分没有,同学们就会抗议."而要求"既不让同学们抗议,又与原来的M尽可能接近".因此,我们要对实力相 ...
- React笔记02——React中的组件
一个网页可以被拆分成若干小部分,每个部分都可以称为组件,即组件是网页中的一部分.组件中还可以有多个组件. 上一节中的App.js就是一个组件(继承了React.Component类的类). 一个组件的 ...
- Java总结第一期
神奇的小阳阳阳再度归来,大家一定想我了吧~哦,谢谢,谢谢,谢谢各位的掌声,thank you,thank you@ 第一章: 下面给大家简单介绍Java: Java技术可以应用在几乎所有类型和规模的设 ...
- HTTP协议之-URL
一.URL url统一资源定位符 1.URL格式: 方案.就是指所使用的协议,类似http:// 服务器的地址,类似i.cnblogs.com/ 制定web服务器的某个资源路径 方案://服务器位置/ ...