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

代理模式的特征:代理类(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. 关于域名系统DNS解析IP地址的一些总结

    关于域名系统DNS(Domain Name System) 从域名中解析出IP地址. DNS主要由3部分组成: ① 名称解析器(resolver) ② 域名空间(domain name space) ...

  2. JPA中entityManager的CRUD

    private EntityManagerFactory entityManagerFactory; private EntityManager entityManager; private Enti ...

  3. AC日记——校门外的树(增强版) 洛谷 P1276

    题目描述 校门外马路上本来从编号0到L,每一编号的位置都有1棵树.有砍树者每次从编号A到B处连续砍掉每1棵树,就连树苗也不放过(记 0 A B ,含A和B):幸运的是还有植树者每次从编号C到D 中凡是 ...

  4. TCP/IP、Http、Socket、XMPP-从入门到深入

    TCP/IP.Http.Socket.XMPP-从入门到深入 终极iOS程序猿 2016-12-29 18:27 为了便于大家理解和记忆,我们先对这几个概念进行的介绍,然后分析他们的不同,再进行详细的 ...

  5. ZH奶酪:自然语言处理工具LTP语言云调用方法

    前言 LTP语言云平台 不支持离线调用: 支持分词.词性标注.命名实体识别.依存句法分析.语义角色标注: 不支持自定义词表,但是你可以先用其他支持自定义分词的工具(例如中科院的NLPIR)把文本进行分 ...

  6. # 2015-2016-2 《Java程序设计》课程总结

    2015-2016-2 <Java程序设计>课程总结

  7. SQLite剖析之锁和并发控制

    在SQLite中,锁和并发控制机制都是由pager.c模块负责处理的,用于实现ACID(Atomic.Consistent.Isolated和Durable)特性.在含有数据修改的事务中,该模块将确保 ...

  8. hdu3415 单调队列

    Max Sum of Max-K-sub-sequence Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & ...

  9. console.log((function f(n){return ((n > 1) ? n * f(n-1) : n)})(5))调用解析

    console.log((function f(n){) ? n * f(n-) : n)})()); 5被传入到函数,函数内部三元计算,5 > 1成立,运算结果是5*f(4),二次运算,5*4 ...

  10. 【BZOJ-1419】Red is good 概率期望DP

    1419: Red is good Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 660  Solved: 257[Submit][Status][Di ...