java动态代理为什么只能代理接口(java动态代理和静态代理的区别)

2022-10-26 22:14:15 0

java动态代理为什么只能代理接口(java动态代理和静态代理的区别)

代理:设计模式代理模式是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制对某个真实对象的访问。代理类负责为委托类预处理消息,过滤消息并转发消息,以及进行消息被委托类执行后的后续处理。

通过代理层这一中间层,有效的控制对于真实委托类对象的直接访问,同时可以实现自定义的控制策略(Spring的AOP机制),设计上获得更大的灵活性。

java动态代理的类和接口(jdk1.6源码),java.lang.reflect.Proxy:动态代理机制的主类,提供一组静态方法为一组接口动态的生成对象和代理类。

// 方法 1: 该方法用于获取指定代理对象所关联的调用处理器

public static InvocationHandler getInvocationHandler中并为其定义类对象,然后该类才能被使用。Proxy类与普通类的唯一区别就是其字节码是由 JVM 在运行时动态生成的而非预存在于任何一个 .class 文件中

每次生成动态代理类对象时都需要指定一个类装载器对象:newProxyInstance,第三个参数this代表当前HelloServiceProxy类,换句话说是使用HelloServiceProxy作为对象的代理。

invoke方法有三个参数:第一个proxy是代理对象,第二个是当前调用那个方法,第三个是方法的参数。

public class ProxyTest {

public static void main。当代理类正在被创建时它会临时保存(接口名字列表,pendingGenerationMarker)。标记 pendingGenerationMarke 的作用是通知后续的同类请求(接口数组相同且组内接口排列顺序也相同)代理类正在被创建,请保持等待直至创建完成。

/*

* 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);

}

}

。。。。。

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);

3,动态创建代理类的class对象

/**

* Choose a name for the proxy class to generate.

*/

long num;

synchronized (nextUniqueNumberLock) {

num = nextUniqueNumber++;

}

String proxyName = proxyPkg + proxyClassNamePrefix + num;

/*

* Verify that the class loader hasn't already

* defined a class with the chosen name.

*/

// 动态地生成代理类的字节码数组

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());

}

// 把生成的代理类的类对象记录进 proxyClasses 表

proxyClasses.put(proxyClass, null);

首先根据规则(接口public与否),生成代理类的名称,$ProxyN格式,然后动态生成代理类。

所有的代码生成的工作都由 ProxyGenerator 所完成了,该类在rt.jar中,需要反编译

public static byte[] generateProxyClass(final String name,

Class[] interfaces)

{

ProxyGenerator gen = new ProxyGenerator(name, interfaces);

// 这里动态生成代理类的字节码,由于比较复杂就不进去看了

final byte[] classFile = gen.generateClassFile();

// 如果saveGeneratedFiles的值为true,则会把所生成的代理类的字节码保存到硬盘上

if (saveGeneratedFiles) {

java.security.AccessController.doPrivileged(

new java.security.PrivilegedAction() {

public Void run() {

try {

FileOutputStream file =

new FileOutputStream(dotToSlash(name) + ".class");

file.write(classFile);

file.close();

return null;

} catch (IOException e) {

throw new InternalError(

"I/O exception saving generated file: " + e);

}

}

});

}

// 返回代理类的字节码

return classFile;

}

4,代码生成过程进入结尾部分,根据结果更新缓存表,如果成功则将代理类的类对象引用更新进缓存表,否则清楚缓存表中对应关键值,最后唤醒所有可能的正在等待的线程。

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) {

cache.put(key, new WeakReference(proxyClass));

} else {

cache.remove(key);

}

cache.notifyAll();

}

}

return proxyClass;

InvocationHandler解析代码参考:http://rejoy.iteye.com/blog/1627405

通过getProxyClass0方法中生成具体的class文件的过程,定义path,讲class文件写到指定的磁盘中,反编译生成的代理class文件。

发现在静态代码块中获取了的方法有:Object中的equals方法、Object中的hashCode方法、Object中toString方法 , 以及invoke的接口方法。后语至此,JDK是动态生成代理类,并通过调用解析器,执行接口实现的方法的原理已经一目了然。动态代理加上反射,是很多框架的基础。比如Spring的AOP机制,自定义前置后置通知等控制策略,以及mybatis中的运用反射和动态代理来实现插件技术等等。

文章参考:

http://www.ibm.com/developerworks/cn/java/j-lo-proxy1/index.html

http://blog.csdn.net/ykzhen2015/article/details/50312651

如果大家喜欢这篇文章的话,希望大家能够收藏,转发 谢谢!更多相关资讯可以关注西安华美校区,免费获得java零基础教程!额外附送excel教程!

关键字:  java动态代理为什么只能代理接口  java动态代理和静态代理的区别  java动态代理的实现方式  java动态代理的两种方式  java动态代理使用场景