代理模式

代理模式的作用是:为其他对象提供一种代理以控制对这个对象的访问。在考虑到性能或安全等因素的情况下,一个客户不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。

Proxy代理类:代理对象角色内部含有对真实对象的引用,从而可以操作真实对象,同时代理对象提供与真实对象相同的接口以便在任何时刻都能代替真实对象。同时,代理对象可以在执行真实对象操作时,附加其他的操作,相当于对真实对象进行封装。

Target目标类:代理角色所代表的真实对象,是我们最终要引用的对象。

动态代理

假如要按照上述的方法使用代理模式,那么真实角色必须是事先已经存在的,并将其作为代理对象的内部属性。但是实际使用时,一个真实角色对应一个代理角色,假如大量使用会导致类的急剧膨胀;此外,假如事先并不知道真实角色,该如何使用代理呢?这个问题可以通过Java的动态代理类来解决。

java动态类的实现主要通过java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口。

Proxy类主要用来获取动态代理对象,InvocationHandler接口用来约束调用者实现。

Proxy 提供用于创建动态代理类和实例的静态方法,它还是由这些方法创建的所有动态代理类的超类。

static InvocationHandler getInvocationHandler(Object proxy)
返回指定代理实例的调用处理程序。
static Class<?> getProxyClass(ClassLoader loader, Class<?>... interfaces)

返回代理类的 java.lang.Class 对象,并向其提供类加载器和接口数组。
static boolean isProxyClass(Class<?> cl)

当且仅当指定的类通过 getProxyClass 方法或
newProxyInstance 方法动态生成为代理类时,返回 true。
static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)

返回一个指定接口的代理类实例,该接口可以将方法调用指派到指定的调用处理程序。
参数:
loader - 定义代理类的类加载器
interfaces - 代理类要实现的接口列表
h - 指派方法调用的调用处理程序

InvocationHandler 是代理实例的调用处理程序实现的接口。每个代理实例都具有一个关联的调用处理程序。对代理实例调用方法时,将对方法调用进行编码并将其指派到它的调用处理程序的 invoke 方法。

Object invoke(Object proxy, Method method, Object[] args)
在代理实例上处理方法调用并返回结果。

Object proxy:指被代理的对象。 
Method method:要调用的方法 
Object[] args:方法调用时所需要的参数

根据自己理解画的动态代理原理图

示例代码

写一个动态代理,其内部可以实现 ArrayList 和HashMap中完全相同的功能,并可以计算每个方法运行的时间。

定义代理工具类,可以根据目标和建议的不同生成不同的代理类对象。

 import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;
public class ProxyUtil {
//抽取方法,接收不同的目标和建议,返回一个代理
public static Object getProxy(final Object target,final Advice advice) {
/*参数:
定义代理类的类加载器
代理类要实现的接口列表
指派方法调用的调用处理程序*/
Object proxy = Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InvocationHandler(){ public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
advice.beforeMethod(method);
Object retVal = method.invoke(target, args);
advice.afterMethod(method);
return retVal;
}
}
);
return proxy;
}
}

定义建议接口

 import java.lang.reflect.Method;
public interface Advice {
void beforeMethod(Method method);
void afterMethod(Method method);
}

自定义建议类实现建议接口

 import java.lang.reflect.Method;
public class MyAdvice implements Advice {
long beginTime = 0;
public void afterMethod(Method method) {
long endTime = System.currentTimeMillis();
System.out.println("["+method.getName() + "]耗时" + (endTime - beginTime)+"毫秒");
}
public void beforeMethod(Method method) {
beginTime = System.currentTimeMillis();
}
}

客户端测试

 import java.util.*;
class TargetDemo
{
public static void main(String[] args)
{
//定义target
List<String> target = new ArrayList<String>();
//获取target的代理类对象
List proxy = (List)ProxyUtil.getProxy(target,new MyAdvice());
//代理类对象实现添加等方法
proxy.add("hello");
proxy.add("hehe");
proxy.add("hello");
System.out.println("size="+proxy.size());
for(Object tar : proxy){
System.out.println(tar);
} System.out.println("================"); Map<String,Integer> target1 = new HashMap<String,Integer>();
Map proxy1 = (Map)ProxyUtil.getProxy(target1,new MyAdvice());
proxy1.put("zhangsan1",21);
proxy1.put("zhangsan2",22);
proxy1.put("zhangsan2",22);
System.out.println("size="+proxy1.size());
Set<Map.Entry<String,Integer>> entrySet = proxy1.entrySet(); Iterator<Map.Entry<String,Integer>> it = entrySet.iterator(); while(it.hasNext())
{
Map.Entry<String,Integer> me = it.next();
String key = me.getKey();
Integer value = me.getValue(); System.out.println(key+"="+value);
}
}
}

运行结果

---------- 运行 ----------
[add]耗时1毫秒
[add]耗时0毫秒
[add]耗时0毫秒
[size]耗时0毫秒
size=3
[iterator]耗时1毫秒
hello
hehe
hello
================
[put]耗时0毫秒
[put]耗时0毫秒
[put]耗时0毫秒
[size]耗时0毫秒
size=2
[entrySet]耗时0毫秒
zhangsan1=21
zhangsan2=22

输出完成 (耗时 0 秒) - 正常终止

java-代理模式及动态代理的更多相关文章

  1. (转)轻松学,Java 中的代理模式及动态代理

    背景:讲到反射机制,肯定会想到动态代理. 轻松学,Java 中的代理模式及动态代理 代理模式可以在不修改被代理对象的基础上,通过扩展代理类,进行一些功能的附加与增强.值得注意的是,代理类和被代理类应该 ...

  2. Java设计模式-代理模式之动态代理(附源代码分析)

    Java设计模式-代理模式之动态代理(附源代码分析) 动态代理概念及类图 上一篇中介绍了静态代理,动态代理跟静态代理一个最大的差别就是:动态代理是在执行时刻动态的创建出代理类及其对象. 上篇中的静态代 ...

  3. Java代理模式之动态代理

    动态代理类的源码是程序在运行期间由JVM根据反射等机制动态生成的,所以不存在代理类的字节码文件.代理角色和真实角色的联系在程序运行时确定! Java中有两种动态代理,一种是JDK自带的,另一种的CGL ...

  4. JAVA代理模式与动态代理模式

    1.代理模式 所谓代理,就是一个人或者一个机构代表另一个人或者另一个机构采取行动.在一些情况下,一个客户不想或者不能够直接引用一个对象,而代理对象可以在客户端和目标对象之前起到中介的作用.代理模式给某 ...

  5. Java的三种代理模式(Spring动态代理对象)

    Java的三种代理模式 1.代理模式 代理(Proxy)是一种设计模式,提供了对目标对象另外的访问方式;即通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩 ...

  6. java代理模式及动态代理类

     1.      代理模式 代理模式的作用是:为其他对象提供一种代理以控制对这个对象的访问.在某些情况下,一个客户不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用 ...

  7. 代理模式-jdk动态代理

    IDB package com.bjpowernode.proxy; /** * 代理类和目标类都必须使用同一个接口. */ public interface IDB { int insert(); ...

  8. 动态代理模式——JDK动态代理

    今天,我就来讲一下动态代理的设计模式. 动态代理的意义在于生成一个代理对象,来代理真实对象,从而控制真实对象的访问.操作动态代理需要两个步骤:一.代理对象和真实对象建立代理关系.二.实现代理对象的代理 ...

  9. 代理模式与动态代理之JDK实现和CGlib实现

    静态代理 静态代理中的代理类和委托类会实现同一接口或是派生自相同的父类. 由业务实现类.业务代理类 两部分组成.业务实现类 负责实现主要的业务方法,业务代理类负责对调用的业务方法作拦截.过滤.预处理, ...

  10. Java 中的代理模式及动态代理

    原文:https://blog.csdn.net/briblue/article/details/73928350

随机推荐

  1. 修复 Firefox 下本地使用 Bootstrap 3 时 glyphicon 不显示问题

    本地开发使用 Firefox 调试,遇到了 glyphicon 图标不显示的问题,期初以为是路径问题,搜索一大圈后找到了答案,原来这是一个安全性的问题,于是问题就好办了,解决方案如下: 1. 在Fir ...

  2. [html]经验集

    禁止默认的右键菜单: window.document.oncontextmenu = function(){ return false;} WebBrowser 控件用法:(手动填充内容) // 首先 ...

  3. ios 关于状态栏的一些小知识

    一.改变状态栏颜色 状态栏分为两种颜色,默认的是黑色,这里想要改为白色: 分为两步: 第一步:在项目中找到plist文件,添加View controller-based status bar appe ...

  4. Android Studio使用org.apache.http报错

    Android Studio使用org.apache.http报错需要加上这句话:useLibrary 'org.apache.http.legacy'

  5. notepad++ 离线插件下载

    http://www.cnblogs.com/findumars/p/5180562.html

  6. Coursera Machine Learning 作业答案脚本 分享在github上

    Github地址:https://github.com/edward0130/Coursera-ML

  7. [刘阳Java]_MyBatis_映射文件的resultMap标签入门_第4讲

    <resultMap>:用于解决实体类中属性和表字段名不相同的问题 id:表示当前<resultMap>标签的唯一标识 result:定义表字段和实体类属性的对应关系 prop ...

  8. 一次诡异的TOMCAT启动故障的解决

    该系统采用TOMCAT+SSH+Linux+Proxool连接池, 以前数据库是本地连接. 后换数据库远端连接,最近老是启动不了. 1.怀疑是proxool连接池没有自动断开后恢复.尝试解决,不是这个 ...

  9. Javascript 截取2位小数

    今天在处理数据时,前台界面金额需要保留两位小数,所以只能使用Javascript 来进行截取. var regex = /([0-9]+\.[0-9]{2})[0-9]*/; var localMon ...

  10. 清空stringbuilder

    大家知道对于字符串频繁拼接是使用stringbuilder.Append方法比使用string+=方法效率高很多,但有时需要清空stringbuilder时却不知道怎么清空,因为它没有clear或em ...