一、 源码
package java.lang.reflect;
import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;
import sun.misc.ProxyGenerator;
public class Proxy implements java.io.Serializable {
private static final long serialVersionUID = -2222568056686623797L;
/** prefix for all proxy class names 所有的代理类名称的前缀*/
private final static String proxyClassNamePrefix = "$Proxy";
/** parameter types of a proxy class constructor代理类的构造函数的参数类型*/
private final static Class[] constructorParams = { InvocationHandler.class };
/** maps a class loader to the proxy class cache for that loader为一个映射类加载器到代理类的加载器进行缓存*/
private static Map loaderToCache = new WeakHashMap();
/** marks that a particular proxy class is currently being generated */
private static Object pendingGenerationMarker = new Object();
/** next number to use for generation of unique proxy class names */
private static long nextUniqueNumber = 0;
private static Object nextUniqueNumberLock = new Object();
/** set of all generated proxy classes, for isProxyClass implementation */
private static Map proxyClasses = Collections
.synchronizedMap(new WeakHashMap());
/**
* the invocation handler for this proxy instance.
* 代理实例的调用处理器
* 此代理实例的调用处理程序。
* @serial
*/
protected InvocationHandler h;
/**
* Prohibits instantiation. 禁止实例化
*/
private Proxy() {
}
/**
* Constructs a new <code>Proxy</code> instance from a subclass (typically,
* a dynamic proxy class) with the specified value for its invocation
* handler.
*/
protected Proxy(InvocationHandler h) {
this.h = h;
}
public static Class<?> getProxyClass(ClassLoader loader,
Class<?>... interfaces) throws IllegalArgumentException {
if (interfaces.length > 65535) {
throw new IllegalArgumentException("interface limit exceeded");
}
Class proxyClass = null;
/* collect interface names to use as key for proxy class cache
收集接口的名称用于代理类缓存中的键*/
String[] interfaceNames = new String[interfaces.length];
Set interfaceSet = new HashSet(); // for detecting duplicates
for (int i = 0; i < interfaces.length; i++) {
/*
* Verify that the class loader resolves the name of this interface
* to the same Class object.
* 通过类加载器去加载,验证类实现是否实现接口
*/
String interfaceName = interfaces[i].getName();
Class interfaceClass = null;
try { //参数false表示类加载器加载时候不解释improt
interfaceClass = Class.forName(interfaceName, false, loader);
} catch (ClassNotFoundException e) {
}
if (interfaceClass != interfaces[i]) {
throw new IllegalArgumentException(interfaces[i]
+ " is not visible from class loader");
}
/*
* Verify that the Class object actually represents an interface.
*/
if (!interfaceClass.isInterface()) { // 验证是不是接口
throw new IllegalArgumentException(interfaceClass.getName()
+ " is not an interface");
}
/*
* Verify that this interface is not a duplicate.
* 验证接口是否重复
*/
if (interfaceSet.contains(interfaceClass)) {
throw new IllegalArgumentException("repeated interface: "
+ interfaceClass.getName());
}
interfaceSet.add(interfaceClass);
interfaceNames[i] = interfaceName;
}
/*
* Using string representations of the proxy interfaces as keys in the
* proxy class cache (instead of their Class objects) is sufficient
* because we require the proxy interfaces to be resolvable by name
* through the supplied class loader, and it has the advantage that
* using a string representation of a class makes for an implicit weak
* reference to the class.
用代理接口的字符串形式表示key存在缓存里尔不是Class对象足够了,因为我们需要代理接口去通过类加载器用名字渲染。并且这样带来的好处是使用字符串形式表述class能不明显的依赖class
*/
Object key = Arrays.asList(interfaceNames);
/*
* Find or create the proxy class cache for the class loader.
*/
Map cache;
synchronized (loaderToCache) {
cache = (Map) loaderToCache.get(loader);
if (cache == null) {
cache = new HashMap();
loaderToCache.put(loader, cache);
}
/*
* This mapping will remain valid for the duration of this method,
* without further synchronization, because the mapping will only be
* removed if the class loader becomes unreachable.
*/
}
/*
* Look up the list of interfaces in the proxy class cache using the
* key. This lookup will result in one of three possible kinds of
* values: null, if there is currently no proxy class for the list of
* interfaces in the class loader, the pendingGenerationMarker object,
* if a proxy class for the list of interfaces is currently being
* generated, or a weak reference to a Class object, if a proxy class
* for the list of interfaces has already been generated.
*/
synchronized (cache) {
/*
* Note that we need not worry about reaping the cache for entries
* with cleared weak references because if a proxy class has been
* garbage collected, its class loader will have been garbage
* collected as well, so the entire cache will be reaped from the
* loaderToCache map.
* 因为一个代理class会被垃圾回收,
* 它的类加载器也会被垃圾回收,所以实体缓存会从loaderToCache map中获得
* 三种情况:
* 1如果当前缓存总没有此Proxy类则返回null
* 2如果Proxy类正在创建则返回pendingGenerationMarker对象
* 3如果此Proxy类已经被创建,则返回WeakReference对象
*/
do {
Object value = cache.get(key);
if (value instanceof Reference) {
proxyClass = (Class) ((Reference) value).get();
}
if (proxyClass != null) {
// proxy class already generated: return it
return proxyClass;
} else if (value == pendingGenerationMarker) {
// proxy class being generated: wait for it
try {
cache.wait();
} catch (InterruptedException e) {
/*
* The class generation that we are waiting for should
* take a small, bounded time, so we can safely ignore
* thread interrupts here.
*/
}
continue;
} else {
/*
* No proxy class for this list of interfaces has been
* generated or is being generated, so we will go and
* generate it now. Mark it as pending generation.
*/
cache.put(key, pendingGenerationMarker);
break;
}
} while (true);
}
try {
String proxyPkg = null; // package to define proxy class in
/*
* Record the package of a non-public proxy interface so that the
* proxy class will be defined in the same package. Verify that all
* non-public proxy interfaces are in the same package.
*/
for (int i = 0; i < interfaces.length; i++) {
int flags = interfaces[i].getModifiers();
if (!Modifier.isPublic(flags)) {
String name = interfaces[i].getName();
int n = name.lastIndexOf('.');
String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
if (proxyPkg == null) {
proxyPkg = pkg;
} else if (!pkg.equals(proxyPkg)) {
throw new IllegalArgumentException(
"non-public interfaces from different packages");
}
}
}
if (proxyPkg == null) { // if no non-public proxy interfaces,
proxyPkg = ""; // use the unnamed package
}
{
/*
* Choose a name for the proxy class to generate.
*/
long num;
//这里使用静态属性作为锁,保护了同步区域内的数据
//因为num是long型的,无法对原始对象加锁(只能对类加锁)
//而如果对整个当前对象加锁会浪费性能
//使用一个锁对象,还可达到同时保护多个数据(对象,原始类型)的效果
synchronized (nextUniqueNumberLock) {
num = nextUniqueNumber++;
}
String proxyName = proxyPkg + proxyClassNamePrefix + num;
/*
* Verify that the class loader hasn't already defined a class
* with the chosen name.
*/
/*
* Generate the specified proxy class.
*/
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces);
try {
//加载代理类
proxyClass = defineClass0(loader, proxyName,
proxyClassFile, 0, proxyClassFile.length);
} catch (ClassFormatError e) {
/*
* A ClassFormatError here means that (barring bugs in the
* proxy class generation code) there was some other invalid
* aspect of the arguments supplied to the proxy class
* creation (such as virtual machine limitations exceeded).
*/
throw new IllegalArgumentException(e.toString());
}
}
// add to set of all generated proxy classes, for isProxyClass
proxyClasses.put(proxyClass, null);
} finally {
/*
* We must clean up the "pending generation" state of the proxy
* class cache entry somehow. If a proxy class was successfully
* generated, store it in the cache (with a weak reference);
* otherwise, remove the reserved entry. In all cases, notify all
* waiters on reserved entries in this cache.
*/
synchronized (cache) {
if (proxyClass != null) {
//key是一堆接口的集合,并除去标记正在生成代理的pending generation对象
cache.put(key, new WeakReference(proxyClass));
} else {
cache.remove(key);
}
cache.notifyAll();
}
}
return proxyClass;
}
//类加载器,接口的Class数组,类加载器,通常是APPClassLoader
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对象
*/
Class cl = getProxyClass(loader, interfaces);
/*
* Invoke its constructor with the designated invocation handler.
*/
try {
//获得有一个InvocationHandler对象参数的构造函数
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 boolean isProxyClass(Class<?> cl) {
if (cl == null) {
throw new NullPointerException();
}
return proxyClasses.containsKey(cl);
}
public static InvocationHandler getInvocationHandler(Object proxy)
throws IllegalArgumentException {
/*
* Verify that the object is actually a proxy instance.
*/
if (!isProxyClass(proxy.getClass())) {
throw new IllegalArgumentException("not a proxy instance");
}
Proxy p = (Proxy) proxy;
return p.h;
}
private static native Class defineClass0(ClassLoader loader, String name,
byte[] b, int off, int len);
}
二、 API文档说明
java.lang.reflect
类 Proxy
java.lang.Object
java.lang.reflect.Proxy
所有已实现的接口:
Serializable
________________________________________
public class Proxy
extends Object
implements Serializable
Proxy 提供用于创建动态代理类和实例的静态方法,它还是由这些方法创建的所有动态代理类的超类。
创建某一接口 Foo 的代理:
InvocationHandler handler = new MyInvocationHandler(...);
Class proxyClass = Proxy.getProxyClass(
Foo.class.getClassLoader(), new Class[] { Foo.class });
Foo f = (Foo) proxyClass.
getConstructor(new Class[] { InvocationHandler.class }).
newInstance(new Object[] { handler });
或使用以下更简单的方法:
Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
new Class[] { Foo.class },
handler);
动态代理类(以下简称为代理类)是一个实现在创建类时在运行时指定的接口列表的类,该类具有下面描述的行为。 代理接口 是代理类实现的一个接口。 代理实例 是代理类的一个实例。 每个代理实例都有一个关联的调用处理程序 对象,它可以实现接口 InvocationHandler。通过其中一个代理接口的代理实例上的方法调用将被指派到实例的调用处理程序的 Invoke 方法,并传递代理实例、识别调用方法的 java.lang.reflect.Method 对象以及包含参数的 Object 类型的数组。调用处理程序以适当的方式处理编码的方法调用,并且它返回的结果将作为代理实例上方法调用的结果返回。
代理类具用以下属性:
• 代理类是公共的、最终的,而不是抽象的。
• 未指定代理类的非限定名称。但是,以字符串 "$Proxy" 开头的类名空间应该为代理类保留。
• 代理类扩展 java.lang.reflect.Proxy。
• 代理类会按同一顺序准确地实现其创建时指定的接口。
• 如果代理类实现了非公共接口,那么它将在与该接口相同的包中定义。否则,代理类的包也是未指定的。注意,包密封将不阻止代理类在运行时在特定包中的成功定义,也不会阻止相同类加载器和带有特定签名的包所定义的类。
• 由于代理类将实现所有在其创建时指定的接口,所以对其 Class 对象调用 getInterfaces 将返回一个包含相同接口列表的数组(按其创建时指定的顺序),对其 Class 对象调用 getMethods 将返回一个包括这些接口中所有方法的 Method 对象的数组,并且调用 getMethod 将会在代理接口中找到期望的一些方法。
• 如果 Proxy.isProxyClass 方法传递代理类(由 Proxy.getProxyClass 返回的类,或由 Proxy.newProxyInstance 返回的对象的类),则该方法返回 true,否则返回 false。
• 代理类的 java.security.ProtectionDomain 与由引导类加载器(如 java.lang.Object)加载的系统类相同,原因是代理类的代码由受信任的系统代码生成。此保护域通常被授予 java.security.AllPermission。
• 每个代理类都有一个可以带一个参数(接口 InvocationHandler 的实现)的公共构造方法,用于设置代理实例的调用处理程序。并非必须使用反射 API 才能访问公共构造方法,通过调用 Proxy.newInstance 方法(将调用 Proxy.getProxyClass 的操作和调用带有调用处理程序的构造方法结合在一起)也可以创建代理实例。
代理实例具有以下属性:
• 提供代理实例 proxy 和一个由其代理类 Foo 实现的接口,以下表达式将返回 true:
• proxy instanceof Foo
并且以下的强制转换操作将会成功(而不抛出 ClassCastException):
(Foo) proxy
• 每个代理实例都有一个关联的调用处理程序,它会被传递到其构造方法中。静态 Proxy.getInvocationHandler 方法将返回与作为其参数传递的代理实例相关的调用处理程序。
• 代理实例上的接口方法调用将按照该方法的文档描述进行编码,并被指派到调用处理程序的 Invoke 方法。
• 在代理实例上的 java.lang.Object 中声明的 hashCode、equals 或 toString 方法的调用将按照与编码和指派接口方法调用相同的方式进行编码,并被指派到调用处理程序的 invoke 方法,如上所述。传递到 invoke 的 Method 对象的声明类是 java.lang.Object。代理类不重写从 java.lang.Object 继承的代理实例的其他公共方法,所以这些方法的调用行为与其对 java.lang.Object 实例的操作一样。
在多代理接口中重复的方法
当代理类的两个或多个接口包含一个具有相同名称和参数签名的方法时,代理类的接口顺序变得非常重要。在代理实例上调用重复方法 时,传递到调用处理程序的 Method 对象没有必要成为其声明类可以从接口(通过该接口调用代理方法)的引用类型指派的对象。此限制存在的原因是,生成的代理类中的相应方法实现无法确定它通过哪一个接口调用。因此,在代理实例上调用重复方法时,第一个接口中的方法的 Method 对象包含接口的代理类列表中的方法(直接或通过超级接口继承),该对象会传递到调用处理程序的 invoke 方法,无论该方法调用通过哪一种引用类型发生。
如果代理接口包含某一方法,它的名称和参数签名与 java.lang.Object 的 hashCode、equals 或 toString 方法相同,那么在代理实例上调用这样的方法时,传递到调用处理程序的 Method 对象将使 java.lang.Object 成为其声明类。换句话说,java.lang.Object 公共的非最终方法理论上在所有代理接口之前,以便确定哪一个 Method 对象传递到调用处理程序。
还要注意,当重复方法被指派到调用处理程序时,invoke 方法只可以抛出经过检查的异常类型,该异常类型可以使用所有 代理接口(可以通过它调用)中方法的 throws 子句指派一种异常类型。如果 invoke 方法抛出一个经过检查的异常,该异常没有指派给任何由一个代理接口(可以通过它调用)中的方法声明的异常类型,那么该代理实例上的调用将抛出一个未经检查的 UndeclaredThrowableException。此限制表示并非所有的由传递到 invoke 方法的 Method 对象上调用 getExceptionTypes 返回的异常类型都可以由 invoke 方法成功抛出。
从以下版本开始:
1.3
另请参见:
InvocationHandler, 序列化表格
________________________________________
字段摘要
protected InvocationHandler
h
此代理实例的调用处理程序。
构造方法摘要
protected Proxy(InvocationHandler h)
使用其调用处理程序的指定值从子类(通常为动态代理类)构建新的 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)
返回一个指定接口的代理类实例,该接口可以将方法调用指派到指定的调用处理程序。
从类 java.lang.Object 继承的方法
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
字段详细信息
h
protected InvocationHandler h
此代理实例的调用处理程序。
构造方法详细信息
Proxy
protected Proxy(InvocationHandler h)
使用其调用处理程序的指定值从子类(通常为动态代理类)构建新的 Proxy 实例。
参数:
h - 此代理实例的调用处理程序
方法详细信息
getProxyClass
public static Class<?> getProxyClass(ClassLoader loader,
Class<?>... interfaces)
throws IllegalArgumentException
返回代理类的 java.lang.Class 对象,并向其提供类加载器和接口数组。该代理类将由指定的类加载器定义,并将实现提供的所有接口。如果类加载器已经定义了具有相同排列接口的代理类,那么现有的代理类将被返回;否则,类加载器将动态生成并定义这些接口的代理类。
对可以传递给 Proxy.getProxyClass 的参数有以下几个限制:
• interfaces 数组中的所有 Class 对象必须表示接口,而不能表示类或基本类型。
• interfaces 数组中的两个元素不能引用同一 Class 对象。
• 所有接口类型的名称通过特定的类加载器必须可见。换句话说,对于类加载器 cl 和所有接口 i,以下表达式必须为 true:
• Class.forName(i.getName(), false, cl) == i
• 所有非公共接口必须位于同一包中;否则,该代理类将不可能实现所有的接口,无论它在哪一个包中定义。
• 对于有相同签名的指定接口中任何成员方法集:
o 如果任何方法的返回类型是基本类型或 void,那么所有的方法必须具有与此相同的返回类型。
o 否则,该方法之一必须是返回类型,它可以指派给该方法其余的所有返回类型。
• 得到的代理类必须不超过虚拟机在类上施加的任何限制。例如,虚拟机可以限制某一类实现至多 65535 的接口数;在这种情况下,interfaces 数组的大小必须不超过 65535。
如果违反了这些限制,Proxy.getProxyClass 将抛出 IllegalArgumentException。如果 interfaces 数组参数或其任何元素为 null,则将抛出 NullPointerException。
注意,指定的代理接口的顺序非常重要:对接口组合相同但顺序不同的代理类的两个请求会导致两个不同的代理类。
参数:
loader - 定义代理类的类加载器
interfaces - 代理类要实现的接口列表
返回:
用指定的类加载器定义的代理类,它可以实现指定的接口
抛出:
IllegalArgumentException - 如果违反传递到 getProxyClass 的参数上的任何限制
NullPointerException - 如果 interfaces 数组参数或其任何元素为 null
________________________________________
newProxyInstance
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
返回一个指定接口的代理类实例,该接口可以将方法调用指派到指定的调用处理程序。此方法相当于:
Proxy.getProxyClass(loader, interfaces).
getConstructor(new Class[] { InvocationHandler.class }).
newInstance(new Object[] { handler });
Proxy.newProxyInstance 抛出 IllegalArgumentException,原因与 Proxy.getProxyClass 相同。
参数:
loader - 定义代理类的类加载器
interfaces - 代理类要实现的接口列表
h - 指派方法调用的调用处理程序
返回:
一个带有代理类的指定调用处理程序的代理实例,它由指定的类加载器定义,并实现指定的接口
抛出:
IllegalArgumentException - 如果违反传递到 getProxyClass 的参数上的任何限制
NullPointerException - 如果 interfaces 数组参数或其任何元素为 null,或如果调用处理程序 h 为 null
________________________________________
isProxyClass
public static boolean isProxyClass(Class<?> cl)
当且仅当指定的类通过 getProxyClass 方法或 newProxyInstance 方法动态生成为代理类时,返回 true。
此方法的可靠性对于使用它做出安全决策而言非常重要,所以此方法的实现不应仅测试相关的类是否可以扩展 Proxy。
参数:
cl - 要测试的类
返回:
如该类为代理类,则为 true,否则为 false
抛出:
NullPointerException - 如果 cl 为 null
________________________________________
getInvocationHandler
public static InvocationHandler getInvocationHandler(Object proxy)
throws IllegalArgumentException
返回指定代理实例的调用处理程序。
参数:
proxy - 返回调用处理程序的代理实例
返回:
代理实例的调用处理程序
抛出:
IllegalArgumentException - 如果参数不是一个代理实例
三、 解析
1.验证InvocationHandler是否空
2.生成代理类的Class对象,这里戏份比较多,代码中详细注释。
(1).通过类加载器去加载得到Class实例,比较是否想通的Class
(2).判断是否是接口
(3).去重Class,并通过String[]保存接口名
(4).从缓存中创建根据类加载器取得Map,如果没有则创建一个,保存到WeakHashMap
(5). put key,value<一堆接口,正在创建代理的标志> into Map
(6).记录包可见的代理接口,for循环中是校验非公有接口是否在同一包下
(7).生成类名,并生成代理类
(8).把代理类放入代理类缓存
(9).获得有一个InvocationHandler对象参数的构造函数,并创建实例.
Java代码
1. public static Object newProxyInstance(ClassLoader loader,
2. Class<?>[] interfaces,
3. InvocationHandler h)//这里有三个参数,第一个是传入classloader,一般情况是传入当前的classloader.但是我在上一节模拟实现里传入的是URL loader..第二个参数表示的是接口,第三个是Invocationhandler,除了第一个参数,其他和我在上一节里的一样.JDK的封装的比较好,所以他传入的是Interface的数组,
4. throws IllegalArgumentException
5. {
6. if (h == null) {
7. throw new NullPointerException();//如果Invocationhandler 为空,抛异常
8. }
9.
10. /*
11. * Look up or generate the designated proxy class.这个方法里最主要的地方在这里,它直接通过调用 getProxyClass方法获取到了自动生成的动态代理类的二进制码.在我上一节的内容里,我们是通过自己生成JAVA文件,然后通过JAVA文件动态编译成对应的class文件,然后通过URLClassLoader.loadClass("com.cjb.proxy.Proxy1");这个方法来获取对应的二进制码的.这个方法下面会继续解释.
12. */
13. Class cl = getProxyClass(loader, interfaces);
14.
15. /*
16. * Invoke its constructor with the designated invocation handler.这个方法就是获取对应class的Constructor,然后通过这个Constructor来实例化..
17. */
18. try {
19. Constructor cons = cl.getConstructor(constructorParams);
20. return (Object) cons.newInstance(new Object[] { h });
21. } catch (NoSuchMethodException e) {
22. throw new InternalError(e.toString());
23. } catch (IllegalAccessException e) {
24. throw new InternalError(e.toString());
25. } catch (InstantiationException e) {
26. throw new InternalError(e.toString());
27. } catch (InvocationTargetException e) {
28. throw new InternalError(e.toString());
29. }
30. }
31.
32. 上面的方法,除了最重要的getProxyClass,其他都很容易理解.,那么下面开始读getProxyClass方法
33.
34. public static Class<?> getProxyClass(ClassLoader loader,
35. Class<?>... interfaces)
36. throws IllegalArgumentException
37. {
38. if (interfaces.length > 65535) {
39. throw new IllegalArgumentException("interface limit exceeded");//JDK想的果然比较到位,连interface传的太多都想到了..~!~
40. }
41.
42. Class proxyClass = null;//这个就是最后要生成的二进制码,首先初始化一下
43.
44. /* collect interface names to use as key for proxy class cache */
45. String[] interfaceNames = new String[interfaces.length];//这个存放的是对应的Interface的名字..
46.
47. Set interfaceSet = new HashSet(); //这个HashSet 是为了检测interface重复记录的.
48.
49. for (int i = 0; i < interfaces.length; i++) {
50. /*
51. * Verify that the class loader resolves the name of this
52. * interface to the same Class object.
53. */
54. String interfaceName = interfaces[i].getName();
55. Class interfaceClass = null;
56. try {
57. interfaceClass = Class.forName(interfaceName, false, loader);//创建对应接口的二进制码,第二个参数false表示,不需要初始化
58. } catch (ClassNotFoundException e) {
59. }
60. if (interfaceClass != interfaces[i]) {//如果创建出来的二进制码和原来的接口不一样,表示这个接口对于这个classloader来说是不可见的
61. throw new IllegalArgumentException(
62. interfaces[i] + " is not visible from class loader");
63. }
64.
65. /*
66. * Verify that the Class object actually represents an
67. * interface.
68. */
69. if (!interfaceClass.isInterface()) {//如果不是接口,那么就抛异常,这里就规定了,我们必须通过接口来代理..或者说,必须面向接口编程
70. throw new IllegalArgumentException(
71. interfaceClass.getName() + " is not an interface");
72. }
73.
74. /*
75. * Verify that this interface is not a duplicate.前面说,InterfaceSet是拿来判断对应的interface接口是否有重复的.这里的方法是:在循环interfaces的时候,把每个interface都添加到interfaceSet里..当然,在添加之前会判断,当前循环到的接口在InterfaceSet里是否有,如果已经有了,则抛异常,说这个接口重复了..没有,则添加..
76. */
77. if (interfaceSet.contains(interfaceClass)) {
78. throw new IllegalArgumentException(
79. "repeated interface: " + interfaceClass.getName());
80. }
81. interfaceSet.add(interfaceClass);
82.
83. interfaceNames[i] = interfaceName;//这句就是把每个接口名放到interfaceNames数组里..
84. }
85.
86. /*
87. * Using string representations of the proxy interfaces as
88. * keys in the proxy class cache (instead of their Class
89. * objects) is sufficient because we require the proxy
90. * interfaces to be resolvable by name through the supplied
91. * class loader, and it has the advantage that using a string
92. * representation of a class makes for an implicit weak
93. * reference to the class.
94. */
95. Object key = Arrays.asList(interfaceNames);//这里把Interface数组转换成list..这里直接写成了Object类型
96.
97. /*
98. * Find or create the proxy class cache for the class loader.
99. */
100. Map cache;//放缓存的Map
101. synchronized (loaderToCache) {//loaderToCache也是一个Map.它的key是classloader,对应的value是对应的缓存,也是一个HashMap.他把对应的不同的classloader放到loaderToCache里,如果下次还要调用这个方法创建代理,并传入的是同一个classloader,那么可以直接从cache里取..增加速度.当然,如果没有,则创建一条记录,放到loaderToCache里
102. cache = (Map) loaderToCache.get(loader);
103. if (cache == null) {
104. cache = new HashMap();
105. loaderToCache.put(loader, cache);
106. }
107. /*
108. * This mapping will remain valid for the duration of this
109. * method, without further synchronization, because the mapping
110. * will only be removed if the class loader becomes unreachable.
111. */
112. }
113.
114. /*
115. * Look up the list of interfaces in the proxy class cache using
116. * the key. This lookup will result in one of three possible
117. * kinds of values:
118. * null, if there is currently no proxy class for the list of
119. * interfaces in the class loader,
120. * the pendingGenerationMarker object, if a proxy class for the
121. * list of interfaces is currently being generated,
122. * or a weak reference to a Class object, if a proxy class for
123. * the list of interfaces has already been generated.
124. */
125. synchronized (cache) {
126. /*
127. * Note that we need not worry about reaping the cache for
128. * entries with cleared weak references because if a proxy class
129. * has been garbage collected, its class loader will have been
130. * garbage collected as well, so the entire cache will be reaped
131. * from the loaderToCache map.
132. */
133. do {
134. Object value = cache.get(key);//这里从cache里获取对应的Object..第一次执行的话,明显获取到的是Null..key表示的是用接口名字转换而来的list..这个可以看上面的代码.
135. if (value instanceof Reference) {
136. proxyClass = (Class) ((Reference) value).get();//如果已经能获取到了,那么,我们需要的二进制码文件就是这个获取到的
137. }
138. if (proxyClass != null) {
139. // proxy class already generated: return it
140. return proxyClass;
141. } else if (value == pendingGenerationMarker) {//这里的pendingGenerationMarker是一个静态常量,表示 new Object().JDK给出的 解释是,如果代理正在创建,那么等待他
142. // proxy class being generated: wait for it
143. try {
144. cache.wait();
145. } catch (InterruptedException e) {
146. /*
147. * The class generation that we are waiting for should
148. * take a small, bounded time, so we can safely ignore
149. * thread interrupts here.
150. */
151. }
152. continue;
153. } else {
154. /*
155. * No proxy class for this list of interfaces has been
156. * generated or is being generated, so we will go and
157. * generate it now. Mark it as pending generation.
158. */
159. cache.put(key, pendingGenerationMarker);//如果cache里获取到的对应于key的value是Null ,那么,就创建一个object对象放进去.上面说了,pendingGenerationMarker= new Object();
160. break;
161. }
162. } while (true);
163. }
164.
165. try {
166. String proxyPkg = null; // package to define proxy class in 这个是代理类的包名
167.
168. /*
169. * Record the package of a non-public proxy interface so that the
170. * proxy class will be defined in the same package. Verify that
171. * all non-public proxy interfaces are in the same package.
172. */
173. for (int i = 0; i < interfaces.length; i++) {
174. int flags = interfaces[i].getModifiers();//getModifiers()方法返回的是该接口的修饰类型,用Int类型表示
175. if (!Modifier.isPublic(flags)) {//如果不是public 的接口..
176.
177. //我们可以这样理解,我们动态创建的代理,他的修饰类型必须是和接口的修饰类型是一样的,我们知道,接口可以是public或者默认,两种修饰类型.这里的判断如果不是public接口,那么,该接口肯定是默认的,如果是默认修饰类型,那么,它只能被同一个包下面的类看到,所以,就必须为该代理类创建一个包名..当然,如果是public的话,就没必要,因为,反正所有的类都能看到..
178. String name = interfaces[i].getName();
179. int n = name.lastIndexOf('.');
180. String pkg = ((n == -1) ? "" : name.substring(0, n + 1));//注意这里的N+1 ,其实是包括 "."的..比如 com.cjb.proxy.Proxy..它返回的就是"com.cjb.proxy."注意最后的那个点
181.
182. if (proxyPkg == null) {
183. proxyPkg = pkg;
184. } else if (!pkg.equals(proxyPkg)) {
185. throw new IllegalArgumentException(
186. "non-public interfaces from different packages");
187. }
188. }
189. }
190.
191. if (proxyPkg == null) { // if no non-public proxy interfaces,这里可以看到,如果是public 的接口,对应代理类的包名就是"",也就是没有包名
192. proxyPkg = ""; // use the unnamed package
193. }
194.
195. {
196. /*
197. * Choose a name for the proxy class to generate.
198. */
199. long num;
200. synchronized (nextUniqueNumberLock) {
201. num = nextUniqueNumber++;//Num是一个计数器.用处是,创建代理的类名的时候用..我们可以看到,它是初始值是0.然后,每被调用一次,Num++.
202. }
203. String proxyName = proxyPkg + proxyClassNamePrefix + num;//proxyPkg是之前生成的包名, proxyClassNamePrefix 是一个静态常量,proxyClassNamePrefix="$Proxy".最后Num是计数器.也就是说,它的代理类的名字是从 $Proxy1 $Proxy2 $Proxy3一直在增长的,这样的话,就避免了重复.
204. /*
205. * Verify that the class loader hasn't already
206. * defined a class with the chosen name.
207. */
208.
209. /*
210. * Generate the specified proxy class.下面打红字的两个方法是最后生成代理对象的..但是,很悲剧的是,他是用native修饰的,也就是说,它是不是用java来实现的..也就是说,最最关键的地方,不是用java实现的...
211. */
212. byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
213. proxyName, interfaces);
214. try {
215. proxyClass = defineClass0(loader, proxyName,
216. proxyClassFile, 0, proxyClassFile.length);
217. } catch (ClassFormatError e) {
218. /*
219. * A ClassFormatError here means that (barring bugs in the
220. * proxy class generation code) there was some other
221. * invalid aspect of the arguments supplied to the proxy
222. * class creation (such as virtual machine limitations
223. * exceeded).
224. */
225. throw new IllegalArgumentException(e.toString());
226. }
227. }
228. // add to set of all generated proxy classes, for isProxyClass
229. proxyClasses.put(proxyClass, null);
230.
231. } finally {
232. /*
233. * We must clean up the "pending generation" state of the proxy
234. * class cache entry somehow. If a proxy class was successfully
235. * generated, store it in the cache (with a weak reference);
236. * otherwise, remove the reserved entry. In all cases, notify
237. * all waiters on reserved entries in this cache.
238. */
239. synchronized (cache) {
240. if (proxyClass != null) {
241. cache.put(key, new WeakReference(proxyClass));
242. } else {
243. cache.remove(key);
244. }
245. cache.notifyAll();
246. }
247. }
248. return proxyClass;
249. }
Java的动态代理机制早在其1.3版本就已经引入了。在jdk1.5中,动态代理机制主要由两个类来实现,他们是Proxy类和InvocationHandler接口,他们都可以在java.lang.reflect包下面找到。
InvocationHandler接口里面只有一个方法invoke,为了使用的java的动态代理,用户需要实现这个接口,并且在invoke方法中写好调用实际方法的代码,同时还能在调用实际方法的前后加上其他的逻辑,比如日志或者事物操作等等。这个接口的实现类最终会被由jdk生成的动态代理类使用来调用实际的方法。关于如何使用java动态代理,请参阅网上其它文章,下面将要就Proxy生成动态代理类的源码进行分析。
在Proxy类里面,有两个方法跟动态代理类的生成有关,他们是:
Java代码
1. public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,
2. InvocationHandler h) throws IllegalArgumentException;
3.
4. public static Class<?> getProxyClass(ClassLoader loader, Class<?>... interfaces)
5. throws IllegalArgumentException
第一个方法比较简单,代码如下:
Java代码
1. public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
2. throws IllegalArgumentException{
3. if (h == null) {
4. throw new NullPointerException();
5. }
6. /*
7. * Look up or generate the designated proxy class.
8. */
9. Class cl = getProxyClass(loader, interfaces);
10. /*
11. * Invoke its constructor with the designated invocation handler.
12. */
13. try {
14. Constructor cons = cl.getConstructor(constructorParams);
15. return (Object) cons.newInstance(new Object[] { h });
16. } catch (NoSuchMethodException e) {
17. throw new InternalError(e.toString());
18. } catch (IllegalAccessException e) {
19. throw new InternalError(e.toString());
20. } catch (InstantiationException e) {
21. throw new InternalError(e.toString());
22. } catch (InvocationTargetException e) {
23. throw new InternalError(e.toString());
24. }
25. }
可以看到,在newProxyInstance方法内部调用了getProxyClass方法,然后使用反射机制来创建由getProxyClass返回的动态代理类的实例。所以让我们重点来看一下getProxyClass这个方法。首先要说明一下在getProxyClass里面用到的几个类私有变量的作用。
Java代码
1. /** maps a class loader to the proxy class cache for that loader */
2. private static Map loaderToCache = new WeakHashMap();
3. 这个变量用来保存某个类加载器以及使用该加载器加载的动态代理类集合。key为类加载器,
4. value则是一个HashMap,里面放了具体的动态代理类,和用来索引的key。使用WeakHashMap是处于性能的考虑
5. /** marks that a particular proxy class is currently being generated */
6. private static Object pendingGenerationMarker = new Object();
7. 用来标识一个动态代理类正在被创建,主要用来处理多线程的情况
8. /** next number to use for generation of unique proxy class names */
9. private static long nextUniqueNumber = 0;//用来生成唯一的动态代理类名时候用到
10. private static Object nextUniqueNumberLock = new Object();//锁对象
11. /** set of all generated proxy classes, for isProxyClass implementation */
12. private static Map proxyClasses = Collections.synchronizedMap(new WeakHashMap());
13. 这个变量用来保存所有生成的所有动态代理类,主要是为了方便另外一个方法isProxyClass的使用设置的,在getProxyClass这个方法里面是没有什么用处的。同样适用的WeakHashMap,也是出于性能的考虑,不至于因为proxyClasses持有动态代理类的应用而导致垃圾回收器没法回收不再使用的动态代理类。
好了,介绍了变量,我们可以来关注一下getProxyClass方法了,这个方法大致可以分为三步,第一步是把传入的interface类的名字保存下来,第二步检查要用户请求的动态代理类是否已经存在了,如果已经存在那么就直接返回之前创建好的动态代理类。第三步就是当用户请求的动态代理类不存在的时候去创建这个动态代理类。让我们分别看一下这几部分的代码。
[list]
• 第一步:
Java代码
1. /* collect interface names to use as key for proxy class cache */
2. String[] interfaceNames = new String[interfaces.length];
3.
4. for (int i = 0; i < interfaces.length; i++) {
5. /*
6. * Verify that the class loader resolves the name of this
7. * interface to the same Class object.
8. */
9. String interfaceName = interfaces[i].getName();
10. Class interfaceClass = null;
11. try {
12. interfaceClass = Class.forName(interfaceName, false, loader);
13. } catch (ClassNotFoundException e) {
14. }
15. if (interfaceClass != interfaces[i]) {
16. throw new IllegalArgumentException(
17. interfaces[i] + " is not visible from class loader");
18. }
19.
20. /*
21. * Verify that the Class object actually represents an
22. * interface.
23. */
24. if (!interfaceClass.isInterface()) {
25. throw new IllegalArgumentException(
26. interfaceClass.getName() + " is not an interface");
27. }
28.
29. interfaceNames[i] = interfaceName;
30. }
这一步比较好理解,就是获得各个interface类的名字,然后保存到一个字符串数组中。其中做了好几步的检查。需要说明的是,这个生成数组将会被用来作为索引动态代理类的key。
• 第二步:
Java代码
1. //将之前生成的接口名字数组转成List,用来作为基于这组接口生成的动态代理
2. //类的索引
3. Object key = Arrays.asList(interfaceNames);
4. /*
5. * 检查对于作为参数输入的类加载器是否已经创建过了动态代理类缓存,如果没有
6. * 就创建一个,如果有就取出来。
7. */
8. Map cache;
9. synchronized (loaderToCache) {
10. cache = (Map) loaderToCache.get(loader);
11. if (cache == null) {
12. cache = new HashMap();
13. loaderToCache.put(loader, cache);
14. }
15. //下面这段话说明了使用WeakHashMap的好处
16. /*
17. * This mapping will remain valid for the duration of this
18. * method, without further synchronization, because the mapping
19. * will only be removed if the class loader becomes unreachable.
20. */
21. }
22. //下面这段代码用来检查实现了指定接口的动态代理是否已经被创建过了。
23. synchronized (cache) {
24. do{
25. //尝试用key从动态代理cache中取动态代理
26. Object value = cache.get(key);
27. if (value instanceof Reference) {
28. proxyClass = (Class) ((Reference) value).get();
29. }
30. //如果动态代理已经存在,那么就直接返回找到的动态代理
31. if (proxyClass != null) {
32. // proxy class already generated: return it
33. return proxyClass;
34. }
35. //如果没有找到动态代理,但是发现key对应的是一个
36. //pendingGenerationMarker对象,那就说面之前已经有别的线程已经在
37. //创建这个动态代理了,所以进入等待状态。负责创建的动态代理的
38. //那个线程创建完动态代理之后就会notify所有在cache上wait的线程
39. //这些线程被激活后就会继续执行do循环,然后发现动态代理已经被创建
40. //了,所以就直接返回被创建了动态代理
41. else if (value == pendingGenerationMarker) {
42. // proxy class being generated: wait for it
43. try {
44. cache.wait();
45. } catch (InterruptedException e) {
46. /*
47. * The class generation that we are waiting for should
48. * take a small, bounded time, so we can safely ignore
49. * thread interrupts here.
50. */
51. }
52. continue;
53. }
54. //如果发现自己是第一个要创建动态代理的线程,就在对应的key上
55. //放置pendingGenerationMarker标志对象
56. else {
57. /*
58. * No proxy class for this list of interfaces has been
59. * generated or is being generated, so we will go and
60. * generate it now. Mark it as pending generation.
61. */
62. cache.put(key, pendingGenerationMarker);
63. break;
64. }
65. } while (true);
66. }
• 第三步:创建动态代理
Java代码
1. try {
2. //在动态代理的接口不是public的情况下,保存动态代理所在的包
3. String proxyPkg = null; // package to define proxy class in
4.
5. /*
6. * Record the package of a non-public proxy interface so that the
7. * proxy class will be defined in the same package. Verify that
8. * all non-public proxy interfaces are in the same package.
9. */
10. //在动态代理的接口不是public的情况下,找出动态代理应该被创建在哪个包中
11. //如果出现两个不同的包的非public Inteface就抛错
12. for (int i = 0; i < interfaces.length; i++) {
13. int flags = interfaces[i].getModifiers();
14. if (!Modifier.isPublic(flags)) {
15. String name = interfaces[i].getName();
16. int n = name.lastIndexOf('.');
17. String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
18. if (proxyPkg == null) {
19. proxyPkg = pkg;
20. }
21. else if (!pkg.equals(proxyPkg))
22. {
23. throw new IllegalArgumentException(
24. "non-public interfaces from different packages");
25. }
26. }
27. }
28. if (proxyPkg == null) { // if no non-public proxy interfaces,
29. proxyPkg = ""; // use the unnamed package
30. }
31.
32. {
33. /*
34. * Choose a name for the proxy class to generate.
35. */
36. //去一个数字,用来作为生成的动态代理的一部分
37. long num;
38. synchronized (nextUniqueNumberLock) {
39. num = nextUniqueNumber++;
40. }
41. //动态代理类的名字,proxyClassNamePrefix是固定的,值为"$Proxy"
42. //java中合法的类名和变量名可以以$符开头
43. String proxyName = proxyPkg + proxyClassNamePrefix + num;
44. /*
45. * Verify that the class loader hasn't already
46. * defined a class with the chosen name.
47. */
48.
49. /*
50. * Generate the specified proxy class.
51. */
52. //下面就是创建动态代理的类文件,然后把生成的动态代理类加载进
53. //JVM中,下面用到的几个方法是java语言比较低层的机制,这里就
54. //不说了,有兴趣的可以看看源代码
55. byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
56. proxyName, interfaces);
57. try {
58. proxyClass = defineClass0(loader, proxyName,
59. proxyClassFile, 0, proxyClassFile.length);
60. } catch (ClassFormatError e) {
61. /*
62. * A ClassFormatError here means that (barring bugs in the
63. * proxy class generation code) there was some other
64. * invalid aspect of the arguments supplied to the proxy
65. * class creation (such as virtual machine limitations
66. * exceeded).
67. */
68. throw new IllegalArgumentException(e.toString());
69. }
70. }
71. // add to set of all generated proxy classes, for isProxyClass
72. proxyClasses.put(proxyClass, null);
73.
74. finally {
75. /*
76. * We must clean up the "pending generation" state of the proxy
77. * class cache entry somehow. If a proxy class was successfully
78. * generated, store it in the cache (with a weak reference);
79. * otherwise, remove the reserved entry. In all cases, notify
80. * all waiters on reserved entries in this cache.
81. */
82. //这里是用来擦屁股的,首先把生成的动态代理类加到对应的cache里面,然后
83. //去激活所有被同一个cache阻塞的线程,通知他们动态代理已经生成的,好让
84. //他们继续执行。
85. //如果动态代理因为各种情况没有生成成功,那么就把cache里面的key删除掉
86. synchronized (cache) {
87. if (proxyClass != null) {
88. cache.put(key, new WeakReference(proxyClass));
89. } else {
90. cache.remove(key);
91. }
92. cache.notifyAll();
93. }
94.
95. return proxyClass;
[java] view plaincopy
1. 读源码,怕过两天又忘记了,还是记录下吧..
2.
3. 动态代理最重要的实现就是Proxy.newInstance ,那我们直接看这个方法
4.
5. public static Object newProxyInstance(ClassLoader loader,
6. Class<?>[] interfaces,
7. InvocationHandler h)//这里有三个参数,第一个是传入classloader,一般情况是传入当前的classloader.但是我在上一节模拟实现里传入的是URL loader..第二个参数表示的是接口,第三个是Invocationhandler,除了第一个参数,其他和我在上一节里的一样.JDK的封装的比较好,所以他传入的是Interface的数组,
8. throws IllegalArgumentException
9. {
10. if (h == null) {
11. throw new NullPointerException();//如果Invocationhandler 为空,抛异常
12. }
13.
14. /*
15. * Look up or generate the designated proxy class.这个方法里最主要的地方在这里,它直接通过调用 getProxyClass方法获取到了自动生成的动态代理类的二进制码.在我上一节的内容里,我们是通过自己生成JAVA文件,然后通过JAVA文件动态编译成对应的class文件,然后通过URLClassLoader.loadClass("com.cjb.proxy.Proxy1");这个方法来获取对应的二进制码的.这个方法下面会继续解释.
16. */
17. Class cl = getProxyClass(loader, interfaces);
18.
19. /*
20. * Invoke its constructor with the designated invocation handler.这个方法就是获取对应class的Constructor,然后通过这个Constructor来实例化..
21. */
22. try {
23. Constructor cons = cl.getConstructor(constructorParams);
24. return (Object) cons.newInstance(new Object[] { h });
25. } catch (NoSuchMethodException e) {
26. throw new InternalError(e.toString());
27. } catch (IllegalAccessException e) {
28. throw new InternalError(e.toString());
29. } catch (InstantiationException e) {
30. throw new InternalError(e.toString());
31. } catch (InvocationTargetException e) {
32. throw new InternalError(e.toString());
33. }
34. }
35.
36. 上面的方法,除了最重要的getProxyClass,其他都很容易理解.,那么下面开始读getProxyClass方法
37.
38. public static Class<?> getProxyClass(ClassLoader loader,
39. Class<?>... interfaces)
40. throws IllegalArgumentException
41. {
42. if (interfaces.length > 65535) {
43. throw new IllegalArgumentException("interface limit exceeded");//JDK想的果然比较到位,连interface传的太多都想到了..~!~
44. }
45.
46. Class proxyClass = null;//这个就是最后要生成的二进制码,首先初始化一下
47.
48. /* collect interface names to use as key for proxy class cache */
49. String[] interfaceNames = new String[interfaces.length];//这个存放的是对应的Interface的名字..
50.
51. Set interfaceSet = new HashSet(); //这个HashSet 是为了检测interface重复记录的.
52.
53. for (int i = 0; i < interfaces.length; i++) {
54. /*
55. * Verify that the class loader resolves the name of this
56. * interface to the same Class object.
57. */
58. String interfaceName = interfaces[i].getName();
59. Class interfaceClass = null;
60. try {
61. interfaceClass = Class.forName(interfaceName, false, loader);//创建对应接口的二进制码,第二个参数false表示,不需要初始化
62. } catch (ClassNotFoundException e) {
63. }
64. if (interfaceClass != interfaces[i]) {//如果创建出来的二进制码和原来的接口不一样,表示这个接口对于这个classloader来说是不可见的
65. throw new IllegalArgumentException(
66. interfaces[i] + " is not visible from class loader");
67. }
68.
69. /*
70. * Verify that the Class object actually represents an
71. * interface.
72. */
73. if (!interfaceClass.isInterface()) {//如果不是接口,那么就抛异常,这里就规定了,我们必须通过接口来代理..或者说,必须面向接口编程
74. throw new IllegalArgumentException(
75. interfaceClass.getName() + " is not an interface");
76. }
77.
78. /*
79. * Verify that this interface is not a duplicate.前面说,InterfaceSet是拿来判断对应的interface接口是否有重复的.这里的方法是:在循环interfaces的时候,把每个interface都添加到interfaceSet里..当然,在添加之前会判断,当前循环到的接口在InterfaceSet里是否有,如果已经有了,则抛异常,说这个接口重复了..没有,则添加..
80. */
81. if (interfaceSet.contains(interfaceClass)) {
82. throw new IllegalArgumentException(
83. "repeated interface: " + interfaceClass.getName());
84. }
85. interfaceSet.add(interfaceClass);
86.
87. interfaceNames[i] = interfaceName;//这句就是把每个接口名放到interfaceNames数组里..
88. }
89.
90. /*
91. * Using string representations of the proxy interfaces as
92. * keys in the proxy class cache (instead of their Class
93. * objects) is sufficient because we require the proxy
94. * interfaces to be resolvable by name through the supplied
95. * class loader, and it has the advantage that using a string
96. * representation of a class makes for an implicit weak
97. * reference to the class.
98. */
99. Object key = Arrays.asList(interfaceNames);//这里把Interface数组转换成list..这里直接写成了Object类型
100.
101. /*
102. * Find or create the proxy class cache for the class loader.
103. */
104. Map cache;//放缓存的Map
105. synchronized (loaderToCache) {//loaderToCache也是一个Map.它的key是classloader,对应的value是对应的缓存,也是一个HashMap.他把对应的不同的classloader放到loaderToCache里,如果下次还要调用这个方法创建代理,并传入的是同一个classloader,那么可以直接从cache里取..增加速度.当然,如果没有,则创建一条记录,放到loaderToCache里
106. cache = (Map) loaderToCache.get(loader);
107. if (cache == null) {
108. cache = new HashMap();
109. loaderToCache.put(loader, cache);
110. }
111. /*
112. * This mapping will remain valid for the duration of this
113. * method, without further synchronization, because the mapping
114. * will only be removed if the class loader becomes unreachable.
115. */
116. }
117.
118. /*
119. * Look up the list of interfaces in the proxy class cache using
120. * the key. This lookup will result in one of three possible
121. * kinds of values:
122. * null, if there is currently no proxy class for the list of
123. * interfaces in the class loader,
124. * the pendingGenerationMarker object, if a proxy class for the
125. * list of interfaces is currently being generated,
126. * or a weak reference to a Class object, if a proxy class for
127. * the list of interfaces has already been generated.
128. */
129. synchronized (cache) {
130. /*
131. * Note that we need not worry about reaping the cache for
132. * entries with cleared weak references because if a proxy class
133. * has been garbage collected, its class loader will have been
134. * garbage collected as well, so the entire cache will be reaped
135. * from the loaderToCache map.
136. */
137. do {
138. Object value = cache.get(key);//这里从cache里获取对应的Object..第一次执行的话,明显获取到的是Null..key表示的是用接口名字转换而来的list..这个可以看上面的代码.
139. if (value instanceof Reference) {
140. proxyClass = (Class) ((Reference) value).get();//如果已经能获取到了,那么,我们需要的二进制码文件就是这个获取到的
141. }
142. if (proxyClass != null) {
143. // proxy class already generated: return it
144. return proxyClass;
145. } else if (value == pendingGenerationMarker) {//这里的pendingGenerationMarker是一个静态常量,表示 new Object().JDK给出的 解释是,如果代理正在创建,那么等待他
146. // proxy class being generated: wait for it
147. try {
148. cache.wait();
149. } catch (InterruptedException e) {
150. /*
151. * The class generation that we are waiting for should
152. * take a small, bounded time, so we can safely ignore
153. * thread interrupts here.
154. */
155. }
156. continue;
157. } else {
158. /*
159. * No proxy class for this list of interfaces has been
160. * generated or is being generated, so we will go and
161. * generate it now. Mark it as pending generation.
162. */
163. cache.put(key, pendingGenerationMarker);//如果cache里获取到的对应于key的value是Null ,那么,就创建一个object对象放进去.上面说了,pendingGenerationMarker= new Object();
164. break;
165. }
166. } while (true);
167. }
168.
169. try {
170. String proxyPkg = null; // package to define proxy class in 这个是代理类的包名
171.
172. /*
173. * Record the package of a non-public proxy interface so that the
174. * proxy class will be defined in the same package. Verify that
175. * all non-public proxy interfaces are in the same package.
176. */
177. for (int i = 0; i < interfaces.length; i++) {
178. int flags = interfaces[i].getModifiers();//getModifiers()方法返回的是该接口的修饰类型,用Int类型表示
179. if (!Modifier.isPublic(flags)) {//如果不是public 的接口..
180.
181. //我们可以这样理解,我们动态创建的代理,他的修饰类型必须是和接口的修饰类型是一样的,我们知道,接口可以是public或者默认,两种修饰类型.这里的判断如果不是public接口,那么,该接口肯定是默认的,如果是默认修饰类型,那么,它只能被同一个包下面的类看到,所以,就必须为该代理类创建一个包名..当然,如果是public的话,就没必要,因为,反正所有的类都能看到..
182. String name = interfaces[i].getName();
183. int n = name.lastIndexOf('.');
184. String pkg = ((n == -1) ? "" : name.substring(0, n + 1));//注意这里的N+1 ,其实是包括 "."的..比如 com.cjb.proxy.Proxy..它返回的就是"com.cjb.proxy."注意最后的那个点
185.
186. if (proxyPkg == null) {
187. proxyPkg = pkg;
188. } else if (!pkg.equals(proxyPkg)) {
189. throw new IllegalArgumentException(
190. "non-public interfaces from different packages");
191. }
192. }
193. }
194.
195. if (proxyPkg == null) { // if no non-public proxy interfaces,这里可以看到,如果是public 的接口,对应代理类的包名就是"",也就是没有包名
196. proxyPkg = ""; // use the unnamed package
197. }
198.
199. {
200. /*
201. * Choose a name for the proxy class to generate.
202. */
203. long num;
204. synchronized (nextUniqueNumberLock) {
205. num = nextUniqueNumber++;//Num是一个计数器.用处是,创建代理的类名的时候用..我们可以看到,它是初始值是0.然后,每被调用一次,Num++.
206. }
207. String proxyName = proxyPkg + proxyClassNamePrefix + num;//proxyPkg是之前生成的包名, proxyClassNamePrefix 是一个静态常量,proxyClassNamePrefix="$Proxy".最后Num是计数器.也就是说,它的代理类的名字是从 $Proxy1 $Proxy2 $Proxy3一直在增长的,这样的话,就避免了重复.
208. /*
209. * Verify that the class loader hasn't already
210. * defined a class with the chosen name.
211. */
212.
213. /*
214. * Generate the specified proxy class.下面打红字的两个方法是最后生成代理对象的..但是,很悲剧的是,他是用native修饰的,也就是说,它是不是用java来实现的..也就是说,最最关键的地方,不是用java实现的...
215. */
216. byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
217. proxyName, interfaces);
218. try {
219. proxyClass = defineClass0(loader, proxyName,
220. proxyClassFile, 0, proxyClassFile.length);
221. } catch (ClassFormatError e) {
222. /*
223. * A ClassFormatError here means that (barring bugs in the
224. * proxy class generation code) there was some other
225. * invalid aspect of the arguments supplied to the proxy
226. * class creation (such as virtual machine limitations
227. * exceeded).
228. */
229. throw new IllegalArgumentException(e.toString());
230. }
231. }
232. // add to set of all generated proxy classes, for isProxyClass
233. proxyClasses.put(proxyClass, null);
234.
235. } finally {
236. /*
237. * We must clean up the "pending generation" state of the proxy
238. * class cache entry somehow. If a proxy class was successfully
239. * generated, store it in the cache (with a weak reference);
240. * otherwise, remove the reserved entry. In all cases, notify
241. * all waiters on reserved entries in this cache.
242. */
243. synchronized (cache) {
244. if (proxyClass != null) {
245. cache.put(key, new WeakReference(proxyClass));
246. } else {
247. cache.remove(key);
248. }
249. cache.notifyAll();
250. }
251. }
252. return proxyClass;
253. }
254.
255. 可以看到,我们想看的,最重要的生成二进制码的方法,是native的..读了这么多源码,都是一些前期处理.关键的地方不知道..当然,虽然没看到关键的地方,但是对于它前面的处理的学习,也是非常有用的..看看JDK是怎么处理重名问题的,怎么处理cache.等等..
一.相关类及其方法:
java.lang.reflect.Proxy,
Proxy 提供用于创建动态代理类和实例的静态方法.
newProxyInstance()
返回一个指定接口的代理类实例,该接口可以将方法调用指派到指定的调用处理程序
(详见api文档)
java.lang.reflect.InvocationHandler,
InvocationHandler 是代理实例的调用处理程序 实现的接口。
invoke()
在代理实例上处理方法调用并返回结果。在与方法关联的代理实例上调用方法时,将在调用处理程序上调用此方法。
(详见api文档)
二.源代码:
被代理对象的接口及实现类:
Java代码
1. package com.ml.test;
2.
3. public interface Manager {
4. public void modify();
5. }
6.
7. package com.ml.test;
8.
9. public class ManagerImpl implements Manager {
10.
11. @Override
12. public void modify() {
13. System.out.println("*******modify()方法被调用");
14. }
15. }
业务代理类:
Java代码
1. package com.ml.test;
2.
3. import java.lang.reflect.InvocationHandler;
4. import java.lang.reflect.Method;
5.
6. public class BusinessHandler implements InvocationHandler {
7.
8. private Object object = null;
9.
10. public BusinessHandler(Object object) {
11. this.object = object;
12. }
13.
14. @Override
15. public Object invoke(Object proxy, Method method, Object[] args)
16. throws Throwable {
17. System.out.println("do something before method");
18. Object ret = method.invoke(this.object, args);
19. System.out.println("do something after method");
20. return ret;
21.
22. }
23. }
客户端类:
Java代码
1. package com.ml.test;
2. import java.lang.reflect.Proxy;
3. public class Client {
4.
5. public static void main(String[] args) {
6. // 元对象(被代理对象)
7. ManagerImpl managerImpl = new ManagerImpl();
8.
9. // 业务代理类
10. BusinessHandler securityHandler = new BusinessHandler(managerImpl);
11.
12. // 获得代理类($Proxy0 extends Proxy implements Manager)的实例.
13. Manager managerProxy = (Manager) Proxy.newProxyInstance(managerImpl
14. .getClass().getClassLoader(), managerImpl.getClass()
15. .getInterfaces(), securityHandler);
16.
17. managerProxy.modify();
18. }
19. }
三.执行结果:
do something before method
*******modify()方法被调用
do something after method
四.机制分析:
Proxy.(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)做了以下几件事.
(1)根据参数loader和interfaces调用方法 getProxyClass(loader, interfaces)创建代理类$Proxy.
$Proxy0类实现了interfaces的接口,并继承了Proxy类.
(2)实例化$Proxy0并在构造方法中把BusinessHandler传过去,接着$Proxy0调用父类Proxy的构造器,为h赋值,如下:
Java代码
1. class Proxy{
2. InvocationHandler h=null;
3. protected Proxy(InvocationHandler h) {
4. this.h = h;
5. }
6. ...
7. }
下面是本例的$Proxy0类的源码(好不容易才把它提出来,改了JRE源码,打印出字节码,把字节码保存为class文件,并反编译class文件):
Java代码
1. import java.lang.reflect.InvocationHandler;
2. import java.lang.reflect.Method;
3. import java.lang.reflect.Proxy;
4. import java.lang.reflect.UndeclaredThrowableException;
5.
6. public final class $Proxy0 extends Proxy implements Manager {
7.
8. private static Method m1;
9. private static Method m0;
10. private static Method m3;
11. private static Method m2;
12.
13. static {
14. try {
15. m1 = Class.forName("java.lang.Object").getMethod("equals",
16. new Class[] { Class.forName("java.lang.Object") });
17. m0 = Class.forName("java.lang.Object").getMethod("hashCode",
18. new Class[0]);
19. m3 = Class.forName("com.ml.test.Manager").getMethod("modify",
20. new Class[0]);
21. m2 = Class.forName("java.lang.Object").getMethod("toString",
22. new Class[0]);
23. } catch (NoSuchMethodException nosuchmethodexception) {
24. throw new NoSuchMethodError(nosuchmethodexception.getMessage());
25. } catch (ClassNotFoundException classnotfoundexception) {
26. throw new NoClassDefFoundError(classnotfoundexception.getMessage());
27. }
28. }
29.
30. public $Proxy0(InvocationHandler invocationhandler) {
31. super(invocationhandler);
32. }
33.
34. @Override
35. public final boolean equals(Object obj) {
36. try {
37. return ((Boolean) super.h.invoke(this, m1, new Object[] { obj }))
38. .booleanValue();
39. } catch (Throwable throwable) {
40. throw new UndeclaredThrowableException(throwable);
41. }
42. }
43.
44. @Override
45. public final int hashCode() {
46. try {
47. return ((Integer) super.h.invoke(this, m0, null)).intValue();
48. } catch (Throwable throwable) {
49. throw new UndeclaredThrowableException(throwable);
50. }
51. }
52.
53. public final void modify() {
54. try {
55. super.h.invoke(this, m3, null);
56. return;
57. } catch (Error e) {
58. } catch (Throwable throwable) {
59. throw new UndeclaredThrowableException(throwable);
60. }
61. }
62.
63. @Override
64. public final String toString() {
65. try {
66. return (String) super.h.invoke(this, m2, null);
67. } catch (Throwable throwable) {
68. throw new UndeclaredThrowableException(throwable);
69. }
70. }
71. }
接着把得到的$Proxy0实例强制转换成Manager.
当执行managerProxy.modify()方法时,就调用了$Proxy0类中的modify()方法.
在modify方法中,调用父类Proxy中的h的invoke()方法.
即InvocationHandler.invoke();
一。首先需要了解下面3个类的API:java系统支持的代理就是这3个类+反射来实现。
Java代码
1. import java.lang.reflect.InvocationHandler;
2. import java.lang.reflect.Method;
3. import java.lang.reflect.Proxy;<pre></pre>
二。下面的这段测试代码,目的就是:将一个ArrayList对象的操作进行代理,每个method前后都输出一行字符串。
核心代码是
Class clz = ArrayList.class;
Object proxyed_Object = Proxy.newProxyInstance(clz.getClassLoader(),
clz.getInterfaces(), new MyInvocationHandle(new ArrayList(10)));
生成一个ArrayList的代理的对象。
Java代码
1. package proxy;
2.
3. import java.lang.reflect.InvocationHandler;
4. import java.lang.reflect.Method;
5. import java.lang.reflect.Proxy;
6. import java.util.ArrayList;
7. import java.util.List;
8.
9. /**
10. * DEMO:测试java中的代理
11. *
12. * 代理了一个ArrayList对象,并在调用方法前后各加了一个systemout输出
13. * @author wei.songw
14. *
15. */
16. public class MyInvocationHandle implements InvocationHandler {
17.
18. //对代理对象的引用.
19. private List aList;
20.
21. /**
22. * 构造器。
23. * @param list 代理对象
24. */
25. public MyInvocationHandle(Object list) {
26. this.aList = (List) list;
27. }
28.
29. /**
30. * InvocationHandler的方法实现
31. */
32. @Override
33. public Object invoke(Object proxy, Method method, Object[] args)
34. throws Throwable {
35.
36. //方法前调用,插入一段消息
37. System.out.println("before : "+method.getName());
38.
39. //调用方法.
40. Object object = method.invoke(aList, args);
41.
42. //方法后调用,插入一段消息
43. System.out.println("after : "+method.getName());
44.
45. return object;
46. }
47.
48.
49.
50. public static void main(String[] args) {
51. //需要代理一个ArrayList对象,因此按照API构造一个Proxy对象
52. //,同时也初始化了处理Proxy的MyInvocationHandle对象
53. Class clz = ArrayList.class;
54. Object proxyed_Object = Proxy.newProxyInstance(clz.getClassLoader(),
55. clz.getInterfaces(), new MyInvocationHandle(new ArrayList(10)));
56.
57. //TEST1:查看一下代理生成类的接口???
58. // Class<!---->[] itfs = proxyed_Object.getClass().getInterfaces();
59. // for (int i = 0; i < itfs.length; i++) {
60. // System.out.println(itfs[i].getName());
61. // }
62.
63. //注意!这里操作的是代理类!
64. List list = (List)proxyed_Object;
65. list.add(Integer.valueOf(10));
66.
67. //TEST2:输出一下list的大小,确认add方法被调用
68. // System.out.println(list.size());
69. }
70. }
71. <pre></pre>
输出如下:
before : add
after : add
如果将TEST2段代码去掉注释,可以看到如下输出:
before : add
after : add
before : size
after : size
1
证明add方法确实被调用了。
三。代理模式的结构图(UML+时序图)
通过UML图可以看到代理类和被代理实际对象实现同一接口/或者一个抽象类,因此外部调用Subject,是感觉不到代理类的存在。
问题出现了:上面的测试代码中,被代理ArrayList对象,并未与调用者MyInvocationHandle实现同样的接口 。那是怎么实现代理模式的呢?
看Proxy类的文档,写到:
Java代码
1. /**
2. * Returns an instance of a proxy class for the specified interfaces
3. * that dispatches method invocations to the specified invocation
4. * handler. This method is equivalent to:
5. * <pre> * Proxy.getProxyClass(loader, interfaces).
6. * getConstructor(new Class[] { InvocationHandler.class }).
7. * newInstance(new Object[] { handler });
8. * </pre>
9. *
10. * <p><code>Proxy.newProxyInstance</code> throws
11. * <code>IllegalArgumentException</code> for the same reasons that
12. * <code>Proxy.getProxyClass</code> does.
13. *
14. * @param loader the class loader to define the proxy class
15. * @param interfaces the list of interfaces for the proxy class
16. * to implement
17. * @param h the invocation handler to dispatch method invocations to
18. * @return a proxy instance with the specified invocation handler of a
19. * proxy class that is defined by the specified class loader
20. * and that implements the specified interfaces
21. * @throws IllegalArgumentException if any of the restrictions on the
22. * parameters that may be passed to <code>getProxyClass</code>
23. * are violated
24. * @throws NullPointerException if the <code>interfaces</code> array
25. * argument or any of its elements are <code>null</code>, or
26. * if the invocation handler, <code>h</code>, is
27. * <code>null</code>
28. */</p><pre></pre><p></p>
返回一个实现指定接口的代理类实例,并绑定方法调用到一个指定的invocation handler.
如果将TEST1段注释去掉,可以看到这个代理对象实现了如下接口:
java.util.List java.util.RandomAccess java.lang.Cloneable java.io.Serializable
并且Proxy.newProxyInstance等同于
* Proxy.getProxyClass(loader, interfaces).
* getConstructor(new Class[] { InvocationHandler.class }).
* newInstance(new Object[] { handler });
这里是部分源码:
Java代码
1. for (int i = 0; i < interfaces.length; i++) {
2. int flags = interfaces[i].getModifiers();
3. if (!Modifier.isPublic(flags)) {
4. String name = interfaces[i].getName();
5. int n = name.lastIndexOf('.');
6. String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
7. if (proxyPkg == null) {
8. proxyPkg = pkg;
9. } else if (!pkg.equals(proxyPkg)) {
10. throw new IllegalArgumentException(
11. "non-public interfaces from different packages");
12. }
13. }
14. }<pre></pre>
通过时序图可以看到,外部Client和代理类打交道,而代理类在调用实际对象时可以增加一些有益的操作。
Java代码
1. /**
2. * JDK 动态代理类分析(java.lang.reflect.Proxy使用)
3. *
4. * @author 张明学
5. *
6. */
7. public class ProxyStudy {
8.
9. @SuppressWarnings("unchecked")
10. public static void main(String[] args) throws Exception {
11. // 动态代理类:通用指定类加载器,和接口产生一类
12. // getProxyClass()返回代理类的 java.lang.Class 对象,并向其提供类加载器和接口数组。
13. Class clazzProxy = Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class);
14. System.out.println("动态产生的类名为:" + clazzProxy.getName());
15. System.out.println("----------获取动态产生的类的构造方法---------");
16. Constructor[] constructors = clazzProxy.getConstructors();
17. int i = 1;
18. for (Constructor constructor : constructors) {
19. System.out.println("第" + (i++) + "个构造方法名:" + constructor.getName());
20. Class[] parameterClazz = constructor.getParameterTypes();
21. System.out.println("第" + (i++) + "个构造方法参数:" + Arrays.asList(parameterClazz));
22. }
23. System.out.println("----------获取动态产生的类的普通方法---------");
24. Method[] methods = clazzProxy.getDeclaredMethods();
25. for (int j = 0; j < methods.length; j++) {
26. Method method = methods[j];
27. System.out.println("第" + (j + 1) + "个普通方法名:" + method.getName());
28. Class[] parameterClazz = method.getParameterTypes();
29. System.out.println("第" + (j + 1) + "个普通方法参数:" + Arrays.asList(parameterClazz));
30. }
31. System.out.println("---------获取动态代理对象的构造方法---------");
32. // 动态代理产生的对象的构造方法需要一个实现java.lang.reflect.InvocationHandler接口的对象,故不能通过
33. // clazzProxy.newInstance();产生一个对象,可以根据构造方法产生一个对象
34. // InvocationHandler 是代理实例的调用处理程序 实现的接口。
35. Constructor constructor = clazzProxy.getConstructor(InvocationHandler.class);
36.
37. // 代理产生的对象
38. Collection proxyBuildCollection = (Collection) constructor
39. .newInstance(new InvocationHandler() {
40. // 为什么这里选择ArrayList作为目标对象?
41. // 因为这里的constructor是clazzProxy这个动态类的构造方法,clazzProxy是通过Proxy.getProxyClass()方法产生的,
42. // 该方法有两个参数,一个是指定类加载器,一个是指定代理要实现的接口,这个接口我上面指定了Collection
43. // 而ArrayList实现了Collection接口,固可以为该动态类的目标对象
44. ArrayList target = new ArrayList();// 动态类的目标对象
45.
46. public Object invoke(Object proxy, Method method,
47. Object[] args) throws Throwable {
48. System.out.println("执行目标" + method.getName() + "方法之前:"
49. + System.currentTimeMillis());
50. Object result = method.invoke(target, args);// 其实代理对象的方法调用还是目标对象的方法
51. System.out.println("执行目标" + method.getName() + "方法之后:"
52. + System.currentTimeMillis());
53. return result;
54. }
55.
56. });
57. proxyBuildCollection.clear();
58. proxyBuildCollection.add("abc");
59. proxyBuildCollection.add("dbc");
60. System.out.println(proxyBuildCollection.size());
61. System.out.println(proxyBuildCollection.getClass().getName());
62.
63. /**
64. * 动态代理:总结如下:
65. * 1,通过Proxy.getProxyClass(classLoader,interface)方法产生一个动态类的class字节码(clazz)
66. * 该getProxyClass()方法有两个参数:一个是指定该动态类的类加载器,一个是该动态类的要实现的接口(从这里可以看现JDK的动态代理必须要实现一个接口)
67. *
68. * 2,通过第一步的获取的clazz对象可以获取它的构造方法constructor,那么就可以通用constructor的newInstance()方法构造出一个动态实体对象
69. * 但constructor的newInstance()方法需要指定一个实现了InvocationHandler接口的类handler,在该类中需要一个目标对象A和实现invoke方法
70. * 目标对象A要求能对第一步中的接口的实现,因为在invoke方法中将会去调用A中的方法并返回结果。
71. * 过程如下:调用动态代理对象ProxyObject的x方法 ————> 进入构造方法传进的handler的invoke方法 ————> invoke方法调用handler中的target对象
72. * 的x方法(所以要求target必须要实现构造动态代理类时指定的接口)并返回它的返回值。(其实如果我们代理P类,那么target就可以选中P类,只是要求P必需实现一个接口)
73. *
74. * 那么上述中x方法有哪些呢?除了从Object继承过来的方法中除toString,hashCode,equals外的方法不交给handler外,其它的方法全部交给handler处理
75. * 如上面proxyBuildCollection.getClass().getName()就没有调用handler的getClass方法,而是调用自己的
76. *
77. * 3,在handler的invoke方法中return method.invoke(target,args)就是将方法交给target去完成。那么在这个方法执行之前,之后,异常时我们都可以做一些操作,
78. * 并且可以在执行之前检查方法的参数args,执行之后检查方法的结果
79. */
80. System.out.println("-------------------下面的写法更简便--------------------");
81.
82. // proxyBuildColl是对ArrayList进行代理
83. Collection proxyBuildCollection2 = (Collection) Proxy.newProxyInstance(
84. Collection.class.getClassLoader(),// 指定类加载器
85. new Class[] { Collection.class },// 指定目标对象实现的接口
86. // 指定handler
87. new InvocationHandler() {
88. ArrayList target = new ArrayList();
89.
90. public Object invoke(Object proxy, Method method,
91. Object[] args) throws Throwable {
92. System.out.println(method.getName() + "执行之前...");
93. if (null != args) {
94. System.out.println("方法的参数:" + Arrays.asList(args));
95. } else {
96. System.out.println("方法的参数:" + null);
97. }
98. Object result = method.invoke(target, args);
99. System.out.println(method.getName() + "执行之后...");
100. return result;
101. }
102. });
103. proxyBuildCollection2.add("abc");
104. proxyBuildCollection2.size();
105. proxyBuildCollection2.clear();
106. proxyBuildCollection2.getClass().getName();
107.
108. System.out.println("-------------------对JDK动态代理的重构--------------------");
109. Set proxySet = (Set) buildProxy(new HashSet(), new MyAdvice());
110. proxySet.add("abc");
111. proxySet.size();
112. }
113. /**
114. * 构造一个目标对象的代理对象
115. *
116. * @param target
117. * 目标对象(需要实现某个接口)
118. * @return
119. */
120. public static Object buildProxy(final Object target,final AdviceInter advice) {
121. Object proxyObject = Proxy.newProxyInstance(
122. target.getClass().getClassLoader(),// 指定类加载器
123. target.getClass().getInterfaces(), // 指定目标对象实现的接口
124. // handler
125. new InvocationHandler() {
126.
127. public Object invoke(Object proxy, Method method,
128. Object[] args) throws Throwable {
129. advice.beforeMethod(target, method, args);
130. Object result = method.invoke(target, args);
131. advice.afterMethod(target, method, args);
132. return result;
133. }
134. });
135. return proxyObject;
136. }
137.
138. }
Java代码
1. /**
2. * 代理中执行目标方法之前之后的操作的一个实例
3. *
4. * @author 张明学
5. *
6. */
7. public class MyAdvice implements AdviceInter {
8.
9. public void afterMethod(Object target, Method method, Object[] args) {
10. System.out.println("目标对象为:" + target.getClass().getName());
11. System.out.println(method.getName() + "执行完毕!");
12. }
13.
14. public void beforeMethod(Object target, Method method, Object[] args) {
15. System.out.println(method.getName() + "开始执行");
16. if (null != args) {
17. System.out.println("参数为:" + Arrays.asList(args));
18. } else {
19. System.out.println("参数为:" + null);
20. }
21. }
22. }
Java代码
1. /**
2. * 代理中执行目标方法之前之后的操作
3. *
4. * @author 张明学
5. *
6. */
7. public interface AdviceInter {
8. /**
9. * 目标方法执行之前
10. *
11. */
12. public void beforeMethod(Object target, Method method, Object[] args);
13.
14. /**
15. * 目标方法执行之后
16. *
17. * @param target
18. * 目标对象
19. * @param method
20. * 方法
21. * @param args
22. * 参数
23. */
24. public void afterMethod(Object target, Method method, Object[] args);
25. }
介绍
代理模式
代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。
按照代理的创建时期,代理类可以分为两种:
静态代理:由程序员创建或特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。
动态代理:在程序运行时,运用反射机制动态创建而成。
在JDK 1.3以后提供了动态代理的技术,允许开发者在运行期创建接口的代理实例。 JDK的动态代理主要涉及到java.lang.reflect包中的两个类:Proxy和InvocationHandler。其中InvocationHandler是一个接口,可以通过实现该接口定义横切逻辑,在并通过反射机制调用目标类的代码,动态将横切逻辑和业务逻辑编织在一起。
一)静态代理:
1.Count.java
[java] view plaincopy
1. <span style="font-size:16px;">package net.battier.dao;
2. /**
3. * 定义一个账户接口
4. *
5. * @author Administrator
6. *
7. */
8. public interface Count {
9. // 查看账户方法
10. public void queryCount();
11. // 修改账户方法
12. public void updateCount();
13. } </span>
2.CountImpl.java
[java] view plaincopy
1. package net.battier.dao.impl;
2. import net.battier.dao.Count;
3. /**
4. * 委托类(包含业务逻辑)
5. *
6. * @author Administrator
7. *
8. */
9. public class CountImpl implements Count {
10. @Override
11. public void queryCount() {
12. System.out.println("查看账户方法...");
13. }
14. @Override
15. public void updateCount() {
16. System.out.println("修改账户方法...");
17. }
18. }
3.CountProxy.java
[java] view plaincopy
1. package net.battier.dao.impl;
2.
3. import net.battier.dao.Count;
4.
5. /**
6. * 这是一个代理类(增强CountImpl实现类)
7. *
8. * @author Administrator
9. *
10. */
11. public class CountProxy implements Count {
12. private CountImpl countImpl;
13.
14. /**
15. * 覆盖默认构造器
16. *
17. * @param countImpl
18. */
19. public CountProxy(CountImpl countImpl) {
20. this.countImpl = countImpl;
21. }
22.
23. @Override
24. public void queryCount() {
25. System.out.println("事务处理之前");
26. // 调用委托类的方法;
27. countImpl.queryCount();
28. System.out.println("事务处理之后");
29. }
30.
31. @Override
32. public void updateCount() {
33. System.out.println("事务处理之前");
34. // 调用委托类的方法;
35. countImpl.updateCount();
36. System.out.println("事务处理之后");
37.
38. }
39.
40. }
4.TestCount.java
[java] view plaincopy
1. Java代码
2. package net.battier.test;
3. import net.battier.dao.impl.CountImpl;
4. import net.battier.dao.impl.CountProxy;
5. /**
6. *测试Count类
7. *
8. * @author Administrator
9. *
10. */
11. public class TestCount {
12. public static void main(String[] args) {
13. CountImpl countImpl = new CountImpl();
14. CountProxy countProxy = new CountProxy(countImpl);
15. countProxy.updateCount();
16. countProxy.queryCount();
17. }
18. }
观察代码可以发现每一个代理类只能为一个接口服务,这样一来程序开发中必然会产生过多的代理,而且,所有的代理操作除了调用的方法不一样之外,其他的操作都一样,则此时肯定是重复代码。解决这一问题最好的做法是可以通过一个代理类完成全部的代理功能,那么此时就必须使用动态代理完成。
二)动态代理
1.定义一个接口和实现类:
[java] view plaincopy
1. <span style="font-weight: normal;"><span style="font-size:16px;">package com.tech.service;
2. public interface PersonService {
3. public String getPersonName(Integer personId);
4. public void save(String name);
5. public void update(Integer personId, String name);
6. }
7.
8. package com.tech.service.impl;
9. import com.tech.service.PersonService;
10. public class PersonServiceBean implements PersonService {
11. public String user = null;
12.
13. public PersonServiceBean(){};
14. public PersonServiceBean(String user){
15. this.user = user;
16. }
17.
18. @Override
19. public String getPersonName(Integer personId) {
20. // TODO Auto-generated method stub
21. System.out.println("这是find方法");
22. return this.user;
23. }
24.
25. @Override
26. public void save(String name) {
27. // TODO Auto-generated method stub
28. System.out.println("这是save方法");
29. }
30.
31. @Override
32. public void update(Integer personId, String name) {
33. // TODO Auto-generated method stub
34. System.out.println("这是update方法");
35. }
36. public String getUser() {
37. return user;
38. }
39. public void setUser(String user) {
40. this.user = user;
41. }
42.
43. }</span></span>
2.JDK动态代理代理类
[java] view plaincopy
1. package com.tech.jdkproxy;
2.
3. import java.lang.reflect.InvocationHandler;
4. import java.lang.reflect.Method;
5. import java.lang.reflect.Proxy;
6.
7. import com.tech.service.impl.PersonServiceBean;
8.
9. /**
10. *
11. * 切面
12. * @author ch
13. *
14. */
15. public class JDKProxyFactory implements InvocationHandler{
16.
17. private Object proxyObject; //目标对象
18.
19. /**
20. * 绑定委托对象并返回一个代理类
21. * @param proxyObject
22. * @return
23. */
24. public Object createProxyInstance(Object proxyObject) {
25. this.proxyObject = proxyObject;
26.
27. //生成代理类的字节码加载器
28. ClassLoader classLoader = proxyObject.getClass().getClassLoader();
29. //需要代理的接口,被代理类实现的多个接口都必须在这里定义 (这是一个缺陷,cglib弥补了这一缺陷)
30. Class<?>[] proxyInterface = proxyObject.getClass().getInterfaces();//new Class[]{};
31.
32. //织入器,织入代码并生成代理类
33. return Proxy.newProxyInstance(classLoader,
34. proxyInterface, this);
35.
36. }
37.
38. @Override
39. public Object invoke(Object proxy, Method method, Object[] args)
40. throws Throwable {
41. PersonServiceBean bean = (PersonServiceBean)this.proxyObject;
42. Object result = null;
43. //控制哪些用户执行切入逻辑
44. if(bean.getUser() != null) {
45. //执行原有逻辑
46. result = method.invoke(this.proxyObject, args);
47. }
48. return result;
49. }
50. }
3.测试类
[java] view plaincopy
1. package com.tech.junit;
2.
3. import org.junit.BeforeClass;
4. import org.junit.Test;
5.
6. import com.tech.jdkproxy.JDKProxyFactory;
7. import com.tech.service.PersonService;
8. import com.tech.service.impl.PersonServiceBean;
9.
10. public class PersonTest {
11.
12. @BeforeClass
13. public static void setUpBeforeClass() throws Exception {
14. }
15.
16. @Test
17. public void Test() {
18. JDKProxyFactory factory = new JDKProxyFactory();
19. PersonService bean = (PersonService) factory
20. .createProxyInstance(new PersonServiceBean("lucy"));
21. //用户为lucy,有权限
22. bean.save("abc");
23.
24. PersonService bean2 = (PersonService) factory
25. .createProxyInstance(new PersonServiceBean());
26. //用户为null,没有权限,不输出
27. bean2.save("abc");
28. }
29. }
JDK的动态代理深入解析(Proxy,InvocationHandler)-I
1. DK首先定义一个接口(动态代理就是建立在接口编程上,这个接口就是被代理对象)
public interface UserDao {
public void save(User user);
public void delete(User user);
public void update(User user);
}
2. 接口的实现类(真实业务的实现)
public class UserDaoImpl implements UserDao {
public void delete(User user) {
System.out.println("删除用户成功。。。。");
}
public void save(User user) {
System.out.println("插入用户成功。。。。");
}
public void update(User user) {
System.out.println("更新用户成功。。。。");
}
}
3. 实现InVocationHandler接口的invoke()方法
public class LogHandler_old implements InvocationHandler {
// 组合的方式引入被代理对象
private Object target = null;
private static Logger logger = Logger.getLogger(LogHandler_old.class);
// 构造函数注入被代理对象
public LogHandler_old(Object target) {
this.target = target;
}
/*
* invoke 必须根据需要 Override
* Proxy.newProxyInstance(...)时候会自动调用这个invoke方法
*/
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
logger.info(method.getName() + "开始执行。。。。");
Object result = method.invoke(target, args);
logger.info(method.getName() + "执行结束。。。。");
return result;
}
}
4. 创建Proxy对象,测试
public class ProxyTest_old {
public static void main(String[] args) {
UserDao userDao = new UserDaoImpl();
LogHandler_old logHandler = new LogHandler_old(userDao);
UserDao userDaProxy = (UserDao) Proxy.newProxyInstance(userDao
.getClass().getClassLoader(), userDao.getClass()
.getInterfaces(), logHandler);
userDaProxy.delete(new User());
userDaProxy.save(new User());
userDaProxy.update(new User());
}
}
解释:
1. Proxy即动态代理类;
2. Static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h):返回代理类的一个实例,返回后的代理类可以当作被代理类使用;
它有三个参数:
ClassLoader loader ----指定被代理对象的类加载器
Class[] Interfaces ----指定被代理对象所以事项的接口
InvocationHandler h ----指定需要调用的InvocationHandler对象
3. 实现InVocationHandler接口的LogHandler_old对象
这个对象的invoke()方法就是Proxy这个动态代理类所代理的接口类的抽象方法的真实实现;
它有三个参数:
Object proxy -----代理类对象
Method method -----被代理对象的方法(这里不是接口的抽象方法了,是具体的实现类中的方法)
Object[] args -----该方法的参数数组
JDK中具体的动态代理类是怎么产生的呢?
1.产生代理类$Proxy0类
执行了Proxy.newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)
将产生$Proxy0类,它继承Proxy对象,并根据第二个参数,实现了被代理类的所有接口,自然就可以生成接口要实现的所有方法了(这时候会重写hashcode,toString和equals三个方法),但是还没有具体的实现体;
2. 将代理类$Proxy0类加载到JVM中
这时候是根据Proxy.newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)它的第一个参数----就是被代理类的类加载器,把当前的代理类加载到JVM中
3. 创建代理类$Proxy0类的对象
调用的$Proxy0类的$Proxy0(InvocationHandler)构造函数,生成$Proxy0类的对象
参数就是Proxy.newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)它的第三个参数
这个参数就是我们自己实现的InvocationHandler对象,我们知道InvocationHandler对象中组合加入了代理类代理的接口类的实现类;所以,$Proxy0对象调用所有要实现的接口的方法,都会调用InvocationHandler对象的invoke()方法实现;
4. 生成代理类的class byte
动态代理生成的都是二进制class字节码