论坛首页 入门技术论坛

Java动态代理的设计是否有缺陷??

浏览 14608 次
该帖已经被评为新手帖
作者 正文
   发表时间:2010-04-25  
xyz20003 写道
^_^个人感觉这个api没问题呀,如果没有Object proxy这第一个参数,当我们希望在代理方法中访问proxy的时候该怎么办呢?

最简单的场景就像我之前举出的,
public class Hello {
  public Hello doSomething() {
    return this;
  }
}

如果不提供Object proxy这个第一个参数,我们就不容易获得proxy了,手里最多只有一个target可以用。

如果参与讨论的各位大侠有时间,不妨考虑一下这种情况吧。多谢。


呵呵,又碰到你了。

获得proxy有什么用??这一直是我的疑问。

这个例子,我还是看不出与proxy有什么关系?(我有点愚钝了O(∩_∩)O~)。劳烦您指教!!
0 请登录后投票
   发表时间:2010-04-25  
只是想讨论一下,像我举的例子,方法的返回值是实例本身,如果invoke方法中没有Object proxy的话,你该如何处理呢?
0 请登录后投票
   发表时间:2010-04-25  
xyz20003 写道
只是想讨论一下,像我举的例子,方法的返回值是实例本身,如果invoke方法中没有Object proxy的话,你该如何处理呢?


method.invoke(Object obj , Object[] args)方法返回的值,不就是那个方法返回的值吗?
0 请登录后投票
   发表时间:2010-04-25  
我能理解你们吵了半天,所以比较晕,所以我详细的把自己的思路整理一下,咱们慢慢研究。

首先,我有一个接口
pubic interface Hello {
  Hello preparePrefix(String prefix);
  Hello prepareName(String name);
  String getResult();
}

下面我想用proxy来代理这个接口,实现下面的功能

Hello hello = Proxy...

hello.preparePrefix("Hello").prepareName("Lingo").getResult();

请问,如果不借助Object proxy这个参数,你该如何实现呢?
0 请登录后投票
   发表时间:2010-04-25   最后修改:2010-04-25
用了Object proxy这个参数,我就可以这么实现。
public interface Hello {
  Hello preparePrefix(String prefix);
  Hello prepareName(String name);
  String getResult();
}


import java.lang.reflect.*;

public class Test {
    public static void main(String[] args) {
        Hello hello = (Hello) Proxy.newProxyInstance(
            Hello.class.getClassLoader(),
            new Class[] { Hello.class },
            new HelloHandler());

        String result = hello.preparePrefix("Hello")
                             .prepareName("Lingo")
                             .getResult();

        System.out.println(result);
    }

    public static class HelloHandler implements InvocationHandler {
        private String prefix;
        private String name;
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            if (method.getName().equals("preparePrefix")) {
                prefix = (String) args[0];
                return proxy;
            } else if (method.getName().equals("prepareName")) {
                name = (String) args[0];
                return proxy;
            } else if (method.getName().equals("getResult")) {
                return prefix + " " + name;
            }
            return null;
        }
    }
}
0 请登录后投票
   发表时间:2010-04-25  
package proxy.study.oo;

public interface Hello {
	Hello preparePrefix(String prefix);

	Hello prepareName(String name);

	String getResult();
}

 

package proxy.study.oo;

public class HelloImpl implements Hello {

	private String name;
	private String prefix;

	@Override
	public String getResult() {
		return name + " : " + prefix;
	}

	@Override
	public Hello prepareName(String name) {
		this.name = name;
		return this;
	}
	@Override
	public Hello preparePrefix(String prefix) {
		this.prefix = prefix;
		return this;
	}
}
 
package proxy.study.oo;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class MyInvocationHandler 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 {
		Object result = null;
		result = method.invoke(target, args);
		return result;
	}
}
 
package proxy.study.oo;

import java.lang.reflect.Proxy;

public class ProxyDemo {

	public static void main(String[] args) {

		HelloImpl real = new HelloImpl();

		MyInvocationHandler handler = new MyInvocationHandler();

		handler.setTarget(real);
		
		Hello proxyObject = (Hello) Proxy
				.newProxyInstance(real.getClass().getClassLoader(),
						new Class[] { Hello.class }, handler);
		String result = proxyObject.preparePrefix("Hello").prepareName("Lingo").getResult();
		System.out.println("执行的结果:" + result);
	}

}

 输出:

执行的结果:Lingo : Hello

 

0 请登录后投票
   发表时间:2010-04-25  
你可以和我的实现比较一下,我的实现可以保证用户一直使用的都是proxy,你的实现从第一次方法调用之后,就把被代理的实例暴露给客户了。

这样的问题是,如果我的代理中还要进行日志,权限,事务等拦截,你的这种方式就会造成后续的拦截失效。
0 请登录后投票
   发表时间:2010-04-25  
xyz20003 写道
用了Object proxy这个参数,我就可以这么实现。


在你的实现中,你感觉到没有。你的InvocationHandler是和某个接口紧密相连的。

切面有可能是面对多个接口的,那么你又应该怎么做?

很谢谢你一直在回复。PS:我们不是在吵,呵呵,是在讨论话题。
0 请登录后投票
   发表时间:2010-04-25  
xyz20003 写道
你可以和我的实现比较一下,我的实现可以保证用户一直使用的都是proxy,你的实现从第一次方法调用之后,就把被代理的实例暴露给客户了。

这样的问题是,如果我的代理中还要进行日志,权限,事务等拦截,你的这种方式就会造成后续的拦截失效。


这是可以通过chain(串接的方式实现的)。即,将前一个的proxyObject作为realObject传入到后一个InvocationHandler中去。

参见这篇文章:
Generically chain dynamic proxies

http://www.javaworld.com/javaworld/jw-01-2006/jw-0130-proxy.html
0 请登录后投票
   发表时间:2010-04-25  
呵呵~看来你没看懂我所说的问题呀。

我的代码里
Hello hello(其实是proxy)
  hello.preparePrefix("Hello")(返回的还是proxy)
       .prepareName("Lingo")(返回的还是proxy)
       .getResult();

你的代码里
Hello hello(其实是proxy)
  hello.preparePrefix("Hello")(从这里开始,返回的都是target)
       .prepareName("Lingo")(下面都是在直接操作target,proxy已经失效)
       .getResult();

你说的我绑定在一个接口上,说的正式一点儿应该是:我列举的场景stateful,而平常经常遇到的场景都是stateless,所以你会感到有些不适应。

至于你说的chain,似乎和咱们说的没什么关联,你先仔细考虑一下,思维不要跳的太快,先把我说的问题想明白。:)
0 请登录后投票
论坛首页 入门技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics