2007-04-14
JDK的动态代理是如何实现的?
用Spring大概有3个月,一直都是张口AOP,闭口AOP,但是Spring的AOP具体是怎么实现的,现在也不是十分清楚.
只知道可以用JDK的动态代理,基于接口,或者是cglib方式字节码增强.目前对JDK的动态代理方式不是很理解,固拿出来探讨下,我知道这应该是个新手贴,但还是请大家给点意见.如果真正理解了动态代理,那么对基于Spring AOP出现的各种现象就比较容易理解了.
先贴上一段代码.
从以上代码可以看出在调用com.makeCar()的时候动态代理会生效,而在makeCar()方法中调用abc()的时候并不会进行动态代理.
猜测到底JDK是如何实现动态代理的?
1.基于JDK的反射机制,通过JDK调用handler的method.invoke(this.com, new Class[] {});实现对最终方法的调用,前后各有代码也有点Decorator的味道!
2.也是我比较模糊的一点
也就是动态代理JDK到底是如何实现的?
JDK的动态代理并没有生成具体的类,她只是在运行中起动态调用目标类的作用,那么代码
究竟做了什么,是将CarCompany注册到JDK的某个地方,当调用com.makeCar()的时候JDK到注册的地方去寻找,发现有注册就进行动态代理?
只知道可以用JDK的动态代理,基于接口,或者是cglib方式字节码增强.目前对JDK的动态代理方式不是很理解,固拿出来探讨下,我知道这应该是个新手贴,但还是请大家给点意见.如果真正理解了动态代理,那么对基于Spring AOP出现的各种现象就比较容易理解了.
先贴上一段代码.
package com.jamesby.proxy;
public interface CarCompany {
public void makeCar();
public void abc();
}
package com.jamesby.proxy;
public class CarCompanyImpl implements CarCompany {
public void makeCar() {
System.out.println("Company A make a car!");
abc();
}
public void abc()
{
System.out.println("abc is invoked!");
}
}
package com.jamesby.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class CarCompanyHandler implements InvocationHandler {
CarCompany com;
public CarCompanyHandler(CarCompany com) {
this.com = com;
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("time1:" + System.currentTimeMillis());
method.invoke(this.com, new Class[] {});
System.out.println("time2:" + System.currentTimeMillis());
return null;
}
}
package com.jamesby.proxy;
import java.lang.reflect.Proxy;
public class Test {
public static void main(String[] arg) {
CarCompanyImpl a = new CarCompanyImpl();
CarCompanyHandler handler = new CarCompanyHandler(a);
// 产生一个新的代理类
CarCompany com = (CarCompany) Proxy.newProxyInstance(Test.class
.getClassLoader(), new Class[] { CarCompany.class }, handler);
com.makeCar();
}
}
从以上代码可以看出在调用com.makeCar()的时候动态代理会生效,而在makeCar()方法中调用abc()的时候并不会进行动态代理.
猜测到底JDK是如何实现动态代理的?
1.基于JDK的反射机制,通过JDK调用handler的method.invoke(this.com, new Class[] {});实现对最终方法的调用,前后各有代码也有点Decorator的味道!
2.也是我比较模糊的一点
CarCompany com = (CarCompany) Proxy.newProxyInstance(Test.class
.getClassLoader(), new Class[] { CarCompany.class }, handler);
com.makeCar();
也就是动态代理JDK到底是如何实现的?
JDK的动态代理并没有生成具体的类,她只是在运行中起动态调用目标类的作用,那么代码
CarCompany com = (CarCompany) Proxy.newProxyInstance(Test.class
.getClassLoader(), new Class[] { CarCompany.class }, handler);
究竟做了什么,是将CarCompany注册到JDK的某个地方,当调用com.makeCar()的时候JDK到注册的地方去寻找,发现有注册就进行动态代理?
评论
shaucle
2007-04-15
yimlin 写道
正解!
http://www.blogjava.net/AndersLin/archive/2006/06/11/51997.html
http://www.blogjava.net/AndersLin/archive/2006/06/11/51997.html
哦,这个说了。。。
shaucle
2007-04-15
看看jdk动态代理反编译后的<? extends Proxy>
如果有兴趣的话再看看
cglib(asm), javasist
如果有兴趣的话再看看
cglib(asm), javasist
jamesby
2007-04-14
janh 写道
应该只有一个动态代理,多个拦截器是由spring自己进行维护的,它有专门处理来根据通知类型和Ordered排序值调用不同的拦截器。
我也是这样一来理解的,在看Spring AOP的代码!
janh
2007-04-14
应该只有一个动态代理,多个拦截器是由spring自己进行维护的,它有专门处理来根据通知类型和Ordered排序值调用不同的拦截器。
jamesby
2007-04-14
还有一个问题,那就是如果为一个ServiceImpl配置多个拦截器的时候到底生成多少个动态代理类的问题!
一个动态代理类?
如果一个那多个拦截器如何按照次序拦截?
一个动态代理类?
如果一个那多个拦截器如何按照次序拦截?
jamesby
2007-04-14
这样就可以很好的理解为什么service调用service本身的方法AOP起不到拦截作用了.
因为Spring 将Service 注入到Controller 或者Action的时候注入的是动态代理类,而service调用service自己的方法这时候的对象句柄this实际上是自己实现ServiceImpl类.因此AOP拦截不到.
因为Spring 将Service 注入到Controller 或者Action的时候注入的是动态代理类,而service调用service自己的方法这时候的对象句柄this实际上是自己实现ServiceImpl类.因此AOP拦截不到.
jamesby
2007-04-14
yimlin 写道
正解!
http://www.blogjava.net/AndersLin/archive/2006/06/11/51997.html
http://www.blogjava.net/AndersLin/archive/2006/06/11/51997.html
多谢楼上,看来我的猜测是对的!
这样来说,对于Spring AOP来说,比如事务拦截的时候,只拦截某些方法,实际上Spring 应该是在类似如下代码做文章!
public class CarCompanyHandler implements InvocationHandler {
CarCompany com;
public CarCompanyHandler(CarCompany com) {
this.com = com;
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
//此处做文章,如果是需要事务拦截的,则此处添加事务代,否则什么也不做.
method.invoke(this.com, new Class[] {});
return null;
}
}
如果以上说法成立,那么实际上对于已经被动态代理的接口来讲,无论方法是否匹配,都是通过java的反射机制来对目标类实现调用的.
也就是说一个interface有10个方法声明,但是我只对其中一个方法配置事务属性,结果是对该接口的所有方法调用均是通过发射机制完成的,当然对其中配置事务属性的方法进行事务拦截.
PS:楼上给的blog地址是你自己的blog吗?
yimlin
2007-04-14
正解!
http://www.blogjava.net/AndersLin/archive/2006/06/11/51997.html
http://www.blogjava.net/AndersLin/archive/2006/06/11/51997.html
jamesby
2007-04-14
Class cl = getProxyClass(loader, interfaces);
生成实现接口的类,并自动设置一个ContractorMethodName(InvocationHandler h)的构造函数?
如果这样就还有一个问题也是最关键的问题搞不懂.
就是InvocationHandler 的invoke是如何被调用的?是对代理接口的每个声明的方法生成类似如下代码?
生成实现接口的类,并自动设置一个ContractorMethodName(InvocationHandler h)的构造函数?
如果这样就还有一个问题也是最关键的问题搞不懂.
就是InvocationHandler 的invoke是如何被调用的?是对代理接口的每个声明的方法生成类似如下代码?
makeCar()
{
handler.invoke(......);
}
jamesby
2007-04-14
先贴段JDK的代码,大家帮助分析下:
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;
private final static String proxyClassNamePrefix = "$Proxy";
private final static Class[] constructorParams ={ InvocationHandler.class };
private static Map loaderToCache = new WeakHashMap();
private static Object pendingGenerationMarker = new Object();
private static long nextUniqueNumber = 0;
private static Object nextUniqueNumberLock = new Object();
private static Map proxyClasses =Collections.synchronizedMap(new WeakHashMap());
protected InvocationHandler h;
private Proxy() {
}
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;
String[] interfaceNames = new String[interfaces.length];
Set interfaceSet = new HashSet(); // for detecting duplicates
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);
interfaceNames[i] = interfaceName;
}
Object key = Arrays.asList(interfaceNames);
Map cache;
synchronized (loaderToCache) {
cache = (Map) loaderToCache.get(loader);
if (cache == null) {
cache = new HashMap();
loaderToCache.put(loader, cache);
}
}
synchronized (cache) {
do {
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;
}
} while (true);
}
try {
String proxyPkg = null; // package to define proxy class in
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
}
{
long num;
synchronized (nextUniqueNumberLock) {
num = nextUniqueNumber++;
}
String proxyName = proxyPkg + proxyClassNamePrefix + num;
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces);
try {
proxyClass = defineClass0(loader, proxyName,
proxyClassFile, 0, proxyClassFile.length);
} catch (ClassFormatError e) {
throw new IllegalArgumentException(e.toString());
}
}
proxyClasses.put(proxyClass, null);
} finally {
synchronized (cache) {
if (proxyClass != null) {
cache.put(key, new WeakReference(proxyClass));
} else {
cache.remove(key);
}
cache.notifyAll();
}
}
return proxyClass;
}
//这个就是我的例子中调用的方法.
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
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 boolean isProxyClass(Class<?> cl) {
if (cl == null) {
throw new NullPointerException();
}
return proxyClasses.containsKey(cl);
}
public static InvocationHandler getInvocationHandler(Object proxy)
throws IllegalArgumentException
{
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);
}- 浏览: 129510 次
- 性别:


- 详细资料
搜索本博客
最近加入圈子
最新评论
-
iBatis学习小结
感谢辛勤劳动,希望能贡献更好的东西 :
-- by xuguangyun -
为什么我的Spring的声明事 ...
不要自己抛异常,spring不知道那是什么异常,在catch中直接抛出原来的异常 ...
-- by sinoalex -
Spring AOP 学习小结
写得非常好! 关于 AOP 的几个基础概念,我感觉Spring 的参考文档上面 ...
-- by Hejrcc -
Spring AOP 部分Class的 ...
是的,通过UML的类图,从整体上面了解类之间的关系,是一种不错的方式,理清类之间 ...
-- by rainlife -
Spring AOP 部分Class的 ...
感谢共享
-- by wangzhongjie






评论排行榜