浅谈spring之jdk动态代理
学习来源于b站动力节点
JDK动态代理
动态代理的实现方式常用的有两种:使用JDK的Proxy,与通过CGLIB生成代理。jdk的动态要求目标对象必须实现接口,这是java设计上的要求,使用jdk中的Proxy,Method,InvocationHanderl创建代理对象。接下来演示jdk动态代理实现的一个小业务。
案例:
目前该项目主要完成业务doSome方法或doOther方法。(模拟项目开发,用注解获取对象)
在service包下有SomeService接口(其中有doSome和doOther方法)。
package com.pingfan.bao05.service;
public interface SomeService {void doSome();void doOther();
}
service包下有impl包以及impl包下有实现SomeService接口的类SomeServiceImpl
package com.pingfan.bao05.service.impl;
import com.pingfan.bao05.service.SomeService;
import org.springframework.stereotype.Component;
@Component
public class SomeServiceImpl implements SomeService {@Overridepublic void doSome() {System.out.println("执行业务方法doSome");}@Overridepublic void doOther() {System.out.println("执行业务方法doOther");}
}
applicationContext.xml
<?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 https://www.springframework.org/schema/context/spring-context.xsd"><context:component-scan base-package="com.pingfan.bao05"/>
</beans>
测试:
@Test
public void test02(){String config="applicationContext.xml";ApplicationContext ac=new ClassPathXmlApplicationContext(config);SomeServiceImpl someService= (SomeServiceImpl) ac.getBean("someServiceImpl");someService.doSome();
}
该项目运行一段时间需要改造,对业务增加功能。比如增加记录时间的功能,和提交事务的功能。
对该功能可以在原有代码基础上实现:
对SomeServiceImpl进行修改
package com.pingfan.bao05.service.impl;import com.pingfan.bao05.service.SomeService;
import org.springframework.stereotype.Component;import java.text.SimpleDateFormat;
import java.util.Date;@Component
public class SomeServiceImpl implements SomeService {@Overridepublic void doSome() {System.out.println("执行方法的时间"+new SimpleDateFormat("yyyy-MM-dd").format(new Date()));System.out.println("执行业务方法doSome");//提交事务System.out.println("方法执行完毕提交事务");}@Overridepublic void doOther() {System.out.println("执行方法的时间"+new SimpleDateFormat("yyyy-MM-dd").format(new Date()));System.out.println("执行业务方法doOther");System.out.println("方法执行完毕提交事务");}
}
测试:
@Test
public void test02(){String config="applicationContext.xml";ApplicationContext ac=new ClassPathXmlApplicationContext(config);SomeServiceImpl someService= (SomeServiceImpl) ac.getBean("someServiceImpl");someService.doSome();System.out.println("-----------");someService.doOther();
}
结果
执行方法的时间2021-01-16
执行业务方法doSome
方法执行完毕提交事务
-----------
执行方法的时间2021-01-16
执行业务方法doOther
方法执行完毕提交事务
至此功能添加成功,如果像这种类很多,在开发中添加起来很多次,而且都是重复的操作。接下来对该项目进行优化,使得逻辑清晰。
增加一个工具类。ServiceTools。(把非业务方法放到工具类中)
package com.pingfan.bao05.utiles;
import java.text.SimpleDateFormat;
import java.util.Date;
public class ServiceTools {public static void doLog(){System.out.println("非业务方法,执行方法的时间"+new SimpleDateFormat("yyyy-MM-dd").format(new Date()));}public static void doTrans(){System.out.println("方法执行完毕提交事务");}
}
接下来使用jdk动态代理实现不改变原有代码为其增加打印日志和提交事务的功能。
实现步骤:
- 创建目标类,SomeServiceImpl类,给它的doSome,doOther增加日志和事务功能
- 创建InvocationHandler接口的实现类,在这个类实现给目标方法增加功能。
- 使用jdk中类Proxy,创建代理对象。实现创建对象的能力。
1我们已经完成,接下来实现2
MyIncationHandler.java
package com.pingfan.bao05.handler;import com.pingfan.bao05.utiles.ServiceTools;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;public class MyIncationHandler implements InvocationHandler {//目标对象private Object targect;//SomeServiceImpl类public MyIncationHandler(Object targect){this.targect=targect;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {//通过代理对象执行方法时,会调用执行这个invoke//执行目标类的方法,通过Method类实现。Object res=null;ServiceTools.doLog();res=method.invoke(targect,args);//SomeServiceImpl.doOther或者doSomeServiceTools.doTrans();//目标方法执行结果return res;}
}
实现步骤3
@Test
public void test02(){String config="applicationContext.xml";ApplicationContext ac=new ClassPathXmlApplicationContext(config);//使用jdk的Proxy创建代理对象,创建目标对象。SomeServiceImpl targect= (SomeServiceImpl) ac.getBean("someServiceImpl");//创建InvocationHandler对象InvocationHandler handler=new MyIncationHandler(targect);//使用Proxy创建代理SomeService proxy=(SomeService) Proxy.newProxyInstance(targect.getClass().getClassLoader(),targect.getClass().getInterfaces(),handler);//通过代理执行方法,会调用handler中的invokeproxy.doSome();
}
结果:
非业务方法,执行方法的时间2021-01-16
执行业务方法doSome
方法执行完毕提交事务
分析:首先执行proxy.doSome();
他会执行proxy类中的handler类中的invake方法。而其中的method是通过jdk处理我们拿到的doSome,也就是Proxy.doSome,传递到了method,进而执行目标类的doSome方法,那我们就可以在此之前或者之后执行我们增加的功能。
现在又有个需求,我们只在执行doSome方法时,才执行日志和事务功能。
分析:通过获取到的方法名进行判断执行的方法,再进行增加功能。
对MyIncationHandler进行修改。
package com.pingfan.bao05.handler;import com.pingfan.bao05.utiles.ServiceTools;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;public class MyIncationHandler implements InvocationHandler {//目标对象private Object targect;//SomeServiceImpl类public MyIncationHandler(Object targect){this.targect=targect;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {//通过代理对象执行方法时,会调用执行这个invoke//执行目标类的方法,通过Method类实现。Object res=null;if(method.getName().equals("doSome")){ServiceTools.doLog();res=method.invoke(targect,args);//SomeServiceImpl.doOther或者doSomeServiceTools.doTrans();}else{res=method.invoke(targect,args);//SomeServiceImpl.doOther或者doSome}//目标方法执行结果return res;}
}
测试:
@Test
public void test02(){String config="applicationContext.xml";ApplicationContext ac=new ClassPathXmlApplicationContext(config);//使用jdk的Proxy创建代理对象,创建目标对象。SomeServiceImpl targect= (SomeServiceImpl) ac.getBean("someServiceImpl");//创建InvocationHandler对象InvocationHandler handler=new MyIncationHandler(targect);//使用Proxy创建代理SomeService proxy=(SomeService) Proxy.newProxyInstance(targect.getClass().getClassLoader(),targect.getClass().getInterfaces(),handler);//通过代理执行方法,会调用handler中的invokeproxy.doSome();System.out.println("-----------");proxy.doOther();
}
结果:
非业务方法,执行方法的时间2021-01-16
执行业务方法doSome
方法执行完毕提交事务
-----------
执行业务方法doOther
总结:可以看到执行doSome方法时才会执行额外的功能。至此动态代理的实现完成,而我们接下来学习的aop他就是基于动态代理实现的,可以明显的发现,我们在不改变源代码的基础上增加了新的功能,体现了动态代理的解耦合。实现业务和非业务功能分离。
浅谈spring之jdk动态代理相关推荐
- 浅谈Spring中JDK动态代理与CGLIB动态代理
前言 Spring是Java程序员基本不可能绕开的一个框架,它的核心思想是IOC(控制反转)和AOP(面向切面编程).在Spring中这两个核心思想都是基于设计模式实现的,IOC思想的实现基于工厂模式 ...
- Spring : Spring Aop JDK动态代理调用过程
1.美图 2.概述 JDK动态代理参考 : JDK动态代理 3.源码 打开JdkDynamicAopProxy类,查看invoke方法: /*** Implementation of {@code I ...
- 浅谈Spring的AOP实现-代理机制
说起Spring的AOP(Aspect-Oriented Programming)面向切面编程大家都很熟悉(Spring不是这次博文的重点),但是我先提出几个问题,看看同学们是否了解,如果了解的话可以 ...
- Spring AOP JDK动态代理报错:class com.sun.proxy.$Proxy0 cannot be cast to class com.aha.Spring5.jdkproxy.
报错时候的书写 public class JDKProxy {public static void main(String[] args) {UserDaoImpl userDao = new Use ...
- spring中AOP动态代理的两种方式
AOP动态代理的两种方式 Spring AOP动态代理的方式(spring的AOP默认是JDK Proxy) 浅谈这两种动态代理 JDK的动态代理,需要有实现接口 动态代理--JDK Proxy ⚫ ...
- (转)面试必备技能:JDK动态代理给Spring事务埋下的坑!
一.场景分析 最近做项目遇到了一个很奇怪的问题,大致的业务场景是这样的:我们首先设定两个事务,事务parent和事务child,在Controller里边同时调用这两个方法,示例代码如下: 1.场景A ...
- Spring 初识Aop JDK动态代理实现 原理初显
Spring 初识Aop JDK动态代理实现 原理初显 一.项目结构 二.具体步骤: 1.创建maven项目 创建好包结构 2.写一个TestDao接口 及实现类 3. 写一个自己的切面类 4.jav ...
- Spring JDK动态代理
JDK 动态代理是通过 JDK 中的 java.lang.reflect.Proxy 类实现的.下面通过具体的案例演示 JDK 动态代理的使用. 1. 创建项目 在 MyEclipse 中创建一个名称 ...
- Spring AOP动态代理实现,解决Spring Boot中无法正常启用JDK动态代理的问题
Spring AOP动态代理实现,解决Spring Boot中无法正常启用JDK动态代理的问题 参考文章: (1)Spring AOP动态代理实现,解决Spring Boot中无法正常启用JDK动态代 ...
最新文章
- thinkphp mysql 密码加密_thinkphp框架实现mysql读写分离
- centos7安装vsftpd
- 完美解决Informix的中文乱码问题
- OWASP 2017 Top10 漏洞体系
- 成都Uber优步司机奖励政策(4月12日)
- python字典随时添加元素和值
- abb变频器acs880说明书_常见品牌变频器修改功率方法大全
- 面向对象之迪米特法则
- Minidao_1.6.1版本发布,超轻量Java持久化框架
- 联想微型计算机功率,解锁全部潜力,联想这款笔记本可以将CPU功耗提升至24W
- 解析WeNet云端推理部署代码
- 七种方法实现单例模式
- vs快速添加引用解析的快捷键
- 一张图理清SpringMVC工作原理
- 数据库知识整理 - 并发控制(封锁、两段锁协议、意向锁)
- 《C++精英内参之程序员高效指南》-12-8影响效率的不良习惯之科学的休息方法
- AM5728概述(1)
- 03JavaScript基础——数组、二维数组、数组方法
- 谈谈对数据治理的理解
- 编程设计一个基于条件风险最小的Bayes分类器
热门文章
- 机械设备行业:工业气体企业财务分析
- 刘强东在耶鲁北京中心演讲(2015-8):商城+金融+3农+生鲜
- c++语言编的小游戏,用C++语言编写小游戏系统(可读取文件)
- 转载:做技术有前途吗?一位老工程师对年轻人的“十大忠告”
- 京东技术助力十余省抗击疫情 应急资源平台已提供超6.6亿件抗疫物资
- v-for与v-if为什么不能同时用?
- Java进阶:java程序设计慕课版课后答案浪潮优派
- 解析面试常问题之JavaScript中的闭包概念及应用,顺便普及一下大家口中常说的内存泄漏问题
- ARM的memory Compiler总结
- react使用antd-mobile做自定义替换头像功能