参考博文:https://blog.csdn.net/jiankunking/article/details/52143504

内容

一、动态代理解析

1. 代理模式

Java 这门语言有许多种设计模式,其中一种设计模式为代理模式,所谓代理模式,就是通过代理方来操作目标对象,而不是自己直接调用。代理模式又分为静态代理和动态代理。
静态代理:针对每个被代理对象写一个代理类,当有多个代理对象时需要写多个代理类,操作不够优雅;
动态代理:可以根据接口动态的生成代理类,这动态生成的类不需要自己书写,jdk帮我们完成了,代码变得简洁。
无论是动态代理还是静态代理,最终都会产生一个代理类(class文件),里面都含有对被代理对象的封装,只是诞生的途径不一样。下面我主要介绍 JDK 动态代理 的实现和原理。

2. 为什么要使用动态代理

动态代理是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制对某个对象的访问。代理类负责为委托类预处理消息,过滤消息并转发消息,以及进行消息被委托类执行后的后续处理。

3. JDK 动态代理简单结构图

4. JDK 动态代理实现步骤

  1. 创建一个实现接口InvocationHandler的类,它必须实现invoke方法
  2. 创建被代理的类以及接口
  3. 通过Proxy的静态方法 newProxyInstance(ClassLoaderloader, Class[] interfaces, InvocationHandler h)创建一个代理
  4. 通过代理调用方法

注意: 真实类(被代理的类)必须实现接口

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 动态代理 的总结了,代码仅供参考,欢迎讨论交流。

最新文章

  1. ajaxform使用
  2. 玩转Android Camera开发(一):Surfaceview预览Camera,基础拍照功能完整demo
  3. framework&amp;&amp;library&#39;s root
  4. phpExcel导出excel的类,每步都有说明
  5. linq to Entity 数据库除了有主键还有唯一索引,是不是不能更新
  6. ASP.NET MVC程序传值方式:ViewData,ViewBag,TempData和Session
  7. Qt中的串口编程之三
  8. node c++多线程插件 第一天 c++线程相关函数
  9. asp.net 程序,当发生找不到文件的错误时,如何正确定位是哪个文件?
  10. iOS加密算法总结
  11. mybatis xml &lt; &gt;
  12. 解决macOS因为它来自身份不明的开发者,不显示允许任何来源 –安装文件下载损坏问题
  13. LeetCode算法题-Power Of Two(Java实现)
  14. Centos6下安装中文字体
  15. Java 基础学习总结(一)抽象类和接口
  16. 第2章 线性表《C#数据结构和算法》
  17. 编写一个c++工程
  18. MP算法、OMP算法及其在人脸识别的应用
  19. 公钥与私钥对HTTPS的理解(数字证书的需要)
  20. Hadoop面试链接

热门文章

  1. zookeeper的JAVA API使用
  2. GateWay配置使用
  3. 题目要求:传入数组 内容为[[&#39;lisi&#39;,&#39;男&#39;,&#39;27&#39;],[&#39;wangwu&#39;,&#39;男&#39;,18],[&#39;zhaoliu&#39;,&#39;男&#39;,&#39;30&#39;]],将此二维数组转化为一维数组,创建自定义函数完成
  4. 一比一还原axios源码(五)—— 拦截器
  5. Docker 学习之命令篇
  6. 面试突击32:为什么创建线程池一定要用ThreadPoolExecutor?
  7. Bert不完全手册3. Bert训练策略优化!RoBERTa &amp; SpanBERT
  8. 如何绑定msix中断 cpu亲和性
  9. springcloud学习00-开发工具相关准备
  10. STM32控制永磁同步电机 | FOC电机控制算法概述