一、概念
代理模式是常用的Java设计模式,它的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。按照代理类的创建时期,代理类可分为两种。
静态代理类:由程序员创建或由特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。
动态代理类:在程序运行时,运用反射机制动态创建而成。
静态代理通常只代理一个类,动态代理是代理一个接口下的多个实现类。
静态代理事先知道要代理的是什么,而动态代理不知道要代理什么东西,只有在运行时才知道。
动态代理是实现JDK里的InvocationHandler接口的invoke方法,但注意的是代理的是接口,也就是你的业务类必须要实现接口,通过Proxy里的newProxyInstance得到代理对象。
还有一种动态代理CGLIB,代理的是类,不需要业务类继承接口,通过派生的子类来实现代理。通过在运行时,动态修改字节码达到修改类的目的。
静态代理类:由程序员创建或由特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。
动态代理类:在程序运行时,运用反射机制动态创建而成。
静态代理通常只代理一个类,动态代理是代理一个接口下的多个实现类。
静态代理事先知道要代理的是什么,而动态代理不知道要代理什么东西,只有在运行时才知道。
动态代理是实现JDK里的InvocationHandler接口的invoke方法,但注意的是代理的是接口,也就是你的业务类必须要实现接口,通过Proxy里的newProxyInstance得到代理对象。
还有一种动态代理CGLIB,代理的是类,不需要业务类继承接口,通过派生的子类来实现代理。通过在运行时,动态修改字节码达到修改类的目的。
二、静态代理类
如下, HelloServiceProxy类是代理类,HelloServiceImpl类是委托类,这两个类都实现了HelloService接口。其中HelloServiceImpl类是HelloService接口的真正实现者,而HelloServiceProxy类是通过调用HelloServiceImpl类的相关方法来提供特定服务的。HelloServiceProxy类的echo()方法和getTime()方法会分别调用被代理的HelloServiceImpl对象的echo()方法和getTime()方法,并且在方法调用前后都会执行一些简单的打印操作。
由此可见,代理类可以为委托类预处理消息、把消息转发给委托类和事后处理消息等。
在Client1类的main()方法中,先创建了一个HelloServiceImpl对象,又创建了一个HelloServiceProxy对象,最后调用HelloServiceProxy对象的echo()方法。
(1) getProxyClass()静态方法负责创建动态代理类,它的完整定义如下:
public static Class<?>getProxyClass(ClassLoader loader,Class<?>[] interfaces) throwsIllegalArgumentException
参数loader 指定动态代理类的类加载器,参数interfaces指定动态代理类需要实现的所有接口。
(2) newProxyInstance()静态方法负责创建动态代理类的实例,它的完整定义如下:
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler handler) throws
IllegalArgumentException
参数loader指定动态代理类的类加载器,参数interfaces 指定动态代理类需要实现的所有接口,参数handler 指定与动态代理类关联的InvocationHandler 对象。
以下两种方式都创建了实现Foo接口的动态代理类的实例:
//创建InvocationHandler对象
InvocationHandler handler = new MyInvocationHandler(...);
//创建动态代理类
Class proxyClass = Proxy.getProxyClass(Foo.class.getClassLoader(),new Class[] { Foo.class });
//创建动态代理类的实例
Foo foo = (Foo) proxyClass.getConstructor(new Class[] {InvocationHandler.class }).
newInstance(new Object[] {handler });
//创建InvocationHandler对象
InvocationHandler handler = new MyInvocationHandler(...);
//直接创建动态代理类的实例
Foo foo = (Foo)Proxy.newProxyInstance(Foo.class.getClassLoader(),new Class[] {Foo.class }, handler);
由Proxy类的静态方法创建的动态代理类具有以下特点:
动态代理类是public、final和非抽象类型的;
动态代理类继承了java.lang.reflect.Proxy类;
动态代理类的名字以“$Proxy”开头;
动态代理类实现getProxyClass()和newProxyInstance()方法中参数interfaces指定的所有接口;
Proxy 类的isProxyClass(Class<?>cl)静态方法可用来判断参数指定的类是否为动态代理类。只有通过Proxy类创建的类才是动态代理类;
动态代理类都具有一个public 类型的构造方法,该构造方法有一个InvocationHandler 类型的参数。
由Proxy类的静态方法创建的动态代理类的实例具有以下特点:
1. 假定变量foo 是一个动态代理类的实例,并且这个动态代理类实现了Foo 接口,那么“foo instanceofFoo”的值为true。把变量foo强制转换为Foo类型是合法的:
(Foo) foo //合法
2.每个动态代理类实例都和一个InvocationHandler 实例关联。Proxy类的getInvocationHandler(Objectproxy)静态方法返回与参数proxy指定的代理类实例所关联的InvocationHandler 对象。
3.假定Foo接口有一个amethod()方法,那么当程序调用动态代理类实例foo的amethod()方法时,该方法会调用与它关联的InvocationHandler对象的invoke()方法。
InvocationHandler 接口为方法调用接口,它声明了负责调用任意一个方法的invoke()方法:
Object invoke(Object proxy,Method method,Object[] args) throwsThrowable
参数proxy指定动态代理类实例,参数method指定被调用的方法,参数args指定向被调用方法传递的参数,invoke()方法的返回值表示被调用方法的返回值。
动态代理例程
以下信息来源于另一篇博客
由此可见,代理类可以为委托类预处理消息、把消息转发给委托类和事后处理消息等。
-
例程 1 HelloService.java
-
package proxy;
-
import java.util.Date;
-
public interface HelloService{
-
public String echo(String msg);
-
public Date getTime();
-
}
-
例程 2 HelloServiceImpl.java
-
package proxy;
-
import java.util.Date;
-
public class HelloServiceImpl implements HelloService{
-
public String echo(String msg){
-
return "echo:"+msg;
-
}
-
public Date getTime(){
-
return new Date();
-
}
-
}
-
例程 3 HelloServiceProxy.java
-
package proxy;
-
import java.util.Date;
-
public class HelloServiceProxy implements HelloService{
-
//表示被代理的HelloService 实例
-
private HelloService helloService;
-
public HelloServiceProxy(HelloService helloService){
-
this.helloService=helloService;
-
}
-
public void setHelloServiceProxy(HelloService helloService){
-
this.helloService=helloService;
-
}
-
public String echo(String msg){
-
//预处理
-
System.out.println( "before calling echo()");
-
//调用被代理的HelloService 实例的echo()方法
-
String result=helloService.echo(msg);
-
//事后处理
-
System.out.println( "after calling echo()");
-
return result;
-
}
-
public Date getTime(){
-
//预处理
-
System.out.println( "before calling getTime()");
-
//调用被代理的HelloService 实例的getTime()方法
-
Date date=helloService.getTime();
-
//事后处理
-
System.out.println( "after calling getTime()");
-
return date;
-
}
-
}
在Client1类的main()方法中,先创建了一个HelloServiceImpl对象,又创建了一个HelloServiceProxy对象,最后调用HelloServiceProxy对象的echo()方法。
-
例程 4 Client1.java
-
package proxy;
-
public class Client1{
-
public static void main(String args[]){
-
HelloService helloService= new HelloServiceImpl();
-
HelloService helloServiceProxy= new HelloServiceProxy(helloService);
-
System.out.println(helloServiceProxy.echo( "hello"));
-
}
-
}
-
运行Client1 类,打印结果如下:
-
before calling echo()
-
after calling echo ()
-
echo:hello
三、动态代理类
与静态代理类对照的是动态代理类,动态代理类的字节码在程序运行时由Java反射机制动态生成,无需程序员手工编写它的源代码。动态代理类不仅简化了编程工作,而且提高了软件系统的可扩展性,因为Java反射机制可以生成任意类型的动态代理类。java.lang.reflect 包中的Proxy类和InvocationHandler接口提供了生成动态代理类的能力。
Proxy类提供了创建动态代理类及其实例的静态方法。
(1) getProxyClass()静态方法负责创建动态代理类,它的完整定义如下:
public static Class<?>getProxyClass(ClassLoader loader,Class<?>[] interfaces) throwsIllegalArgumentException
参数loader 指定动态代理类的类加载器,参数interfaces指定动态代理类需要实现的所有接口。
(2) newProxyInstance()静态方法负责创建动态代理类的实例,它的完整定义如下:
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler handler) throws
IllegalArgumentException
参数loader指定动态代理类的类加载器,参数interfaces 指定动态代理类需要实现的所有接口,参数handler 指定与动态代理类关联的InvocationHandler 对象。
以下两种方式都创建了实现Foo接口的动态代理类的实例:
//创建InvocationHandler对象
InvocationHandler handler = new MyInvocationHandler(...);
//创建动态代理类
Class proxyClass = Proxy.getProxyClass(Foo.class.getClassLoader(),new Class[] { Foo.class });
//创建动态代理类的实例
Foo foo = (Foo) proxyClass.getConstructor(new Class[] {InvocationHandler.class }).
newInstance(new Object[] {handler });
//创建InvocationHandler对象
InvocationHandler handler = new MyInvocationHandler(...);
//直接创建动态代理类的实例
Foo foo = (Foo)Proxy.newProxyInstance(Foo.class.getClassLoader(),new Class[] {Foo.class }, handler);
由Proxy类的静态方法创建的动态代理类具有以下特点:
动态代理类是public、final和非抽象类型的;
动态代理类继承了java.lang.reflect.Proxy类;
动态代理类的名字以“$Proxy”开头;
动态代理类实现getProxyClass()和newProxyInstance()方法中参数interfaces指定的所有接口;
Proxy 类的isProxyClass(Class<?>cl)静态方法可用来判断参数指定的类是否为动态代理类。只有通过Proxy类创建的类才是动态代理类;
动态代理类都具有一个public 类型的构造方法,该构造方法有一个InvocationHandler 类型的参数。
由Proxy类的静态方法创建的动态代理类的实例具有以下特点:
1. 假定变量foo 是一个动态代理类的实例,并且这个动态代理类实现了Foo 接口,那么“foo instanceofFoo”的值为true。把变量foo强制转换为Foo类型是合法的:
(Foo) foo //合法
2.每个动态代理类实例都和一个InvocationHandler 实例关联。Proxy类的getInvocationHandler(Objectproxy)静态方法返回与参数proxy指定的代理类实例所关联的InvocationHandler 对象。
3.假定Foo接口有一个amethod()方法,那么当程序调用动态代理类实例foo的amethod()方法时,该方法会调用与它关联的InvocationHandler对象的invoke()方法。
InvocationHandler 接口为方法调用接口,它声明了负责调用任意一个方法的invoke()方法:
Object invoke(Object proxy,Method method,Object[] args) throwsThrowable
参数proxy指定动态代理类实例,参数method指定被调用的方法,参数args指定向被调用方法传递的参数,invoke()方法的返回值表示被调用方法的返回值。
动态代理例程
java 使用动态代理 和ThreadLocal实现事务管理实例
Java设计模式-代理模式之静态代理
概念
为另一个对象提供一个替身或占位符以提供对这个对象的访问,使用代理模式创建代表对象,让代表对象控制某对象的访问,被代理对象可以是远程的对象、创建开销大的对象或需要安全控制的对象
远程代理控制访问远程对象虚拟代理控制访问创建开销大的资源保护代理基于权限控制对资源的访问
静态代理
看如下的类图:
仔细看上面的类图,首先是Subject它为RealSubject和Proxy提供了接口,通过实现同一个接口,Proxy在RealSubject出现的地方取代它,这点和
适配器模式有比较大的区别。
- 由程序员创建或特定工具自动生成源代码再对其编译。在程序运行前代理类的.class文件就已经存在了。上面的类图很好的表示了这种关系,
动态代理
- 在程序运行时运用反射机制动态创建而成。动态代理在代理ProxySubject和RealSubject之间增加了InvocationHandler这一层,这是一种通信间接化,增加了灵 性性
一个关于静态代理的例子
警匪片大家一定都不会陌生,一些有钱的人看那个不顺眼,就想着找黑帮的帮忙杀人,黑帮就帮他们做一些坏事。这里的老板就变成了RealSubject,黑帮就变成了(Proxy),这里的real和proxy只是针对杀人是谁指使的(即幕后黑手是那个)
- 首先定义一个共同的接口,使得RealSubject出现的地方Proxy都可以出现
-
package ProxyMode;
-
-
/*
-
* 抽象接口,对应类图中的Subject
-
*
-
*/
-
-
public interface Subject {
-
-
public void SujectShow();
-
-
}
- 然后定义一个RealSubject,真正的幕后黑手
-
package ProxyMode;
-
-
-
public class RealSubject implements Subject{
-
-
-
public void SujectShow() {
-
// TODO Auto-generated method stub
-
System.out.println( "杀人是我指使的,我是幕后黑手!By---"+getClass());
-
-
}
-
-
}
-
-
-
然后定义一个代理类,黑帮,拿钱办事,但不是幕后黑手
-
-
-
package ProxyMode;
-
-
import proxy.RealeSubject;
-
-
public class ProxySubject implements Subject{
-
-
private Subject realSubject; //代理类中有 老板的引用。
-
-
public Subject TakeCall() //通过电话联系
-
{
-
return new RealSubject();
-
}
-
-
public void Before()
-
{
-
System.out.println( "我只是一个代理类,在做事情之前我先声明,接下来的事情跟我无关,我只是受人指使!By---"+getClass());
-
}
-
-
public void After()
-
{
-
System.out.println( "正如事情还没有发生之前讲的一样,我只是个路人,上面做的事情跟我无关,我是受人指使的! By---"+getClass());
-
}
-
-
-
public void SujectShow() {
-
// TODO Auto-generated method stub
-
-
Object o=TakeCall(); //代理类接到了一个电话
-
-
if(checked(o)) //检查这个电话是不是老板打过来的
-
{
-
Before();
-
-
this.realSubject=(Subject)o;
-
realSubject.SujectShow();
-
-
After();
-
}
-
else {
-
System.out.println( "不好意思,你权限不够,我帮不了你!");
-
}
-
-
-
}
-
boolean checked(Object o) //权限检查,这年头不是谁都可以冒充老板的
-
{
-
if(o instanceof RealSubject )
-
return true;
-
return false;
-
}
-
-
}
-
-
- 测试
-
package ProxyMode;
-
-
public class ProxyTest {
-
-
public static void main(String[] args)
-
{
-
ProxySubject proxy= new ProxySubject();
-
-
proxy.SujectShow();
-
}
-
-
}
执行结果:
我只是一个代理类,在做事情之前我先声明,接下来的事情跟我无关,我只是受人指使!By---class ProxyMode.ProxySubject
杀人是我指使的,我是幕后黑手!By---class ProxyMode.RealSubject
正如事情还没有发生之前讲的一样,我只是个路人,上面做的事情跟我无关,我是受人指使的! By---class ProxyMode.ProxySubject
Java设计模式-代理模式之动态代理(附源码分析)
动态代理概念及类图
动态代理跟静态代理一个最大的区别就是:动态代理是在运行时刻动态的创建出代理类及其对象。上篇中的静态代理是在编译的时候就确定了代理类具体类型,如果有多个类需要代理,那么就得创建多个。还有一点,如果Subject中新增了一个方法,那么对应的实现接口的类中也要相应的实现这些方法。
动态代理的做法:在运行时刻,可以动态创建出一个实现了多个接口的代理类。每个代理类的对象都会关联一个表示内部处理逻辑的InvocationHandler接 口的实现。当使用者调用了代理对象所代理的接口中的方法的时候,这个调用的信息会被传递给InvocationHandler的invoke方法。在 invoke方法的参数中可以获取到代理对象、方法对应的Method对象和调用的实际参数。invoke方法的返回值被返回给使用者。这种做法实际上相 当于对方法调用进行了拦截。
类图如下所示:
上面类图中使用的JDK中的Proxy类,所以是需要要办法来告诉Proxy类需要做什么,不能像静态代理一样,将代码放到Proxy类中,因为现在Proxy不是直接实现的。既然这样的代码不能放在Proxy类中,那么就需要一个InvocationHandler,InvocationHandler的工作就是响应代理的任何调用。
java.lang.reflect.Proxy:这是 Java 动态代理机制的主类,它提供了一组静态方法来为一组接口动态地生成代理类及其对象。
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h) throws IllegalArgumentException
loader: 一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载
interfaces: 一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),
h: 一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler
从上面JDK源码中可以看出getProxyClass方法才是newProxyInstance方法中最重要的,该方法负责为一组接口动态地生成代理类类型对象。下面开始解析proxy中的getProxyClass方法
该方法总共可以分为四个步骤:
对这组接口进行一定程度的安全检查,包括检查接口类对象是否对类装载器可见并且与类装载器所能识别的接口类对象是完全相同的,还会检查确保是 interface 类型而不是 class 类型。
这个步骤通过一个循环来完成,检查通过后将会得到一个包含所有接口名称的字符串数组,记为 String[] interfaceNames
缓存表是一个 HashMap 实例,正常情况下它将存放键值对(接口名字列表,动态生成的代理类的类对象引用)。当代理类正在被创建时它会临时保存(接口名字列表,pendingGenerationMarker)。标记 pendingGenerationMarke 的作用是通知后续的同类请求(接口数组相同且组内接口排列顺序也相同)代理类正在被创建,请保持等待直至创建完成。
首先是确定代理类所在的包,其原则如前所述,如果都为 public 接口,则包名为空字符串表示顶层包;如果所有非 public 接口都在同一个包,则包名与这些接口的包名相同;如果有多个非 public 接口且不同包,则抛异常终止代理类的生成。确定了包后,就开始生成代理类的类名,同样如前所述按格式“$ProxyN”生成。
结尾部分
根据结果更新缓存表,如果成功则将代理类的类对象引用更新进缓存表,否则清楚缓存表中对应关键值,最后唤醒所有可能的正在等待的线程。
InvocationHandler 的核心方法,我们最关心的是Invoke方法为什么会被调用,见下面分析:
动态代理实现过程
具体有如下四步骤: 通过实现 InvocationHandler 接口创建自己的调用处理器;通过为 Proxy 类指定 ClassLoader 对象和一组 interface 来创建动态代理类;通过反射机制获得动态代理类的构造函数,其唯一参数类型是调用处理器接口类型;通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数被传入。
一个具体的例子
接着上面的类图和静态代理中的例子,我们分别创建Subject和RealSubject
Subject
-
package ProxyMode;
-
-
/*
-
* 抽象接口,对应类图中的Subject
-
*
-
*/
-
-
public interface Subject {
-
-
public void SujectShow();
-
-
}
RealSubject
-
package ProxyMode;
-
-
-
public class RealSubject implements Subject{
-
-
-
public void SujectShow() {
-
// TODO Auto-generated method stub
-
System.out.println( "杀人是我指使的,我是幕后黑手!By---"+getClass());
-
-
}
-
-
}
建立InvocationHandler用来响应代理的任何调用
-
package ProxyMode;
-
-
import java.lang.reflect.InvocationHandler;
-
import java.lang.reflect.Method;
-
-
public class ProxyHandler implements InvocationHandler {
-
-
private Object proxied;
-
-
public ProxyHandler( Object proxied )
-
{
-
this.proxied = proxied;
-
}
-
-
-
-
public Object invoke(Object proxy, Method method, Object[] args)
-
throws Throwable {
-
-
System.out.println( "准备工作之前:");
-
-
//转调具体目标对象的方法
-
Object object= method.invoke( proxied, args);
-
-
System.out.println( "工作已经做完了!");
-
return object;
-
}
-
-
}
动态代理类测试,这个代理类中再也不用实现Subject接口,可以动态的获得RealSubject接口中的方法
-
package ProxyMode;
-
-
-
import java.lang.reflect.Proxy;
-
-
public class DynamicProxy {
-
-
public static void main( String args[] )
-
{
-
RealSubject real = new RealSubject();
-
Subject proxySubject = (Subject)Proxy.newProxyInstance(Subject.class.getClassLoader(),
-
new Class[]{Subject.class},
-
new ProxyHandler(real));
-
-
proxySubject.SujectShow();;
-
-
}
-
}
-
测试结果
-
-
准备工作之前:
-
杀人是我指使的,我是幕后黑手!By--- class ProxyMode.RealSubject
-
工作已经做完了!
java.lang.reflect.Proxy:这是 Java 动态代理机制的主类,它提供了一组静态方法来为一组接口动态地生成代理类及其对象。
-
清单 1. Proxy 的静态方法
-
// 方法 1: 该方法用于获取指定代理对象所关联的调用处理器,比如上面代码中的ProxyHandler
-
static InvocationHandler getInvocationHandler(Object proxy)
-
-
// 方法 2:该方法用于获取关联于指定类装载器和一组接口的动态代理类的类对象
-
static Class getProxyClass (ClassLoader loader, Class[] interfaces)
-
-
// 方法 3:该方法用于判断指定类对象是否是一个动态代理类
-
static boolean isProxyClass (Class cl)
-
-
// 方法 4:该方法用于为指定类装载器、一组接口及调用处理器生成动态代理类实例
-
static Object newProxyInstance (ClassLoader loader, Class[] interfaces,
-
InvocationHandler h)
-
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());
-
}
-
}
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h) throws IllegalArgumentException
loader: 一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载
interfaces: 一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),
h: 一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler
从上面JDK源码中可以看出getProxyClass方法才是newProxyInstance方法中最重要的,该方法负责为一组接口动态地生成代理类类型对象。下面开始解析proxy中的getProxyClass方法
该方法总共可以分为四个步骤:
对这组接口进行一定程度的安全检查,包括检查接口类对象是否对类装载器可见并且与类装载器所能识别的接口类对象是完全相同的,还会检查确保是 interface 类型而不是 class 类型。
这个步骤通过一个循环来完成,检查通过后将会得到一个包含所有接口名称的字符串数组,记为 String[] interfaceNames
-
for ( int i = 0; i < interfaces.length; i++) {
-
-
// 验证类加载程 序 解 析 该接口到同一类对象的名称。
-
String interfaceName = interfaces[i].getName();
-
Class<?> interfaceClass = null;
-
try {
-
interfaceClass = Class.forName(interfaceName, false, loader);
-
} catch (ClassNotFoundException e) {
-
}
-
if (interfaceClass != interfaces[i]) {
-
throw new IllegalArgumentException(
-
interfaces[i] + " is not visible from class loader");
-
}
-
-
// 验证类对象真正代表一个接口
-
-
if (!interfaceClass.isInterface()) {
-
throw new IllegalArgumentException(
-
interfaceClass.getName() + " is not an interface");
-
}
-
-
//验证这个接口是不是重复的
-
if (interfaceSet.contains(interfaceClass)) {
-
throw new IllegalArgumentException(
-
"repeated interface: " + interfaceClass.getName());
-
}
-
interfaceSet.add(interfaceClass); //interfaceset是一个hashset集合
-
-
interfaceNames[i] = interfaceName;
-
}
缓存表是一个 HashMap 实例,正常情况下它将存放键值对(接口名字列表,动态生成的代理类的类对象引用)。当代理类正在被创建时它会临时保存(接口名字列表,pendingGenerationMarker)。标记 pendingGenerationMarke 的作用是通知后续的同类请求(接口数组相同且组内接口排列顺序也相同)代理类正在被创建,请保持等待直至创建完成。
-
synchronized (cache) {
-
do {
-
// 以接口名字列表作为关键字获得对应 cache 值
-
Object value = cache.get(key);
-
if (value instanceof Reference) {
-
proxyClass = (Class) ((Reference) value).get();
-
}
-
if (proxyClass != null) {
-
// 如果已经创建,直接返回,这里非常重要,如果已经创建过代理类,那么不再创建
-
return proxyClass;
-
} else if (value == pendingGenerationMarker) {
-
// 代理类正在被创建,保持等待
-
try {
-
cache.wait();
-
} catch (InterruptedException e) {
-
}
-
// 等待被唤醒,继续循环并通过二次检查以确保创建完成,否则重新等待
-
continue;
-
} else {
-
// 标记代理类正在被创建
-
cache.put(key, pendingGenerationMarker);
-
// break 跳出循环已进入创建过程
-
break;
-
} while ( true);
-
}
首先是确定代理类所在的包,其原则如前所述,如果都为 public 接口,则包名为空字符串表示顶层包;如果所有非 public 接口都在同一个包,则包名与这些接口的包名相同;如果有多个非 public 接口且不同包,则抛异常终止代理类的生成。确定了包后,就开始生成代理类的类名,同样如前所述按格式“$ProxyN”生成。
-
// 动态地生成代 理类的字节码数组
-
byte[] proxyClassFile = ProxyGenerator.generateProxyClass( proxyName, interfaces);
-
try {
-
// 动态地定义新生成的代理类
-
proxyClass = defineClass0(loader, proxyName, proxyClassFile, 0,
-
proxyClassFile.length);
-
} catch (ClassFormatError e) {
-
throw new IllegalArgumentException(e.toString());
-
}
-
-
// 把生成的代理类的类对象记录进 proxyClasses 表
-
proxyClasses.put(proxyClass, null);
结尾部分
根据结果更新缓存表,如果成功则将代理类的类对象引用更新进缓存表,否则清楚缓存表中对应关键值,最后唤醒所有可能的正在等待的线程。
-
synchronized (cache) {
-
if (proxyClass != null) {
-
cache.put(key, new WeakReference<Class<?>>(proxyClass));
-
} else {
-
cache.remove(key);
-
}
-
cache.notifyAll();
-
}
InvocationHandler 的核心方法,我们最关心的是Invoke方法为什么会被调用,见下面分析:
Object invoke(Object proxy, Method method, Object[] args)
// 该方法负责集中处理动态代理类上的所 有方法调用。
//第一个参数既是代理类实例,
//第二个参数是被调用的方法对象
// 第三个方法是调用参数。调用处理器根据这三个参数进行预处理或分派到委托类实例上发射执行
每次生成动态代理类对象时都需要指定一个实现了该接口的调用处理器对象(参见 newProxyInstance 的第三个参数)。
很多人肯定跟我一样,我们在Handler中调用的method.invoke方法中并没有显示的调用invoke方法,只是在newProxyInstance中应用了一个handler对象,有了上面关于newProxyInstance的源码分析,我们知道了 newproxyinstance生成了一个$Proxy0类代理。当调用Subjectshow()方法时,其实调用的$Proxy0的SubjectShow()方法,从而调用父类Proxy中传进来第三个参数(h)的的Invoke方法。
-
//这个方法是 Proxy源码中的
-
protected Proxy(InvocationHandler h) {
-
this.h = h;
-
}
-
public final class $Proxy0 extends Proxy implements Subject {
-
private static Method m1;
-
private static Method m0;
-
private static Method m3;
-
private static Method m2;
-
-
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( "***.RealSubject").getMethod( "request",
-
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());
-
}
-
} //static
-
-
public $Proxy0(InvocationHandler invocationhandler) {
-
super(invocationhandler);
-
}
-
-
-
public final boolean equals(Object obj) {
-
try {
-
return ((Boolean) super.h.invoke( this, m1, new Object[] { obj })) .booleanValue();
-
} catch (Throwable throwable) {
-
throw new UndeclaredThrowableException(throwable);
-
}
-
}
-
-
-
public final int hashCode() {
-
try {
-
return ((Integer) super.h.invoke( this, m0, null)).intValue();
-
} catch (Throwable throwable) {
-
throw new UndeclaredThrowableException(throwable);
-
}
-
}
-
-
public final void SubjectShow() {
-
try {
-
super.h.invoke( this, m3, null); //就是这个地方 调用h.invoke()
-
return;
-
} catch (Error e) {
-
} catch (Throwable throwable) {
-
throw new UndeclaredThrowableException(throwable);
-
}
-
}
-
-
-
public final String toString() {
-
try {
-
return (String) super.h.invoke( this, m2, null);
-
} catch (Throwable throwable) {
-
throw new UndeclaredThrowableException(throwable);
-
}
-
}
-
}