锁定老帖子 主题:Java动态代理的设计是否有缺陷??
该帖已经被评为新手帖
|
|
---|---|
作者 | 正文 |
发表时间:2010-04-23
写一个简单的动态代理: 接口: package study.proxy; public interface RealInterface { public void sayHello(); } 实现类: package study.proxy; public class RealObject implements RealInterface { @Override public void sayHello() { System.out.println("-------执行中-------"); } } InvocationHandler: package study.proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class MyInterceptor implements InvocationHandler { private Object target; // 这不是必须的接口方法,但是却是编程必须的 public void setTarget(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // proxy 通过 可以转型,但是转型后的Object依然不能用 // (RealObject)proxy System.out.println("Before"); Object result = method.invoke(target, args); System.out.println("After"); return result; } } 测试类: package study.proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; public class ProxyBasicDemo { public static void main(String[] args) throws Exception { // 这里不是面向接口的编程 MyInterceptor handler = new MyInterceptor(); handler.setTarget(new RealObject()); Class<?> proxyClass = Proxy.getProxyClass(RealInterface.class .getClassLoader(), RealInterface.class); RealInterface proxyObject = (RealInterface) proxyClass.getConstructor( new Class[] { InvocationHandler.class }).newInstance( new Object[] { handler }); proxyObject.sayHello(); } }
我的疑问: 1、在InvocationHandler中的invoke方法中的那个参数 proxy
不能调用toString、hashCode方法; 虽然可以转型为 实体类,但是 不能 在 method.invoke(obj,args)中使用。
不知道这个参数有什么用???
2、既然proxy不知道怎么用,于是,就自己添加个 setTarget(Object target)方法,注入具体的对象。
可行是可行!但是: // 这里不是面向接口的编程 MyInterceptor handler = new MyInterceptor(); 为什么不在InvocationHandler中加入一个setTarget(Object target)方法的签名呢?
刚看动态代理,觉得SUN的这个API设计的不好。有可能是我错了。不知道,大家对动态代理有什么看法!
欢迎各位批评!! 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2010-04-23
最后修改:2010-04-23
如果想对实体类做AOP,可以使用cglib。
jdk提供的proxy只能代理接口。 我不清楚你为何要将接口强制转型为实现类?从你的代码中没有看到这个必要。是否因为你们的接口设计失误,造成具体调用时都要强制转换成实现类? 也许你的意图是在Interceptor中调用代理的方法,那么只需要把Object转换成接口就行了,如果转换成实现类是会报错的。 |
|
返回顶楼 | |
发表时间:2010-04-23
回答:
⒈那个实际是生成的代理接口,所以不能直接使用,但是它包含了你所需要的类型信息。 ⒉因为有可能作为匿名类啊这些,那这个签名就没意义。甚至,有可能你的对象不是一个参数可以解决的等等。 PS:如果一切都面向接口编程,那么又由谁来组装呢? |
|
返回顶楼 | |
发表时间:2010-04-23
xyz20003 写道 如果想对实体类做AOP,可以使用cglib。
jdk提供的proxy只能代理接口。 我不清楚你为何要将接口强制转型为实现类?从你的代码中没有看到这个必要。是否因为你们的接口设计失误,造成具体调用时都要强制转换成实现类? 也许你的意图是在Interceptor中调用代理的方法,那么只需要把Object转换成接口就行了,如果转换成实现类是会报错的。 谢谢你的回复! 我不是要强制转成实现类,这样不好,我知道的。 我是为了证明,原始的InvocationHandler的invoke方法中的第一个对象proxy,没有什么用。 由于proxy对象没有用,所以我们必须加一个setTarget类似的方法。 |
|
返回顶楼 | |
发表时间:2010-04-23
最后修改:2010-04-23
请问为什么会没有什么用呢?如果希望调用被代理实例的方法,不是就会需要proxy吗?
如果你传了一个target进去,还怎么面向切面?本来如果系统里有10个实现了这个接口的类,我只要写一个interceptor就可以拦截10个类的方法调用,现在你这样一搞,我必须写10个拦截器,对应十个类才能实现原来一个拦截器的功能。何苦呢? |
|
返回顶楼 | |
发表时间:2010-04-23
xyz20003 写道 请问为什么会没有什么用呢?如果希望调用被代理实例的方法,不是就会需要proxy吗?
呵呵,热心人。 你是说proxy有 可以调用的方法? proxy是java.lang.reflect.Proxy的实例吧?如果是的话,里面似乎没有很有用的方法? 另外:调用proxy.hashCode()这个Object中的方法,都会报错的!! 谢谢您的耐心指教!! |
|
返回顶楼 | |
发表时间:2010-04-23
xiaolongfeixiang 写道 xyz20003 写道 如果想对实体类做AOP,可以使用cglib。
jdk提供的proxy只能代理接口。 我不清楚你为何要将接口强制转型为实现类?从你的代码中没有看到这个必要。是否因为你们的接口设计失误,造成具体调用时都要强制转换成实现类? 也许你的意图是在Interceptor中调用代理的方法,那么只需要把Object转换成接口就行了,如果转换成实现类是会报错的。 谢谢你的回复! 我不是要强制转成实现类,这样不好,我知道的。 我是为了证明,原始的InvocationHandler的invoke方法中的第一个对象proxy,没有什么用。 由于proxy对象没有用,所以我们必须加一个setTarget类似的方法。 第一个参数的作用就是生成的代理的接口,提供类型信息的。proxy.getClass() |
|
返回顶楼 | |
发表时间:2010-04-23
xiaolongfeixiang 写道 xyz20003 写道 请问为什么会没有什么用呢?如果希望调用被代理实例的方法,不是就会需要proxy吗?
呵呵,热心人。 你是说proxy有 可以调用的方法? proxy是java.lang.reflect.Proxy的实例吧?如果是的话,里面似乎没有很有用的方法? 另外:调用proxy.hashCode()这个Object中的方法,都会报错的!! 谢谢您的耐心指教!! 貌似我一来就回复了你这个问题,你都不看我的。 通过类型信息反射调用被代理对象的方法。 |
|
返回顶楼 | |
发表时间:2010-04-23
xyz20003 写道 如果你传了一个target进去,还怎么面向切面?
哦,我现在的问题就是(就如我提供的例子), 我必须提供一个setTarget或类似的方法。 如果我这样改: public class MyInterceptor implements InvocationHandler { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("Before"); // 由于没有提供任何方法,所以这个参数似乎只能是proxy // 但是这样运行时报错! Object result = method.invoke(proxy, args); System.out.println("After"); return result; } } public class ProxyBasicDemo { public static void main(String[] args) throws Exception { MyInterceptor handler = new MyInterceptor(); Class<?> proxyClass = Proxy.getProxyClass(RealInterface.class .getClassLoader(), RealInterface.class); RealInterface proxyObject = (RealInterface) proxyClass.getConstructor( new Class[] { InvocationHandler.class }).newInstance( new Object[] { handler }); proxyObject.sayHello(); } } 错误是这样的: 引用 ... 943 more Caused by: java.lang.reflect.UndeclaredThrowableException at $Proxy0.sayHello(Unknown Source) ... 947 more Caused by: java.lang.reflect.InvocationTargetException at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) at java.lang.reflect.Method.invoke(Unknown Source) at study.proxy.MyInterceptor.invoke(MyInterceptor.java:18) ... 948 more Caused by: java.lang.reflect.UndeclaredThrowableException at $Proxy0.sayHello(Unknown Source) ... 952 more |
|
返回顶楼 | |
发表时间:2010-04-23
Agrael 写道 xiaolongfeixiang 写道 xyz20003 写道 请问为什么会没有什么用呢?如果希望调用被代理实例的方法,不是就会需要proxy吗?
呵呵,热心人。 你是说proxy有 可以调用的方法? proxy是java.lang.reflect.Proxy的实例吧?如果是的话,里面似乎没有很有用的方法? 另外:调用proxy.hashCode()这个Object中的方法,都会报错的!! 谢谢您的耐心指教!! 貌似我一来就回复了你这个问题,你都不看我的。 通过类型信息反射调用被代理对象的方法。 不好意思,您的回复我看得有点深奥,没怎么明白。于是就先回复他的了。 呵呵,JavaEye就是好心人多、技术牛人多!! 我不知道如何利用proxy这个对象。因为 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("Before"); Object result = method.invoke(proxy, args); System.out.println("After"); return result; } 会报错的!!所以我就对proxy这个参数很晕乎! |
|
返回顶楼 | |