代理模式是aop编程的基础,其主要作用是操作对象,并将你需要的新功能切入若干个你想要的切入点,静态代理模式比较简单,但是缺点比较大,这里就不上代码了,下面写上动态代理模式的代码(jdk方式,而不是采用cglib):

 /**
* 主题接口
* @author TMAC-J
*
*/
interface Subject {
void write();
} public class SubjectImpl implements Subject{ @Override
public void write() {
System.out.println("---write---");
} } import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method; public class MyInvocationHandler implements InvocationHandler{ private Subject Subject = null; public MyInvocationHandler(Subject subject) {
this.Subject = subject;
} @Override
public Object invoke(Object object, Method method, Object[] objects) throws Throwable {
System.out.println("--before write--");
Object result = method.invoke(Subject, objects);
System.out.println("--after write--");
return result;
} } import java.lang.reflect.Proxy; public class Main {
public static void main(String[] args) {
Subject subject = new SubjectImpl();
MyInvocationHandler myInvocationHandler = new MyInvocationHandler(subject);
Subject subjectProxy = (Subject)Proxy.newProxyInstance(Subject.class.getClassLoader(), new Class[]{Subject.class}, myInvocationHandler);
subjectProxy.write();
}
}

  

--before write--
---write---
--after write--

以上是运行结果

jdk动态代理实现的原理如下:

动态代理内部实现

首先来看看类Proxy的代码实现 Proxy的主要静态变量

// 映射表:用于维护类装载器对象到其对应的代理类缓存
private static Map loaderToCache = new WeakHashMap(); // 标记:用于标记一个动态代理类正在被创建中
private static Object pendingGenerationMarker = new Object(); // 同步表:记录已经被创建的动态代理类类型,主要被方法 isProxyClass 进行相关的判断
private static Map proxyClasses = Collections.synchronizedMap(new WeakHashMap()); // 关联的调用处理器引用
protected InvocationHandler h;

Proxy的构造方法

// 由于 Proxy 内部从不直接调用构造函数,所以 private 类型意味着禁止任何调用
private Proxy() {} // 由于 Proxy 内部从不直接调用构造函数,所以 protected 意味着只有子类可以调用
protected Proxy(InvocationHandler h) {this.h = h;}

Proxy静态方法newProxyInstance

public static Object newProxyInstance(ClassLoader loader, Class<?>[]interfaces,InvocationHandler h) throws IllegalArgumentException {
// 检查 h 不为空,否则抛异常
if (h == null) {
throw new NullPointerException();
} // 获得与指定类装载器和一组接口相关的代理类类型对象
Class cl = getProxyClass(loader, interfaces); // 通过反射获取构造函数对象并生成代理类实例
try {
Constructor cons = cl.getConstructor(constructorParams);
return (Object) cons.newInstance(new Object[] { h });
} catch (NoSuchMethodException e) { throw new InternalError(e.toString());
} catch (IllegalAccessException e) { throw new InternalError(e.toString());
} catch (InstantiationException e) { throw new InternalError(e.toString());
} catch (InvocationTargetException e) { throw new InternalError(e.toString());
}
}

ProxygetProxyClass方法调用ProxyGenerator的 generateProxyClass方法产生ProxySubject.class的二进制数据:

public static byte[] generateProxyClass(final String name, Class[] interfaces)

我们可以import sun.misc.ProxyGenerator,调用 generateProxyClass方法产生binary data,然后写入文件,最后通过反编译工具来查看内部实现原理。 反编译后的ProxySubject.java Proxy静态方法newProxyInstance

import java.lang.reflect.*;
public final class ProxySubject extends Proxy
implements Subject
{
private static Method m1;
private static Method m0;
private static Method m3;
private static Method m2;
public ProxySubject(InvocationHandler invocationhandler)
{
super(invocationhandler);
}
public final boolean equals(Object obj)
{
try
{
return ((Boolean)super.h.invoke(this, m1, new Object[] {
obj
})).booleanValue();
}
catch(Error _ex) { }
catch(Throwable throwable)
{
throw new UndeclaredThrowableException(throwable);
}
}
public final int hashCode()
{
try
{
return ((Integer)super.h.invoke(this, m0, null)).intValue();
}
catch(Error _ex) { }
catch(Throwable throwable)
{
throw new UndeclaredThrowableException(throwable);
}
}
public final void doSomething()
{
try
{
super.h.invoke(this, m3, null);
return;
}
catch(Error _ex) { }
catch(Throwable throwable)
{
throw new UndeclaredThrowableException(throwable);
}
}
public final String toString()
{
try
{
return (String)super.h.invoke(this, m2, null);
}
catch(Error _ex) { }
catch(Throwable throwable)
{
throw new UndeclaredThrowableException(throwable);
}
}
static
{
try
{
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] {
Class.forName("java.lang.Object")
});
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
m3 = Class.forName("Subject").getMethod("doSomething", new Class[0]);
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
}
catch(NoSuchMethodException nosuchmethodexception)
{
throw new NoSuchMethodError(nosuchmethodexception.getMessage());
}
catch(ClassNotFoundException classnotfoundexception)
{
throw new NoClassDefFoundError(classnotfoundexception.getMessage());
}
}
}

ProxyGenerator内部是如何生成class二进制数据,可以参考源代码。

private byte[] generateClassFile() {
/*
* Record that proxy methods are needed for the hashCode, equals,
* and toString methods of java.lang.Object. This is done before
* the methods from the proxy interfaces so that the methods from
* java.lang.Object take precedence over duplicate methods in the
* proxy interfaces.
*/
addProxyMethod(hashCodeMethod, Object.class);
addProxyMethod(equalsMethod, Object.class);
addProxyMethod(toStringMethod, Object.class);
/*
* Now record all of the methods from the proxy interfaces, giving
* earlier interfaces precedence over later ones with duplicate
* methods.
*/
for (int i = 0; i < interfaces.length; i++) {
Method[] methods = interfaces[i].getMethods();
for (int j = 0; j < methods.length; j++) {
addProxyMethod(methods[j], interfaces[i]);
}
}
/*
* For each set of proxy methods with the same signature,
* verify that the methods' return types are compatible.
*/
for (List<ProxyMethod> sigmethods : proxyMethods.values()) {
checkReturnTypes(sigmethods);
}
/* ============================================================
* Step 2: Assemble FieldInfo and MethodInfo structs for all of
* fields and methods in the class we are generating.
*/
try {
methods.add(generateConstructor());
for (List<ProxyMethod> sigmethods : proxyMethods.values()) {
for (ProxyMethod pm : sigmethods) {
// add static field for method's Method object
fields.add(new FieldInfo(pm.methodFieldName,
"Ljava/lang/reflect/Method;",
ACC_PRIVATE | ACC_STATIC));
// generate code for proxy method and add it
methods.add(pm.generateMethod());
}
}
methods.add(generateStaticInitializer());
} catch (IOException e) {
throw new InternalError("unexpected I/O Exception");
}
/* ============================================================
* Step 3: Write the final class file.
*/
/*
* Make sure that constant pool indexes are reserved for the
* following items before starting to write the final class file.
*/
cp.getClass(dotToSlash(className));
cp.getClass(superclassName);
for (int i = 0; i < interfaces.length; i++) {
cp.getClass(dotToSlash(interfaces[i].getName()));
}
/*
* Disallow new constant pool additions beyond this point, since
* we are about to write the final constant pool table.
*/
cp.setReadOnly();
ByteArrayOutputStream bout = new ByteArrayOutputStream();
DataOutputStream dout = new DataOutputStream(bout);
try {
/*
* Write all the items of the "ClassFile" structure.
* See JVMS section 4.1.
*/
// u4 magic;
dout.writeInt(0xCAFEBABE);
// u2 minor_version;
dout.writeShort(CLASSFILE_MINOR_VERSION);
// u2 major_version;
dout.writeShort(CLASSFILE_MAJOR_VERSION);
cp.write(dout); // (write constant pool)
// u2 access_flags;
dout.writeShort(ACC_PUBLIC | ACC_FINAL | ACC_SUPER);
// u2 this_class;
dout.writeShort(cp.getClass(dotToSlash(className)));
// u2 super_class;
dout.writeShort(cp.getClass(superclassName));
// u2 interfaces_count;
dout.writeShort(interfaces.length);
// u2 interfaces[interfaces_count];
for (int i = 0; i < interfaces.length; i++) {
dout.writeShort(cp.getClass(
dotToSlash(interfaces[i].getName())));
}
// u2 fields_count;
dout.writeShort(fields.size());
// field_info fields[fields_count];
for (FieldInfo f : fields) {
f.write(dout);
}
// u2 methods_count;
dout.writeShort(methods.size());
// method_info methods[methods_count];
for (MethodInfo m : methods) {
m.write(dout);
}
// u2 attributes_count;
dout.writeShort(0); // (no ClassFile attributes for proxy classes)
} catch (IOException e) {
throw new InternalError("unexpected I/O Exception");
}
return bout.toByteArray();

总结

一个典型的动态代理创建对象过程可分为以下四个步骤:
1、通过实现InvocationHandler接口创建自己的调用处理器 IvocationHandler handler = new InvocationHandlerImpl(...);
2、通过为Proxy类指定ClassLoader对象和一组interface创建动态代理类
Class clazz = Proxy.getProxyClass(classLoader,new Class[]{...});
3、通过反射机制获取动态代理类的构造函数,其参数类型是调用处理器接口类型
Constructor constructor = clazz.getConstructor(new Class[]{InvocationHandler.class});
4、通过构造函数创建代理类实例,此时需将调用处理器对象作为参数被传入
Interface Proxy = (Interface)constructor.newInstance(new Object[] (handler));
为了简化对象创建过程,Proxy类中的newInstance方法封装了2~4,只需两步即可完成代理对象的创建。
生成的ProxySubject继承Proxy类实现Subject接口,实现的Subject的方法实际调用处理器的invoke方法,而invoke方法利用反射调用的是被代理对象的的方法(Object result=method.invoke(proxied,args))

美中不足

诚然,Proxy已经设计得非常优美,但是还是有一点点小小的遗憾之处,那就是它始终无法摆脱仅支持interface代理的桎梏,因为它的设计注定了这个遗憾。回想一下那些动态生成的代理类的继承关系图,它们已经注定有一个共同的父类叫Proxy。Java的继承机制注定了这些动态代理类们无法实现对class的动态代理,原因是多继承在Java中本质上就行不通。有很多条理由,人们可以否定对 class代理的必要性,但是同样有一些理由,相信支持class动态代理会更美好。接口和类的划分,本就不是很明显,只是到了Java中才变得如此的细化。如果只从方法的声明及是否被定义来考量,有一种两者的混合体,它的名字叫抽象类。实现对抽象类的动态代理,相信也有其内在的价值。此外,还有一些历史遗留的类,它们将因为没有实现任何接口而从此与动态代理永世无缘。如此种种,不得不说是一个小小的遗憾。但是,不完美并不等于不伟大,伟大是一种本质,Java动态代理就是佐例。

本文参考:http://www.cnblogs.com/flyoung2008/archive/2013/08/11/3251148.html

http://blog.csdn.net/heyutao007/article/details/49738887

ProxyPattern的更多相关文章

  1. ProxyPattern(23种设计模式之一)

    设计模式六大原则(1):单一职责原则 设计模式六大原则(2):里氏替换原则 设计模式六大原则(3):依赖倒置原则 设计模式六大原则(4):接口隔离原则 设计模式六大原则(5):迪米特法则 设计模式六大 ...

  2. 设计模式のProxyPattern(代理模式)----结构模式

    一.产生背景 在直接访问对象时带来的问题,比如说:要访问的对象在远程的机器上.在面向对象系统中,有些对象由于某些原因(比如对象创建开销很大,或者某些操作需要安全控制,或者需要进程外的访问),直接访问会 ...

  3. [08]Go设计模式:代理模式(ProxyPattern)

    目录 proxy 一.简介 二.代码 三.参考资料 proxy 一.简介 代理设计模式是一种结构设计模式.这种模式建议为控制和访问主要对象提供额外的间接层. 在这种模式下,将创建一个新的代理类,该类实 ...

  4. ProxyPattern(代理模式)-----Java/.Net

    在代理模式(Proxy Pattern)中,一个类代表另一个类的功能.这种类型的设计模式属于结构型模式.

  5. C#设计模式系列:代理模式(Proxy)

    代理模式提供了一个中介控制对某个对象的访问.现实生活中,我们可能会用支票在市场交易中用来代替现金,支票就是账户中资金的代理. 1.代理模式简介 1.1>.定义 代理模式(Proxy)定义:代理模 ...

  6. c#设计模式介绍

    序号 模式名称 模式描述 应用场景 例子 1 单例模式 (SigletonPattern) 保证一个类仅有一个实例,并提供一个访问它的全局访问点. • 单例类只能有一个实例. • 单例类必须自己创建自 ...

  7. 七个结构模式之代理模式(Proxy Pattern)

    定义: 给某一个对象提供一个代理或者占位符,并由代理类来控制对原对象的访问.代理对象在客户端和实际对象之间启到了中介作用,并且强调了代理类对原对象的控制作用.例如:安全代理.缓冲代理.远程代理等. 结 ...

  8. 设计模式学习之代理模式(Proxy,结构型模式)(11)

    参考地址:http://www.cnblogs.com/zhili/p/ProxyPattern.html 一.引言 在软件开发过程中,有些对象有时候会由于网络或其他的障碍,以至于不能够或者不能直接访 ...

  9. 谈谈对AOP的理解

    Aspect Oriented Programming  面向切面编程.解耦是程序员编码开发过程中一直追求的.AOP也是为了解耦所诞生. 具体思想是:定义一个切面,在切面的纵向定义处理方法,处理完成之 ...

随机推荐

  1. TODO:小程序的用户身份

    TODO:小程序的用户身份 小程序的用户身份有三种,一个管理员,二十个开发者,四十个体验者 1.管理员,可设置风险操作保护.风险操作提醒等操作. a)修改管理员,需要用到原管理员,新管理员的身份证号码 ...

  2. Qt And MFC UI Layout

    界面布局 起初,计算机的交互是通过输入的代码进行的, 慢慢的有了图形之后, 就开始了图形界面的交互. 目前来说还有语音交互, 视频交互等多媒体的交互. 不管哪一种交互, 最终在计算机的角度都是信号的输 ...

  3. javaScript 基础知识

    一.三个对话框 1.alert("提示信息") 弹出只带有一个确定按钮的对话框2.confirm("提示信息") 弹出有确定和取消按钮的对话框3.prompt( ...

  4. js创建对象的高级模式

    hello,安瑞万.第一次写博客,心情很激动啊.要是说的不好,你来打我啊?反正你也不知道我家地址.好了,不扯了.进入正题:要是写的不好欢迎大家来批评指导. what:创建对象的三种模式 --1,门户大 ...

  5. 考勤系统代码分析——主页布局easyui框架

    考勤系统主页的布局用的是easyui的Layout控件 Layout:布局容器有5个区域:北.南.东.西和中间.中间区域面板是必须的,边缘的面板都是可选的.每个边缘区域面板都可以通过拖拽其边框改变大小 ...

  6. Box Model,边距折叠,内联和块标签,CSSReset

    一.盒子模型(Box Model) 1.1.宽度测试 1.2.溢出测试 1.3.box-sizing属性 1.4.利用CSS画图 二.边距折叠 2.1.概要 2.2.垂直方向外边距合并计算 三.内联与 ...

  7. iOS 数据库的增删改查(OC版)

    自己写了几个方法来实现数据的增删改查功能: 首先在TARGETS--->>Build phases里面添加数据库所关联的库文件libsqlite3.tbd 添加完以后,在控制器上添加 #i ...

  8. SQL Server 迁移数据到MySQL

    一.背景 由于项目开始时候使用的数据库是SQL Server,后来把存储的数据库调整为MySQL,所以需要把SQL Server的数据转移到MySQL:由于涉及的表比较多,所以想在MySQL中生成对应 ...

  9. sizzle分析记录:getAttribute和getAttributeNode

    部分IE游览器下无法通过getAttribute取值? <form name="aaron"> <input type="text" name ...

  10. 《JS设计模式笔记》 1,单例模式

    <script type="text/javascript"> //单例模式 //1,每次点击都会生成一个新的div var createMask=function ( ...