Java JDK 动态代理实现和代码分析
JDK 动态代理
参考博文:https://blog.csdn.net/jiankunking/article/details/52143504
内容
一、动态代理解析
1. 代理模式
Java 这门语言有许多种设计模式,其中一种设计模式为代理模式,所谓代理模式,就是通过代理方来操作目标对象,而不是自己直接调用。代理模式又分为静态代理和动态代理。
静态代理:针对每个被代理对象写一个代理类,当有多个代理对象时需要写多个代理类,操作不够优雅;
动态代理:可以根据接口动态的生成代理类,这动态生成的类不需要自己书写,jdk帮我们完成了,代码变得简洁。
无论是动态代理还是静态代理,最终都会产生一个代理类(class文件),里面都含有对被代理对象的封装,只是诞生的途径不一样。下面我主要介绍 JDK 动态代理 的实现和原理。
2. 为什么要使用动态代理
动态代理是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制对某个对象的访问。代理类负责为委托类预处理消息,过滤消息并转发消息,以及进行消息被委托类执行后的后续处理。
3. JDK 动态代理简单结构图

4. JDK 动态代理实现步骤
- 创建一个实现接口InvocationHandler的类,它必须实现invoke方法
- 创建被代理的类以及接口
- 通过Proxy的静态方法 newProxyInstance(ClassLoaderloader, Class[] interfaces, InvocationHandler h)创建一个代理
- 通过代理调用方法
注意: 真实类(被代理的类)必须实现接口
5. JDK 动态代理 API
5.1 java.lang.reflect.Proxy
Java 动态代理机制生成的所有动态代理类的父类,它提供了一组静态方法来为一组接口动态地生成代理类及其对象。
主要方法: public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler hanlder)
- 方法职责:
为指定类加载器、一组接口及调用处理器生成动态代理类实例。 - 方法参数:
loader : 类加载器,一般传递真实对象的类加载器;
interfaces: 代理类需要实现的接口;
handler: 代理执行处理器,说人话就是生成代理对象帮你要做什么。 - 方法返回: 创建的代理对象。
5.1 java.lang.reflect.InvocationHandler
主要方法:public Object invoke(Object proxy, Method method, Object[] args)。
- 方法职责:
代理类实现该接口,负责集中处理动态代理类上的所有方法调用,让使用者自定义做什么事情, 对原来方法增强(加什么功能)。 - 方法参数:
proxy : 生成的代理对象;
method: 当前调用的真实方法对象;
args : 当前调用方法的实参。 - 方法返回: 真实方法的返回结果。
二、JDK 动态代理的实现(代码)
1. 项目结构图

2. IRentService 接口
package com.yy.homework.service;
public interface IRentService {
void rent();
}
3. LandlordServiceImpl 真实类
package com.yy.homework.service.impl;
import com.yy.homework.service.IRentService;
public class LandlordServiceImpl implements IRentService {
@Override
public void rent() {
System.out.println("我是房东,我以1000一个月的房价给中介帮我出租!");
}
}
4. TransactionInvocationHandler 代理类
package com.yy.homework.service.impl;
import com.yy.homework.tx.MyTransactionManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class TransactionInvocationHandler implements InvocationHandler {
private Object target;
@Autowired
private MyTransactionManager myTransactionManager;
public Object getTarget() {
return target;
}
public void setTarget(Object target) {
this.target = target;
}
/**
* @author YanYang
* @description: 负责集中处理动态代理类上的所有方法调用,让使用者自定义做什么事情,对原来方法增强(模拟一下事务)
* proxy:生成的代理对象
* method:调用真实对象的方法
* args:当前调用方法的实参
* return:返回真实方法的返回结果
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object retVal = null;
try {
// 开启事务
myTransactionManager.begin();
// 调用真实对象的方法
retVal = method.invoke(target, args);
// 提交事务
myTransactionManager.commit();
} catch (Exception e) {
// 回滚事务
myTransactionManager.rollback();
e.printStackTrace();
}
return retVal;
}
}
5. MyTransactionManager 增强类(模拟一下事务)
package com.yy.homework.tx;
import org.springframework.stereotype.Component;
/**
* @program: static-proxy
* @ClassName MyTransactionManager
* @description:
* @author: YanYang
**/
@Component
public class MyTransactionManager {
public void begin() {
System.out.println("开启事务");
}
public void commit() {
System.out.println("提交事务");
}
public void rollback() {
System.out.println("回滚事务");
}
}
6. 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 http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.yy.homework"/>
<bean id="transactionInvocationHandler" class="com.yy.homework.service.impl.TransactionInvocationHandler">
<property name="target">
<!-- 把房东真实对象参起来藏起来 -->
<bean class="com.yy.homework.service.impl.LandlordServiceImpl"/>
</property>
</bean>
</beans>
7. TransactionInvocationHandlerTest 测试类
package com.yy.homework.service.impl;
import com.yy.homework.service.IRentService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.lang.reflect.Proxy;
import java.util.Arrays;
/**
* @program: static-proxy
* @ClassName TransactionInvocationHandlerTest
* @description:
* @author: YanYang
**/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class TransactionInvocationHandlerTest {
@Autowired
TransactionInvocationHandler handler;
@Test
public void invoke() {
// 动态生成代理类并创建对象
IRentService proxy = (IRentService) Proxy.newProxyInstance(
// 类加载器,一般传递真实对象的类加载器
handler.getTarget().getClass().getClassLoader(),
// 代理类需要实现的接口,获取真实类实现的接口,生成代理类也是实现什么接口
handler.getTarget().getClass().getInterfaces(),
// 代理执行处理器,也就是生成代理对象帮你要做什么
// 通过这个参数告诉 API 生成代理对象具体做什么
handler);
proxy.rent();
System.out.println("handler = " + Arrays.toString(handler.getTarget().getClass().getInterfaces()));
System.out.println("classLoader = " + handler.getTarget().getClass().getClassLoader());
System.out.println("handler = " + handler);
}
}
运行结果:
"C:\Program Files\Java\jdk-11.0.9\bin\java.exe"
com.intellij.rt.junit.JUnitStarter -ideVersion5 -junit4 com.yy.homework.service.impl.TransactionInvocationHandlerTest,invoke
开启事务
我是房东,我以1000一个月的房价给中介帮我出租!
提交事务
handler = [interface com.yy.homework.service.IRentService]
classLoader = jdk.internal.loader.ClassLoaders$AppClassLoader@2437c6dc
handler = com.yy.homework.service.impl.TransactionInvocationHandler@36328d33
Process finished with exit code 0
总结
以上就是对 JDK 动态代理 的总结了,代码仅供参考,欢迎讨论交流。
Java JDK 动态代理实现和代码分析的更多相关文章
- JAVA设计模式-动态代理(Proxy)源码分析
在文章:JAVA设计模式-动态代理(Proxy)示例及说明中,为动态代理设计模式举了一个小小的例子,那么这篇文章就来分析一下源码的实现. 一,Proxy.newProxyInstance方法 @Cal ...
- Java JDK 动态代理使用及实现原理分析
转载:http://blog.csdn.net/jiankunking 一.什么是代理? 代理是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制对某个对象的访问.代理类负责为委托类预处理 ...
- Java,JDK动态代理的原理分析
1. 代理基本概念: 以下是代理概念的百度解释:代理(百度百科) 总之一句话:三个元素,数据--->代理对象--->真实对象:复杂一点的可以理解为五个元素:输入数据--->代理对象- ...
- Java JDK动态代理解析
动态代理虽不常自己实现,但在Spring或MyBatis中都有重要应用.动态代理的意义在于生成一个占位(又称代理对象),来代理真实对象,从而控制真实对象的访问.Spring常JDK和CGLIB动态代理 ...
- java jdk动态代理学习记录
转载自: https://www.jianshu.com/p/3616c70cb37b JDK自带的动态代理主要是指,实现了InvocationHandler接口的类,会继承一个invoke方法,通过 ...
- JDK动态代理实现源码分析
JDK动态代理实现方式 在Spring框架中经典的AOP就是通过动态代理来实现的,Spring分别采用了JDK的动态代理和Cglib动态代理,本文就来分析一下JDK是如何实现动态代理的. 在分析源码之 ...
- JDK动态代理案例与原理分析
一.JDK动态代理实现案例 Person接口 package com.zhoucong.proxy.jdk; public interface Person { // 寻找真爱 void findlo ...
- java jdk动态代理模式举例浅析
代理模式概述 代理模式是为了提供额外或不同的操作,而插入的用来替代”实际”对象的对象,这些操作涉及到与”实际”对象的通信,因此代理通常充当中间人角色. java中常用的动态代理模式为jdk动态代理和c ...
- java jdk动态代理
在面试的时候面试题里有一道jdk的动态代理是原理,并给一个事例直接写代码出来,现在再整理一下 jdk动态代理主要是想动态在代码中增加一些功能,不影响现有代码,实现动态代理需要做如下几个操作 1.首先必 ...
随机推荐
- 'javac' 不是内部或外部命令,也不是可运行的程序或批处理文件
记录在配置环境变量中被 Path 环境坑的一次前提:保证自己电脑中jdk环境配置都没有问题,即JAVA_HOME.Path.CLASSPATH均配置成功. 在这里我就不操作如何配置环境变量了,百度上面 ...
- LOJ6485题解
应该是经典题之一了. \[[n|k]=\frac 1 n\sum_{i=0}^{n-1}w_n^{ik} \] 有这个就可以算了. \[\sum_{i=0}^n\binom n i x^ia_{i \ ...
- Linux----虚拟机克隆、快照、删除、
克隆 已经安装一台linux系统 还想要更多的,直接克隆CentOS即可 使用vm ware 的克隆操作 注意: 使用前先关闭目前已开启的虚拟机 快照 作用: 虚拟系统出现异常,需要回到原先的状态,此 ...
- exit函数和return语句
exit函数是c语言的库函数,有一个整型的参数,代表进程终止,这个函数需<stdlib.h>头文件 在函数中写return只是代表函数终止了,不管在程序的任何位置调用exit那么进程就立即 ...
- kdump原理,是如何找到入口的
请解释下kdump原理,捕获内核是如何获取到生产内核的首地址的.
- 74CMS 3.0任意文件写入漏洞
一. 启动环境 1.双击运行桌面phpstudy.exe软件 2.点击启动按钮,启动服务器环境 二.代码审计 1.双击启动桌面Seay源代码审计系统软件 2.因为74CMS3.0源代码编辑使用GBK编 ...
- 给windows右键添加快捷启动程序
给windows右键添加快捷启动程序 修改点击空白处的右键 运行--redegit 打开注册表 展开第一个H..C..R 找到 Direcory,展开 找到Background 展开 右键shell, ...
- 数据库篇:mysql锁详解
前言 sql事务的执行,如果需要锁定数据进行更新操作,则必定离不开锁 共享锁和排他锁 表锁 行锁 Record Lock 间隙锁 Gap Lock 行锁+间隙锁 Next-Key Lock 加锁场景( ...
- Linux C++ 实现一个简易版的ping (也就是imcp协议)
背景: 想实现一个在没外网的时候就自动重启路由器的功能. 又不想用ping命令,因为在代码里调用system("ping"); 可能会比较耗时,得单开线程.于是找了个实现ICMP协 ...
- leetcode-3无重复字符的最长子串
题目原题: 给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度. 示例 1: 输入: s = "abcabcbb" 输出: 3 解释: 因为无重复字符的最长子串是 ...