Spring AOP动态代理原理与实现方式
AOP:面向切面、面向方面、面向接口是一种横切技术
横切技术运用:
1.事务管理: (1)数据库事务:(2)编程事务(3)声明事物:Spring AOP-->声明事物
2.日志处理:
3.安全验证: Spring AOP---OOP升级
静态代理原理:目标对象:调用业务逻辑 代理对象:日志管理
表示层调用--->代理对象(日志管理)-->调用目标对象
动态代理原理:spring AOP采用动态代理来实现
(1)实现InvocationHandler接口
(2)创建代理类(通过java API)
Proxy.newProxyInstance(动态加载代理类,代理类实现接口,使用handler);
(3)调用invoke方法(虚拟机自动调用方法)
日志处理
//调用目标对象
method.invoke("目标对象","参数");
日志处理
通过代理对象--(请求信息)-->目标对象---(返回信息)----> 代理对象
Spring 动态代理中的基本概念
1、关注点(concern)
一个关注点可以是一个特定的问题,概念、或者应用程序的兴趣点。总而言之,应用程序必须达到一个目标
安全验证、日志记录、事务管理都是一个关注点
在oo应用程序中,关注点可能已经被代码模块化了还可能散落在整个对象模型中
2、横切关注点(crosscutting concern)
如何一个关注点的实现代码散落在多个类中或方法中
3、方面(aspect)
一个方面是对一个横切关注点模块化,它将那些原本散落在各处的,
用于实现这个关注点的代码规整在一处
4、建议(advice)通知
advice是point cut执行代码,是方面执行的具体实现
5、切入点(pointcut)
用于指定某个建议用到何处
6、织入(weaving)
将aspect(方面)运用到目标对象的过程
7、连接点(join point)
程序执行过程中的一个点
通知类型:
try{
//前置通知
//环绕通知
//调用目标对象方法
//环绕通知
//后置通知
}catch(){
//异常通知
}finally{
//终止通知
}
流程图

一.静态代理原理实例:
项目结构图:

IUserServ接口代码
- public interface IUserServ {
- List<User> findAllUser();
- int deleteUserById(User user);
- int saveUser(User user);
- }
UserServImpl实现类代码
- public class UserServImpl implements IUserServ {
- public int deleteUserById(User user) {
- System.out.println("******执行删除方法******");
- return 0;
- }
- public List<User> findAllUser() {
- System.out.println("*******执行查询方法*******");
- return null;
- }
- public int saveUser(User user) {
- System.out.println("*******执行添加方法********");
- return 0;
- }
- }
UserServProxyImpl实现类代码
- //代理类:完成日志输出
- public class UserServProxyImpl implements IUserServ {
- // 访问目标对象(UserServImpl)
- // 代理对象(UserServProxyImpl)
- // 创建目标对象
- private IUserServ iuserServ ;//= new UserServImpl();
- public UserServProxyImpl(IUserServ iuserServ){
- this.iuserServ = iuserServ;
- }
- public int deleteUserById(User user) {
- beforeLog();
- //调用目标对象里方法
- iuserServ.deleteUserById(user);
- afterLog();
- return 0;
- }
- public List<User> findAllUser() {
- beforeLog();
- //调用目标对象里方法
- iuserServ.findAllUser();
- afterLog();
- return null;
- }
- public int saveUser(User user) {
- beforeLog();
- //调用目标对象里方法
- iuserServ.saveUser(user);
- afterLog();
- return 0;
- }
- private void beforeLog() {
- System.out.println("开始执行");
- }
- private void afterLog() {
- System.out.println("执行完毕");
- }
- }
ActionTest测试类代码
- public class ActionTest {
- public static void main(String[] args) {
- //用户访问代理对象---信息->目标对象
- IUserServ iuserServ = new UserServProxyImpl(new UserServImpl());
- iuserServ.findAllUser();
- }
- }
运行结果:
开始执行
*******执行查询方法*******
执行完毕
二.动态代理实例
项目结构图:

IUserServ接口代码与UserServImpl实现类代码和上述代码相同
LogHandler类代码
- public class LogHandler implements InvocationHandler {
- //目标对象
- private Object targetObject;
- /**
- * 创建动态代理类
- * @return object(代理类)
- */
- public Object createProxy(Object targetObject){
- this.targetObject = targetObject;
- return Proxy.newProxyInstance(
- targetObject.getClass().getClassLoader(),
- targetObject.getClass().getInterfaces(), this);
- }
- @Override
- public Object invoke(Object proxy, Method method, Object[] args)
- throws Throwable {
- Object obj = null;
- try {
- beforeLog();
- //obj: 目标对象--->代理对象的返回值--->返回给调用者的信息
- //this.invoke("目标对象","代理对象给目标对象传递参数");
- //调用目标对象中方法
- obj = method.invoke(targetObject, args);
- afterLog();
- } catch (Exception e) {
- e.printStackTrace();
- }
- return obj;
- }
- //日志管理方法
- private void beforeLog(){
- System.out.println("开始执行");
- }
- private void afterLog(){
- System.out.println("执行完毕");
- }
- }
ActionTest测试类代码:
- public class ActionTest {
- public static void main(String[] args) {
- //创建代理对象iuserServ
- LogHandler handler = new LogHandler();
- IUserServ iuserServ = (IUserServ)handler.createProxy(new UserServImpl());
- iuserServ.deleteUserById(new User());
- }
- }
运行结果:
开始执行
******执行删除方法******
执行完毕
三.Spring AOP使用(2.x版本之前)
项目结构图:

IUserServ接口代码与UserServImpl实现类代码和上述代码相同
配置步骤:
1、配置目标对象(applicationContext.xml)
- <bean id="userServTarget" class="com.tarena.biz.impl.UserServImpl"/>
2、配置通知
(a)前置通知(BeforeLogAdvice)
- public class BeforeLogAdvice implements MethodBeforeAdvice {
- /**
- * Method method:调用目标对象的方法
- * Object[] args:发送给目标对象的参数列表
- * Object target:目标对象
- */
- public void before(Method method, Object[] args, Object target)
- throws Throwable {
- beforeLog();
- }
- private void beforeLog(){
- System.out.println("开始执行");
- }
- }
(b)后置通知(AfterLogAdvice)
- public class AfterLogAdvice implements AfterReturningAdvice {
- /**
- * Object returnValue:目标对象返回值
- * Method method:目标对象方法名
- * Object[] args:目标对象参数列表
- * Object target:目标对象
- */
- public void afterReturning(Object returnValue, Method method,
- Object[] args, Object target) throws Throwable {
- afterLog();
- }
- private void afterLog(){
- System.out.println("执行完毕");
- }
- }
(c)在spring容器中,让容器管理通知(applicationContext.xml)
- <!-- 定义通知 -->
- <!-- 前置通知 -->
- <bean id="beforeLogAdvice" class="com.tarena.advice.BeforeLogAdvice"/>
- <!-- 后置通知 -->
- <bean id="afterLogAdvice" class="com.tarena.advice.AfterLogAdvice"/>
3、配置代理对象(applicationContext.xml)
- <!-- 代理类作用: 生成代理类,织入通知 -->
- <bean id="userServProxy"
- class="org.springframework.aop.framework.ProxyFactoryBean">
- <property name="interfaces">
- <!-- 可以添加多个接口 -->
- <list>
- <value>com.tarena.biz.IUserServ</value>
- </list>
- </property>
- <!-- 引入通知 -->
- <property name="interceptorNames">
- <list>
- <value>beforeLogAdvice</value>
- <value>afterLogAdvice</value>
- </list>
- </property>
- <!-- 目标对象 -->
- <property name="target" ref="userServTarget"/>
- </bean>
4.访问()
Spring容器:通过代理对象调用-->织入通知--->目标对象
程序员:访问代理对象
测试类(ActionTest):
- public class ActionTest {
- public static void main(String[] args) {
- ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
- IUserServ iuserServ = (IUserServ)ac.getBean("userServProxy");
- iuserServ.deleteUserById(new User());
- iuserServ.findAllUser();
- }
- }
运行结果:
开始执行
******执行删除方法******
执行完毕
开始执行
*******执行查询方法*******
执行完毕
四.Spring AOP使用(2.x版本之后)这种方式需要额外添加两个jar包,
存放位置在spring-framework-2.5.6.SEC01\lib\aspectj文件夹下。
项目结构图

IUserServ接口代码与UserServImpl实现类代码和上述代码相同
LogAdvice中
- public class LogAdvice {
- public void beforeLog(){
- System.out.println("开始执行");
- }
- public void afterLog(){
- System.out.println("执行完毕");
- }
- }
applicationContext.xml中
- <!-- spring2.x后 -->
- <!-- 目标对象 -->
- <bean id="userServImpl" class="com.tarena.biz.impl.UserServImpl"/>
- <!-- 通知 -->
- <bean id="logAdvice" class="com.tarena.advice.LogAdvice"/>
- <aop:config>
- <aop:aspect id="logAspect" ref="logAdvice">
- <!-- 切入点 -->
- <aop:pointcut id="beforePointCut"
- expression="execution(* saveUser*(..))"/>
- <aop:pointcut id="afterPointCut"
- expression="execution(* saveUser*(..))"/>
- <!-- 织入(通知作用于切入点) -->
- <aop:before method="beforeLog" pointcut-ref="beforePointCut"/>
- <aop:after method="afterLog" pointcut-ref="afterPointCut"/>
- </aop:aspect>
- </aop:config>
测试类:
- public class ActionTest {
- public static void main(String[] args) {
- ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
- IUserServ iuserServ = (IUserServ)ac.getBean("userServImpl");
- iuserServ.deleteUserById(new User());
- iuserServ.findAllUser();
- iuserServ.saveUser(new User());
- }
- }
运行结果
******执行删除方法******
*******执行查询方法*******
开始执行
*******执行添加方法********
执行完毕
注:如果要在业务层所有的方法前后添加日志文件,则需要更改为以下配置
- <aop:pointcut id="beforePointCut"
- expression="execution(* com.tarena.biz.*.*(..))"/>
- <aop:pointcut id="afterPointCut"
- expression="execution(* com.tarena.biz.*.*(..))"/>
运行结果:
开始执行
******执行删除方法******
执行完毕
开始执行
*******执行查询方法*******
执行完毕
开始执行
*******执行添加方法********
执行完毕
Spring AOP动态代理原理与实现方式的更多相关文章
- spring AOP 动态代理和静态代理以及事务
AOP(Aspect Oriented Programming),即面向切面编程 AOP技术,它利用一种称为"横切"的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装 ...
- Spring AOP动态代理实现,解决Spring Boot中无法正常启用JDK动态代理的问题
Spring AOP底层的动态代理实现有两种方式:一种是JDK动态代理,另一种是CGLib动态代理. JDK动态代理 JDK 1.3版本以后提供了动态代理,允许开发者在运行期创建接口的代理实例,而且只 ...
- Spring Aop 动态代理失效分析
1. Spring Aop 原理 Spring Aop 通过动态代理创建代理对象,在调用代理对象方法前后做增强. 2. Transactional, Async 注解失效? 当在动态代理方法中调用当前 ...
- spring aop 动态代理批量调用方法实例
今天项目经理发下任务,需要测试 20 个接口,看看推送和接收数据是否正常.因为对接传输的数据是 xml 格式的字符串,所以我拿现成的数据,先生成推送过去的数据并存储到文本,以便验证数据是否正确,这时候 ...
- Spring AOP 动态代理 缓存
Spring AOP应用:xml配置及注解实现. 动态代理:jdk.cglib.javassist 缓存应用:高速缓存提供程序ehcache,页面缓存,session缓存 项目地址:https://g ...
- Spring AOP动态代理
出现org.springframework.aop.framework.ProxyFactoryBean cannot be cast to 错误 在类型转换的时候, 调用getObject()方法, ...
- Java 动态代理原理图解 (附:2种实现方式详细对比)
动态代理在 Java 中有着广泛的应用,例如:Spring AOP 面向切面编程,Hibernate 数据查询.以及 RPC Dubbo 远程调用等,都有非常多的实际应用@mikechen 目录 ...
- Spring学习笔记之aop动态代理(3)
Spring学习笔记之aop动态代理(3) 1.0 静态代理模式的缺点: 1.在该系统中有多少的dao就的写多少的proxy,麻烦 2.如果目标接口有方法的改动,则proxy也需要改动. Person ...
- spring源码-aop动态代理-5.3
一.动态代理,这是一个很强大的东西哦.研发过程中我们会常用很多业务类,但是存在一个问题.如何在不修改源码逻辑的情况下,加入自己的相关逻辑.比如异常处理,日志记录等! 二.Java动态代理的两种方式JD ...
随机推荐
- python伪代码之爬取完美志愿全国历年文理分数线运行代码持续更新
最近好多小伙伴说想搞个项目实战类的,我就花了一点时间做了一个爬虫项目(在代码复制的时候可能会有点问题,缩格一下就没有问题了) 想要获取更多源码或者答疑或者或者交流学习可以加群:725479218 # ...
- Elastic 技术栈之快速入门
Elastic 技术栈之快速入门 概念 ELK 是什么 ELK 是 elastic 公司旗下三款产品 ElasticSearch .Logstash .Kibana 的首字母组合. ElasticSe ...
- Scala学习(五)---Scala中的类
Scala中的类 摘要: 在本篇中,你将会学习如何用Scala实现类.如果你了解Java或C++中的类,你不会觉得这有多难,并且你会很享受Scala更加精简的表示法带来的便利.本篇的要点包括: 1. ...
- 【转载】固态硬盘的S.M.A.R.T详解
文章来源于: 瑞耐斯存储技术 兵哥写这篇文章,是因为在测试的过程中看到了 SSD存在偶尔有性能下降的情况,经分析为S.M.A.R.T命令所导致,虽然这种情况看似不严重,但如果应用在诸如数据采集等关键性 ...
- Nginx基于TCP/UDP端口的四层负载均衡(stream模块)配置梳理
通过我们会用Nginx的upstream做基于http/https端口的7层负载均衡,由于Nginx老版本不支持tcp协议,所以基于tcp/udp端口的四层负载均衡一般用LVS或Haproxy来做.至 ...
- Linux内核分析 读书笔记 (第三章)
第三章 进程管理 3.1 进程 1.进程: 进程就是处于执行期的程序. 进程就是正在执行的程序代码的实时结果. 进程是处于执行期的程序以及相关的资源的总称. 进程包括代码段和其他资源. 2.线程:执行 ...
- 《Linux内核设计与实现》 第五周 读书笔记(第十八章)
第18章 调试 20135307张嘉琪 18.1 准备开始 18.2 内核中的bug 内核中的bug多种多样,它们的产生可以有无数的原因,同时它们的表象也变化多端,从明白无误的错误代码(比如,没有把正 ...
- /var/lib/mysql 的访问权限问题 Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock' (2)
mysql 登录不进去 提示Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock' (2) she ...
- Alpha冲刺之事后诸葛亮
组长博客 作业博客 项目Postmortem 设想和目标 我们的软件要解决什么问题?是否定义得很清楚?是否对典型用户和典型场景有清晰的描述? 我们的软件针对的是福大学子来到食堂会犹豫不决无法决定吃什么 ...
- Balanced Ternary String CodeForces - 1102D (贪心+思维)
You are given a string ss consisting of exactly nn characters, and each character is either '0', '1' ...