代理模式 :为其它对象提供代理,以控制对这个对象的访问。

代理模式的特征:代理类(proxyClass)与委托类(realClass)有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类(调用realClass的方法,实现代理的功能),以及事后处理消息等。代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。

作用:主要用来做方法的增强,让你可以在不修改源码的情况下,增强一些方法,在方法执行前后做任何你想做的事情(甚至根本不去执行这个方法),因为在InvocationHandler的invoke方法中,你可以直接获取正在调用方法对应的Method对象,具体应用的话,比如可以添加调用日志,做事务控制等

 动态代理结论:Proxy.newProxyInstance根据classloader和接口数组,生成一个$Proxy0代理类,并将InvocationHandler的实现类做为构造函数参数传递给$Proxy0代理类,代理类$Proxy0调用接口的方法,会在方法中调用InvocationHandler的实现类中的invoke()方法。invoke()方法中,通过反射调用委托类(realClass)的实际方法,完成了整个代理操作。

1.为了更好的理解代理模式,先理解静态代理

模拟支付宝支付,大家在淘宝买过东西都知道,买家付款后,钱放在支付宝里,不会立刻给商家,待用户确认收货后,才会支付给商家,这里支付宝就相当于代理用户付款给商家。

支付接口

package com.proxy;

public interface Pay {
public boolean pay();
}

委托类实现了支付接口

package com.proxy;

public class Customer implements Pay{
@Override
public boolean pay() {
System.out.println("网上购物使用支付宝结账付款");
return true;
}
}

代理类也要实现pay接口,包含委托类对象(关联关系)

package com.proxy;

public class AliPay implements Pay{
private Customer customer = null;
public AliPay(Customer customer){
this.customer = customer;
} @Override
public boolean pay() {
if(customer.pay()){
System.out.println("用户收到货物,支付包支付给商家完成");
}
return customer.pay();
}
}

测试

package com.proxy;

public class TestProxy {
public static void main(String[] args) {
Customer customer = new Customer();
AliPay aliPay = new AliPay(customer);
if(aliPay.pay()){
System.out.println("整个购物流程完成!");
}else{
System.out.println("付款失败!");
}
}
}

结果:

网上购物使用支付宝结账付款
用户收到货物,支付包支付给商家完成
整个购物流程完成!

使用静态代理发现,代理类只能为一个接口服务,这样会产生许多代理类。这样一来程序开发中必然会产生过多的代理,而且,所有的代理操作除了调用的方法不一样之外,其他的操作都一样,则此时肯定是重复代码。解决这一问题最好的做法是可以通过一个代理类完成全部的代理功能,那么此时就必须使用动态代理完成。

动态代理:

代理类

package com.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy; public class ProxyPay implements InvocationHandler {
private Object target; /**
* @param proxy 代理的实例proxy instance
* @param method 代理的实例proxy instance调用接口的方法
* @param args 调用实际类方法的参数数组,没有参数为null,基本类型会转成封装类
* @return
* @date 2016-4-7
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object pay = method.invoke(target, args);
if((Boolean) pay){
System.out.println("用户收到货物,支付包支付给商家完成");
}
return pay;
} /**
* loader : 类加载器
* interfaces : 代理类实现的接口
* h :调用方法
*
* public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
*/
public Object bind(Object target) {
this.target = target;
//取得代理对象
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), this);
} }

动态代理测试

package com.proxy;

public class TestDynamicProxy {
public static void main(String[] args) {
Customer customer = new Customer();
ProxyPay proxyPay = new ProxyPay();
Pay pay = (Pay) proxyPay.bind(customer);
if(pay.pay()){
System.out.println("整个购物流程完成!");
}else{
System.out.println("付款失败!");
}
}
}

结果:

网上购物使用支付宝结账付款
用户收到货物,支付包支付给商家完成
整个购物流程完成!

虽然完成了动态代理的代码操作,但是对于整个流程还是有些疑惑,是怎么调用代理类中的invoke方法。

于是看源代码发现

public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
if (h == null) {
throw new NullPointerException();
} /*
* Look up or generate the designated proxy class.
*/
Class cl = getProxyClass(loader, interfaces); /*
* Invoke its constructor with the designated invocation handler.
*/
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());
}
}
/*
* Returns the <code>java.lang.Class</code> object for a proxy class
* given a class loader and an array of interfaces. The proxy class
* will be defined by the specified class loader and will implement
* all of the supplied interfaces. If a proxy class for the same
* permutation of interfaces has already been defined by the class
* loader, then the existing proxy class will be returned; otherwise,
* a proxy class for those interfaces will be generated dynamically
* and defined by the class loader.
*/
getProxyClass方法就是根据给定的classload和interface生成代理类,如果存在,就返回存在的代理类。
cons.newInstance(new Object[] { h })可以看出代理类中的构造函数是传进去的InvocationHandler对象,会调用InvocationHandler实现类的invoke方法

package com.proxy;

import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import sun.misc.ProxyGenerator;
public class ProxyPay implements InvocationHandler {
private Object target;
private static boolean flag = true;
/**
* @param proxy 代理的实例proxy instance
* @param method 代理的实例proxy instance调用接口的方法
* @param args 调用实际类方法的参数数组,没有参数为null,基本类型会转成封装类
* @return
* @date 2016-4-7
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
/**
* Generate a proxy class given a name and a list of proxy interfaces.
*/
String name = "$Proxy0.class";
byte[] bytes = ProxyGenerator.generateProxyClass(name, new Class[]{Pay.class});
FileOutputStream os = new FileOutputStream(new File(ProxyPay.class.getClassLoader().getResource("").getPath(),name));
os.write(bytes); System.out.println(proxy.getClass().getName());
Object pay = method.invoke(target, args);
if((Boolean) pay){
System.out.println("用户收到货物,支付包支付给商家完成");
}
if(flag){
flag = false;
System.out.println("---------------");
System.out.println(((Pay) proxy.getClass().getConstructor(InvocationHandler.class).newInstance(this)).pay());
}
return pay;
} /**
* loader : 类加载器
* interfaces : 代理类实现的接口
* h :调用方法
*
* public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
*/
public Object bind(Object target) {
this.target = target;
//取得代理对象
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), this);
} }

结果:

$Proxy0
网上购物使用支付宝结账付款
用户收到货物,支付包支付给商家完成
---------------
$Proxy0
网上购物使用支付宝结账付款
用户收到货物,支付包支付给商家完成
true
整个购物流程完成!

通过proxy.getClass().getName()可以看到proxy代理类是$Proxy0,在内存中存储,通过反射得到此类的构造函数传入了InvocationHandler,调用接口的pay()方法,
发现会调用InvocationHandler实现类的invoke方法,这也证明了上面说的是正确的。使用ProxyGenerator.generateProxyClass(name, new Class[]{Pay.class});生成了$Proxy0的源码,
通过下面的源码pay()方法的return ((Boolean)this.h.invoke(this, m3, null)).booleanValue();可以看到会调用InvocationHandler实现类的invoke方法。
package $Proxy0;

import com.proxy.Pay;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException; public final class class extends Proxy
implements Pay
{
private static Method m1;
private static Method m3;
private static Method m0;
private static Method m2; public class(InvocationHandler paramInvocationHandler)
throws
{
super(paramInvocationHandler);
} public final boolean equals(Object paramObject)
throws
{
try
{
return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
} public final boolean pay()
throws
{
try
{
return ((Boolean)this.h.invoke(this, m3, null)).booleanValue();
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
} public final int hashCode()
throws
{
try
{
return ((Integer)this.h.invoke(this, m0, null)).intValue();
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
} public final String toString()
throws
{
try
{
return (String)this.h.invoke(this, m2, null);
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
} static
{
try
{
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
m3 = Class.forName("com.proxy.Pay").getMethod("pay", new Class[0]);
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
return;
}
catch (NoSuchMethodException localNoSuchMethodException)
{
throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
}
catch (ClassNotFoundException localClassNotFoundException)
{
throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
}
}
}

结论:Proxy.newProxyInstance根据classloader和接口数组,生成一个$Proxy0代理类,并将InvocationHandler的实现类做为构造函数参数传递给$Proxy0代理类,代理类$Proxy0调用接口的方法,会在方法中调用InvocationHandler的实现类中的invoke()方法。invoke()方法中,通过反射调用委托类(realClass)的实际方法,完成了整个代理操作。

												

代理模式及jdk动态代理原理的更多相关文章

  1. Spring代理模式(jdk动态代理模式)

    有动态代理和静态代理: 静态代理就是普通的Java继承调用方法. Spring有俩种动态代理模式:jdk动态代理模式 和 CGLIB动态代理 jdk动态代理模式: 代码实现: 房东出租房子的方法(继承 ...

  2. 浅谈Java代理一:JDK动态代理-Proxy.newProxyInstance

    浅谈Java代理一:JDK动态代理-Proxy.newProxyInstance java.lang.reflect.Proxy:该类用于动态生成代理类,只需传入目标接口.目标接口的类加载器以及Inv ...

  3. 代理模式 & Java原生动态代理技术 & CGLib动态代理技术

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

  4. 代理模式之cglib动态代理

    上一篇博客说了实现InvocationHandler接口的jdk动态代理,还有一种实现动态代理的方式则是:通过继承的方式实现的cglib动态代理. 先在程序中导入cglib的包,cglib-nodep ...

  5. Spring AOP高级——源码实现(3)AopProxy代理对象之JDK动态代理的创建过程

    spring-aop-4.3.7.RELEASE  在<Spring AOP高级——源码实现(1)动态代理技术>中介绍了两种动态代理技术,当然在Spring AOP中代理对象的生成也是运用 ...

  6. Spring代理模式(CGLIB动态代理模式)

    jdk动态代理和CGLIB动态代理 没什么太大的区别,CGLIB动态代理不需要接口,但是需要导入jar包. 房东出租房子的方法: package com.bjsxt.proxy2; public cl ...

  7. java 代理模式二:动态代理

    java动态代理: java动态代理类位于java.lang.reflect包下,一般主要涉及两个类: 1.Interface InvocationHandler 该接口中仅定义了一个方法:Objec ...

  8. Spring的两种代理方式:JDK动态代理和CGLIB动态代理

    代理模式 代理模式的英文叫做Proxy或Surrogate,中文都可译为”代理“,所谓代理,就是一个人或者一个机构代表另一个人或者另一个机构采取行动.在一些情况下,一个客户不想或者不能够直接引用一个对 ...

  9. 代理模式(静态代理、JDK动态代理原理分析、CGLIB动态代理)

    代理模式 代理模式是设计模式之一,为一个对象提供一个替身或者占位符以控制对这个对象的访问,它给目标对象提供一个代理对象,由代理对象控制对目标对象的访问. 那么为什么要使用代理模式呢? 1.隔离,客户端 ...

随机推荐

  1. [django]django+datatable简单运用于表格中

    使用datatable首先需要下载datatable文件,文件主要包括三个文件夹css,img,js相关文件,在django中如何配置呢? 首先需要在模板中引入datatable文件,格式如下: &l ...

  2. web安全性测试用例

    建立整体的威胁模型,测试溢出漏洞.信息泄漏.错误处理.SQL 注入.身份验证和授权错误. 1.   输入验证 客户端验证 服务器端验证(禁用脚本调试,禁用Cookies) 1.输入很大的数(如4,29 ...

  3. 【C#】【Thread】CountdownEvent任务并行

    System.Threading.CountdownEvent  是一个同步基元,它在收到一定次数的信号之后,将会解除对其等待线程的锁定. CountdownEvent  专门用于以下情况:您必须使用 ...

  4. 阅读ArrayBlockingQueue源码了解如何利用锁实现BlockingQueue

    BlockingQueue是多线程里面一个非常重要的数据结构.在面试的时候,也常会被问到怎么实现BlockingQueue.本篇根据Java7里ArrayBlockingQueue的源码,简单介绍一下 ...

  5. 缩小窗口时CSS背景图出现右侧空白BUG的解决方法

    页面容器(#wrap)与页面头部(#header )为100%宽度.而内容的容器(#page)为固定宽度960px.浏览窗口缩小而小于内容层宽度时会产生宽度理解上的差异.如下图所示窗口宽度大于内容层宽 ...

  6. php get_class()函数

    <?php class Car { function getName(){ echo "My name is " . get_class() . "<br&g ...

  7. 谈谈我的windows服务器运维管理

    我们开发的页游General War(http://gw.gamebox.com)上线运营也有半年多了,服务器的开发到运维基本都由我一手包办,在服务器上线之后我们又招了一个程序员接手后续功能的开发,而 ...

  8. Vue之计算属性

    上一篇里演示了计算属性的优点,但是,computed和data里的属性还是有区别的,computed的一个弱点就在于依赖于data属性的更新,才能触发视图更新. 举个例子: 上个例子中谈到用v-for ...

  9. input-placeholder

    :-moz-placeholder { /* Mozilla Firefox 4 to 18 */ color: #f00; } ::-moz-placeholder { /* Mozilla Fir ...

  10. java String 中用"+"拼接字符串的原理

    之前看<thinkinjava>时记得书上分析国这个问题,然后面试的时候问道了,结果面试官说时的很含糊说是new了一个对象,我说底层用的Stringbuild.他还是说我说错了.谨以此文的 ...