【版权声明】未经博主同意,谢绝转载!(请尊重原创,博主保留追究权)

https://www.cnblogs.com/cnb-yuchen/p/18002823

出自【进步*于辰的博客

参考笔记一,P83;笔记二,P75.4。

1、概述

什么是代理模式?“代理模式”指通过为目标对象(原代码)创建代理对象,将附加功能(附加代码)注入目标对象的方法,从而实现附加功能的设计模式,分为静态代理和动态代理。

什么是静态代理?“静态代理”指为目标类手动创建代理类的代理方式。

什么是动态代理?“动态代理”指在不变动原代码的情况下,通过反射动态创建代理对象的代理方式。(注:“反射”是动态代理的底层,不可见)

2、静态代理的两种形式

2.1 面向接口

特点:目标对象与代理对象隶属于同一接口。

看下述代码:

1、公共接口:目标类和代理类的公共接口。

interface IService {
int transfer(int money);
}

2、目标类。

class Target implements IService {
@Override
public int transfer(int money) {
System.out.println("转账金额:" + money);
return 1;
}
}

3、代理类。

class Proxy implements IService {
private Target target;
public Proxy(Target target) {
this.target = target;
} @Override
public int transfer(int score) {
System.out.println("打开事务");// 附加功能
int x = target.transfer(score);
System.out.println("关闭事务");
return x;
}
}

测试。

class Test {
public static void main(String[] args) {
Proxy proxy = new Proxy(new Target());// 创建代理对象
int x = proxy.transfer(10);
if (x > 0)
System.out.println("转账成功");
else
System.out.println("转账失败");
}
}

测试结果:

2.2 面向继承

特点:目标对象与代理对象是继承关系,代理对象继承于目标对象。

看下述代码:

1、目标类。

class Target {
public int transfer(int money) {
System.out.println("转账金额:" + money);
return 1;
}
}

3、代理类。

class Proxy extends Target {
@Override
public int transfer(int money) {
System.out.println("打开事务");// 附加功能
int x = super.transfer(money);
System.out.println("关闭事务");
return x;
}
}

测试。

class Test {
public static void main(String[] args) {
Proxy proxy = new Proxy();// 创建代理对象
int x = proxy.transfer(20);
if (x > 0)
System.out.println("转账成功");
else
System.out.println("转账失败");
}
}

测试结果:

3、动态代理的两种形式

PS:静态代理需要手动创建代理类,进而创建代理对象,很冗余。换个思路,反射可以根据 Class 信息创建实例,故可以通过反射为目标对象创建代理对象,则无需创建代理类,这就是“动态代理”。

3.1 JDK动态代理

特点:面向接口,隶属于Java API

看下述代码:

1、公共接口。

/**
* 目标对象与代理对象的公共接口
* 注:因为JDK动态代理面向接口,故目标对象和代理对象实现于同一接口
*/
interface IService {
int transfer(int money);
}

2、目标类。

class Target implements IService {
@Override
public int transfer(int money) {
System.out.println("转账金额:" + money);
return 1;
}
}

测试。

class Test {
public static void main(String[] args) {
Target target = new Target();
/**
* 通过 newProxyInstance() 创建代理对象
* 第一个参数是目标对象的类加载器,指定为哪个目标对象创建代理对象;
* 第二个参数是目标对象实现的接口,指定目标对象和代理对象的公共接口;
* 第三个参数是拦截器对象,指定用哪个拦截器来创建代理对象,需要实现 InvocationHandler 接口。
*/
// 由于代理对象 proxy 是通过反射创建于JVM,并无类存在,故要上转为公共接口 IService
IService proxyInstance = (IService) Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InvocationHandler() {
/**
* 代理(调用 transfer())时执行的方法
* @param proxy 代理对象,即 proxyInstance,暂不知如何使用
* @param method 目标对象的 Method 的 class 对象
* @param args 目标对象的 Method 的形参数组
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("打开事务");// 附加功能
// invoke() 是反射中 Method 对象执行时调用的方法,故动态代理是通过反射调用目标对象被代理的方法
Object result = method.invoke(target, args);
System.out.println("关闭事务");
return result;
}
});// 创建代理对象
int x = proxyInstance.transfer(50);
if (x > 0)
System.out.println("转账成功");
else
System.out.println("转账失败");
}
}

测试结果:



可以用Lambda表达式进行简化。

3.2 Cglib动态代理

特点:面向继承,隶属于Spring API

看下述代码:

1、目标类。

class Target {
public int transfer(int money) {
System.out.println("转账金额:" + money);
return 1;
}
}

2、代理类。

/**
* Cglib动态代理类,需实现接口 MethodInterceptor
*/
class DynamicProxy implements MethodInterceptor {
private Object target;
public DynamicProxy(Object target) {
this.target = target;
}
public Object createProxy() {
Enhancer proxy = new Enhancer();// Enhancer 类是一种类生成器
proxy.setCallback(this);// 设置拦截器,指定回对象为自身(暂不理解)
proxy.setSuperclass(target.getClass());// 设置父类,指定为哪个目标对象创建代理对象
return proxy.create();// 创建代理对象
} /**
* 代理(调用 transfer())时执行的方法
* @param proxy 代理对象,即 proxyInstance,暂不知如何使用
* @param method 目标对象的 Method 的 class对象
* @param args 目标对象的 Method 的参数数组
* @param methodProxy 代理方法,即 Target.transfer(),暂不知如何使用
*/
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("打开事务");// 附加功能
// invoke() 是反射中 Method 对象执行时调用的方法,故动态代理是通过反射调用目标对象被代理的方法
Object result = method.invoke(target, args);
System.out.println("关闭事务");
return result;
}
}

测试。

class Test {
public static void main(String[] args) {
Target target = new Target();
Target proxyInstance = (Target) new DynamicProxy(target).createProxy();
int x = proxyInstance.transfer(100);
if (x > 0)
System.out.println("转账成功");
else
System.out.println("转账失败");
}
}

测试结果:

同样可以用Lambda表达式进行简化,不过代理对象的创建(proxy.create())需要对 Enhancer 类的属性进行一些设置,故进行了封装。

注意:JDK动态代理和Cglib动态代理皆可拦截所有方法,包括:toString()hashcode()。不能拦截由 final 修饰方法,如:getClass()

最后

本文中的例子是为了阐述静态代理和动态代理的实现思想、方便大家理解而简单举出的,不一定有实用性,大家自行扩展。

本文完结。

[Java]静态代理、动态代理(基于JDK1.8)的更多相关文章

  1. java静态和动态代理原理

    一.代理概念 为某个对象提供一个代理,以控制对这个对象的访问. 代理类和委托类有共同的父类或父接口,这样在任何使用委托类对象的地方都可以用代理对象替代.代理类负责请求的预处理.过滤.将请求分派给委托类 ...

  2. java 笔记(3) —— 动态代理,静态代理,cglib代理

    0.代理模式 代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口. 代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后处理消息等. 代理类与委托类之间通常会存 ...

  3. 轻松理解 Java 静态代理/动态代理

    目录 什么是代理模式 定义 代理模式的主要角色 优点 缺点 静态代理 动态代理 JDK原生动态代理 例子 分析 小结 CGLIB动态代理 例子 分析 final类型 其他方案 尾声 理解Java动态代 ...

  4. 杨晓峰-Java核心技术-6 动态代理 反射 MD

    目录 第6讲 | 动态代理是基于什么原理? 典型回答 考点分析 知识扩展 反射机制及其演进 动态代理 精选留言 Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAnd ...

  5. 一文读懂Java中的动态代理

    从代理模式说起 回顾前文: 设计模式系列之代理模式(Proxy Pattern) 要读懂动态代理,应从代理模式说起.而实现代理模式,常见有下面两种实现: (1) 代理类关联目标对象,实现目标对象实现的 ...

  6. 8、Spring教程之静态代理/动态代理

    为什么要学习代理模式,因为AOP的底层机制就是动态代理! 代理模式: 静态代理 动态代理 学习aop之前 , 我们要先了解一下代理模式! 静态代理 静态代理角色分析 抽象角色 : 一般使用接口或者抽象 ...

  7. Java 反射 设计模式 动态代理机制详解 [ 转载 ]

    Java 反射 设计模式 动态代理机制详解 [ 转载 ] @author 亦山 原文链接:http://blog.csdn.net/luanlouis/article/details/24589193 ...

  8. Java学习笔记--动态代理

    动态代理 1.JDK动态代理 JDK1.3之后,Java提供了动态代理的技术,允许开发者在运行期创建接口的代理实例.JDK的动态代理主要涉及到java.lang.reflect包中的两个类:Proxy ...

  9. 【SSH系列】静态代理&&动态代理

    从设计模式说起 代理模式是二十三中设计模式中的一种,代理模式就是指由一个代理主题来操作真实的主题,真实的主题执行具体的业务操作,而代理主题负责其她相关业务,简而言之,代理模式可以由以下三个部分组成: ...

  10. 细说java系统之动态代理

    代理模式 在深入学习动态代理之前,需要先掌握代理模式.只有深刻理解了代理模式的应用,才能充分理解Java动态代理带来的便利. 在生活中存在许多使用"代理模式"的场景,比如:村里的张 ...

随机推荐

  1. JS leetcode x 的平方根 题解分析

    壹 ❀ 引 这几天心情复杂,也不知道形容.做道题吧,其实是上周的题,一直没整理,比较巧的是,这也是我同学17年去PPTV面试时遇到的一题,题目来自leetcode69. x 的平方根,题目描述如下: ...

  2. JS leetcode 加一 题解分析

    壹 ❀ 引 今天是刷leetcode的第三天,根据推荐优先刷数据结构相关的卡片,先把数据结构知识体系建立起来,不然就是题目无从下手答案也看不懂的尴尬局面.那么今天的题目是加一,老规矩,先记录自己的解题 ...

  3. 吴X凡绯闻女友小怡同学被骂到清空社交平台?各大平台连敏感词库都没有的吗?

    敏感词都没有的平台 最近某加拿大籍贯的 rapper 被曝私生活不检点,且极有可能涉及诱X未成年少女,成为一个 raper. 当然至于是否属实,其实一个人是否是海王,微信.QQ 聊天记录里面记得清清楚 ...

  4. Java并发编程实例--8.在线程中处理未检查异常

    java中有两类异常: 已检查异常:这类异常编译器要求开发者必须在代码中通过throws去处理. 例如:IOException和ClassNotFoundException. 未检查异常:不必显式的在 ...

  5. vivo 短视频体验与成本优化实践

    作者:来自 vivo 互联网短视频研发团队 本文根据蔡创业.马运杰老师在"2023 vivo开发者大会"现场演讲内容整理而成. 在线点播场景,播放体验提升与成本优化是同等重要的两件 ...

  6. 【Android 逆向】【攻防世界】app1

    1. apk安装到手机, 老套路了 2. jadx打开 this.btn.setOnClickListener(new View.OnClickListener() { // from class: ...

  7. Redis搭建Sentinel实验环境

    环境准备 在物理机上启动3台虚拟机,IP地址分别为:192.168.56.4,192.168.56.5,192.168.56.6. 1.确保3台虚拟机的网络是相互联通的. 2.确保已经在3台虚拟机上安 ...

  8. Acrobat 教程

    https://helpx.adobe.com/cn/acrobat/using/pdf-form-field-properties.html

  9. SpringBoot使用令牌桶算法+拦截器+自定义注解+自定义异常实现简单的限流

    令牌桶 在高并发的情况下,限流是后端常用的手段之一,可以对系统限流.接口限流.用户限流等,本文就使用令牌桶算法+拦截器+自定义注解+自定义异常实现限流的demo. 令牌桶思想 大小固定的令牌桶可自行以 ...

  10. typing模块中Protocol协议的使用

    说明 在 Python 的 typing 模块中,Protocol 是一个用于定义协议(Protocol)的类. 协议是一种形式化的接口,定义了一组方法或属性的规范,而不关心具体的实现.Protoco ...