Java 动态代理模式浅析
代理设计模式的UML图:
我将首先介绍Java中的各种代理实现方法
Java代理设计模式 - 静态代理
这个例子非常简单,只有一个方法wirteCode
的接口IDeveloper
:
public interface IDeveloper {
public void writeCode();
}
// 实现这个接口的类:
public class Developer implements IDeveloper{
private String name;
public Developer(String name){
this.name = name;
}
@Override
public void writeCode() {
System.out.println("Developer " + name + " writes code");
}
}
测试代码:
public class DeveloperTest {
public static void main(String[] args) {
IDeveloper jerry = new Developer("Jerry");
jerry.writeCode();
}
}
测试输出:
Developer Jerry writes code
现在麻烦的是,Jerry的领导因为团队中的开发者像Jerry一样没有编写技术文档,所以并不满意。经过讨论后,整个团队达成协议,相关文档必须与代码一起提供。
为了迫使开发人员编写文档而不直接对现有的实现类Developer进行修改,现在就可以使用静态代理来实现:
// 创建一个和Developer类实现同样接口的类
public class DeveloperProxy implements IDeveloper{
private IDeveloper developer;
// 引用Developer类对象
public DeveloperProxy(IDeveloper developer){
this.developer = developer;
}
@Override
public void writeCode() {
System.out.println("Write documentation...");
this.developer.writeCode();
}
}
测试代码:
public class DeveloperTest {
public static void main(String[] args) {
Developer jerry = new Developer("jerry");
DeveloperProxy jerryproxy = new DeveloperProxy(jerry);
jerryproxy.writeCode();
}
}
测试输出:
Write documentation...
Developer jerry writes code
静态代理的优点
假设你希望在不修改原始类代码的情况下增强现有的稳定实现,你可以创建一个代理类,并将原始实现封装为代理中的私有属性。增强的功能是在代理类中完成的,对现有的代码是完全透明的。回到上面的示例,客户端代码并不关心它用来调用writeCode()
方法的变量是否指向真正的开发人员或开发人员代码。
优点:
- 易于实施和理解
- 原始实现与其代理之间的关系在编译时已经确定,运行时没有额外的开销。
静态代理的缺点
我们仍然使用这个例子来说明。
假设现在缺失文档的问题在QA同事中仍然存在。如果我们想通过静态代理来解决这个问题,那么必须引入另一个代理类。
这是测试人员的接口:
public interface ITester {
public void doTesting();
}
// ITester 接口的实现类:
public class Tester implements ITester {
private String name;
public Tester(String name){
this.name = name;
}
@Override
public void doTesting() {
System.out.println("Tester " + name + " is testing code");
}
}
测试人员代理:
public class TesterProxy implements ITester{
private ITester tester;
public TesterProxy(ITester tester){
this.tester = tester;
}
@Override
public void doTesting() {
System.out.println("Tester is preparing test documentation...");
tester.doTesting();
}
}
测试代码和输出:
从Tester代理的源代码中我们可以很容易的观察到它与开发人员具有完全相同的逻辑。如果又过了一段时间,我们必须为软件交付过程中的其他同事建立文档,我们必须一次又一次的引入新的静态代理类,这会导致静态代理类变得十分庞大。
Java中的动态代理 - 调用处理器
现在我通过代理类EnginnerProxy
来为所有的具体角色提供代理服务,而不是单独为每个原始实现类设置专用的静态代理类。
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class EnginnerProxy implements InvocationHandler
{
Object obj;
public Object bind(Object obj)
{
this.obj = obj;
return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj
.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable
{
System.out.println("Enginner writes document");
Object res = method.invoke(obj, args);
return res;
}
}
主要笔记:
- 不是从具有业务接口(IDeveloper或ITester)的专用接口继承,而是在此变体中,通过代理继承自JDK提供的技术接口
InvocationHandler
。 - 为了确保通用代理可以适用于所有可能的具体实现类,在代理中定义了具有泛型类型的
Object
变量。 - 调用代理实例的接口方法时,它将被
InvocationHandler
中定义的invoke
方法拦截,其中由应用程序开发人员声明的增强逻辑与由Java Reflection
调用的原始逻辑一起调用。
下面是如何使用InvocationHandler设计的动态代理和测试输出:
动态代理类的限制
虽然这个变体成功的避免了静态代理中的重复缺陷,但是它仍然有一个局限性,它无法使用不是从接口继承的实现类,就是说,使用动态代理类,原始类必须先要实现一个或多个接口,这个接口也就是代理接口。
考虑下面的例子,产品所有者没有实现任何接口:
public class ProductOwner {
private String name;
public ProductOwner(String name){
this.name = name;
}
public void defineBackLog(){
System.out.println("PO: " + name + " defines Backlog.");
}
}
以下代码在IDE中没有任何语法错误:
ProductOwner po = new ProductOwner("Ross");
ProductOwner poProxy = (ProductOwner) new EnginnerProxy().bind(po);
poProxy.defineBackLog();
不幸的是编译时报出了以下错误:
Java 动态代理模式浅析的更多相关文章
- Java动态代理模式浅析
Java代理设计模式 - 静态代理 Java中的动态代理 - 调用处理器 代理设计模式的UML图: 我将首先介绍Java中的各种代理实现方法 Java代理设计模式 - 静态代理 这个例子非常简单,只有 ...
- JAVA动态代理模式(从现实生活角度理解代码原理)
所谓动态代理,即通过代理类:Proxy的代理,接口和实现类之间可以不直接发生联系,而可以在运行期(Runtime)实现动态关联. java动态代理主要是使用java.lang.reflect包中的两个 ...
- 关于java动态代理模式
1. 动态代理 动态代理就是通过代理类是代理类与相关接口不直接发生联系,而在运行期(Runtime)实现动态关联. 动态代理主要用到java.lang.reflect包中的两个类,Invocation ...
- java动态代理模式
java动态代理机制详解 Spring的核心AOP的原理就是java的动态代理机制. 在java的动态代理机制中,有两个重要的类或接口: 1.InvocationHandler(Interface): ...
- java 动态代理模式(jdk和cglib)
package proxy.dynamicproxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Met ...
- java jdk动态代理模式举例浅析
代理模式概述 代理模式是为了提供额外或不同的操作,而插入的用来替代”实际”对象的对象,这些操作涉及到与”实际”对象的通信,因此代理通常充当中间人角色. java中常用的动态代理模式为jdk动态代理和c ...
- JAVA代理模式与动态代理模式
1.代理模式 所谓代理,就是一个人或者一个机构代表另一个人或者另一个机构采取行动.在一些情况下,一个客户不想或者不能够直接引用一个对象,而代理对象可以在客户端和目标对象之前起到中介的作用.代理模式给某 ...
- Java设计模式系列之动态代理模式(转载)
代理设计模式 定义:为其他对象提供一种代理以控制对这个对象的访问. 动态代理使用 java动态代理机制以巧妙的方式实现了代理模式的设计理念. 代理模式示例代码 public interface Sub ...
- Java静态代理与动态代理模式的实现
前言: 在现实生活中,考虑以下的场景:小王打算要去租房,他相中了一个房子,准备去找房东洽谈相关事宜.但是房东他很忙,平时上班没时间,总找不到时间去找他,他也没办法.后来,房东想了一个办法,他找到 ...
随机推荐
- 20155320《网络对抗》MSF基础应用
20155320<网络对抗>MSF基础应用 基础问题回答 用自己的话解释什么是exploit,payload,encode 于exploit,我觉得exploit是利用一些工具和方法,通过 ...
- Centos 定时任务发送smtp邮件
接着上一篇文章...... 1.首先创建一个sheel的脚本命令,我是在home文件夹下面创建的命令: touch a.sh 2.编辑a.sh脚本 vim a.sh ,键入键盘 i 键 准备插入 ...
- python 回溯法 子集树模板 系列 —— 14、最长公共子序列(LCS)
问题 输入 第1行:字符串A 第2行:字符串B (A,B的长度 <= 1000) 输出 输出最长的子序列,如果有多个,随意输出1个. 输入示例 belong cnblogs 输出示例 blog ...
- asp.net mvc2+nhibernate实体类映射问题之“尝试创建Controller类型的控制器时出错请确保控制器具有无参数公共构造函数”
程序出了问题,解决后发现如此简单,犯的错误是如此的低级啊,特此记录! 运行程序总是在浏览器中看到一片空白,什么也没有,用application_error跟踪发现抓出一个这样的异常 然后浏览器中就是这 ...
- Windows下面的常用的快捷键
最小化的快捷键: 最小化当前窗口:Alt+ESC 还原刚刚最小化的窗口:Alt+Tab(次快捷键组合可以在多个窗口中切换) 显示桌面,切换之前的桌面:Win+D 在浏览器页面之间切换:Ctrl+T ...
- JAVAWEB 项目注册登录模块问题总结
tomcat: 假如tomcat服务器启动出现错误,那就可能是servlet或代码的原因 tomcat服务器出现不能访问页面的情况,可以在eclipse tomcat服务器设置里设置为共享服务器模式 ...
- 设计模式 笔记 观察者模式 Observer
//---------------------------15/04/27---------------------------- //Observer 观察者模式----对象行为型模式 /* 1:意 ...
- EditText点击出现光标但不弹出软键盘
3.0以下版本可以用editText.setInputType(InputType.TYPE_NULL)来实现.或者设置editText.setKeyListener(null)来实现. 3.0以上版 ...
- Asp.Net_<asp:RadioButtonList
<asp:RadioButtonList runat="server" ID="RadioButtonList1" RepeatDirection ...
- 说说 Python 的变量以及简单数据类型
1 变量 先来看一个示例: news="我国第一个人工智能规划问世"print(news) 运行结果: 可以看出使用 Python 定义变量很简单,甚至都不需要指定变量的类型. 1 ...