学习来源于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动态代理实现不改变原有代码为其增加打印日志和提交事务的功能。

实现步骤:

  1. 创建目标类,SomeServiceImpl类,给它的doSome,doOther增加日志和事务功能
  2. 创建InvocationHandler接口的实现类,在这个类实现给目标方法增加功能。
  3. 使用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动态代理相关推荐

  1. 浅谈Spring中JDK动态代理与CGLIB动态代理

    前言 Spring是Java程序员基本不可能绕开的一个框架,它的核心思想是IOC(控制反转)和AOP(面向切面编程).在Spring中这两个核心思想都是基于设计模式实现的,IOC思想的实现基于工厂模式 ...

  2. Spring : Spring Aop JDK动态代理调用过程

    1.美图 2.概述 JDK动态代理参考 : JDK动态代理 3.源码 打开JdkDynamicAopProxy类,查看invoke方法: /*** Implementation of {@code I ...

  3. 浅谈Spring的AOP实现-代理机制

    说起Spring的AOP(Aspect-Oriented Programming)面向切面编程大家都很熟悉(Spring不是这次博文的重点),但是我先提出几个问题,看看同学们是否了解,如果了解的话可以 ...

  4. 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 ...

  5. spring中AOP动态代理的两种方式

    AOP动态代理的两种方式 Spring AOP动态代理的方式(spring的AOP默认是JDK Proxy) 浅谈这两种动态代理 JDK的动态代理,需要有实现接口 动态代理--JDK Proxy ⚫ ...

  6. (转)面试必备技能:JDK动态代理给Spring事务埋下的坑!

    一.场景分析 最近做项目遇到了一个很奇怪的问题,大致的业务场景是这样的:我们首先设定两个事务,事务parent和事务child,在Controller里边同时调用这两个方法,示例代码如下: 1.场景A ...

  7. Spring 初识Aop JDK动态代理实现 原理初显

    Spring 初识Aop JDK动态代理实现 原理初显 一.项目结构 二.具体步骤: 1.创建maven项目 创建好包结构 2.写一个TestDao接口 及实现类 3. 写一个自己的切面类 4.jav ...

  8. Spring JDK动态代理

    JDK 动态代理是通过 JDK 中的 java.lang.reflect.Proxy 类实现的.下面通过具体的案例演示 JDK 动态代理的使用. 1. 创建项目 在 MyEclipse 中创建一个名称 ...

  9. Spring AOP动态代理实现,解决Spring Boot中无法正常启用JDK动态代理的问题

    Spring AOP动态代理实现,解决Spring Boot中无法正常启用JDK动态代理的问题 参考文章: (1)Spring AOP动态代理实现,解决Spring Boot中无法正常启用JDK动态代 ...

最新文章

  1. thinkphp mysql 密码加密_thinkphp框架实现mysql读写分离
  2. centos7安装vsftpd
  3. 完美解决Informix的中文乱码问题
  4. OWASP 2017 Top10 漏洞体系
  5. 成都Uber优步司机奖励政策(4月12日)
  6. python字典随时添加元素和值
  7. abb变频器acs880说明书_常见品牌变频器修改功率方法大全
  8. 面向对象之迪米特法则
  9. Minidao_1.6.1版本发布,超轻量Java持久化框架
  10. 联想微型计算机功率,解锁全部潜力,联想这款笔记本可以将CPU功耗提升至24W
  11. 解析WeNet云端推理部署代码
  12. 七种方法实现单例模式
  13. vs快速添加引用解析的快捷键
  14. 一张图理清SpringMVC工作原理
  15. 数据库知识整理 - 并发控制(封锁、两段锁协议、意向锁)
  16. 《C++精英内参之程序员高效指南》-12-8影响效率的不良习惯之科学的休息方法
  17. AM5728概述(1)
  18. 03JavaScript基础——数组、二维数组、数组方法
  19. 谈谈对数据治理的理解
  20. 编程设计一个基于条件风险最小的Bayes分类器

热门文章

  1. 机械设备行业:工业气体企业财务分析
  2. 刘强东在耶鲁北京中心演讲(2015-8):商城+金融+3农+生鲜
  3. c++语言编的小游戏,用C++语言编写小游戏系统(可读取文件)
  4. 转载:做技术有前途吗?一位老工程师对年轻人的“十大忠告”
  5. 京东技术助力十余省抗击疫情 应急资源平台已提供超6.6亿件抗疫物资
  6. v-for与v-if为什么不能同时用?
  7. Java进阶:java程序设计慕课版课后答案浪潮优派
  8. 解析面试常问题之JavaScript中的闭包概念及应用,顺便普及一下大家口中常说的内存泄漏问题
  9. ARM的memory Compiler总结
  10. react使用antd-mobile做自定义替换头像功能