`
yunmanfan
  • 浏览: 91045 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

05-04 浅谈Java的代理机制

阅读更多
网站: JavaEye  作者:yate 链接:http://yate.iteye.com/blog/189063 发表时间: 2008年05月03日

声明:本文系JavaEye网站发布的原创博客文章,未经作者书面许可,严禁任何网站转载本文,否则必将追究法律责任!

 可以说代理是java十分重要的一种机制,另一个当然是属于反射了,jdk中单独讲到了反射API(java.lang.reflect),可能有人认为反射对资源消耗比较厉害,确实也是,反射肯定是要消耗资源的,但也不是什么都要用到反射,所以最佳试验应该是在资源消耗程度和反射的使用程度之间找到一个平衡点,本文并不打算讲反射,关于反射的心得以后再贴出来,自己最近也在折磨折磨

代理可以分为:StaticProxy 和DynamicProxy
比如:
Package xyz;
import java.util.logging.*
public class talkToSomebody{
private Loggerlogger=Logger.getLogger(this.getClass().getName());
public void talk(String name){
logger.log(Level.INFO,"talking start....");
System.out.println("Hi!ni hao,"+name);
logger.log(Level.INFO,"talking ends....");
}
}

很显示,你需要talk其他人,其实就只有一个句话是关键的,"Hi!nihao XXX",这才是需要关系的,或者叫核心业务(这个次可能有点牵强),但如果要记录你和哪些人交谈过,哪时候开始的,哪时候结束的,日志功能就是实现这个,这属于业务逻辑,把业务逻辑和核心业务放到了一起,如果哪天不需要记录了,怎么办?得重新改源代码,甚至如果客户只提供给你编译过的class或接口,你会很郁闷的!

解决方法:
用Proxy机制,其实代理就像一个中介机构,我自己突然有什么事(或者不愿意),找中介机构去做,当然你得出钱给中介机构。
public interface ITalk{
public void talk(String name);
}

可以把这个看做你的要求,中介机构必须按照你的要求来做,你才会付钱给中介机构;

public class TalkToSomebody implements ITalk{
public void talk(String name){
System.out.println("Hi,ni hao,"+name);
}
}

不错,中介机构是按照我的要求实现的,结果没错!


public class StaticProxyTalk Implements ITalk{
private Loggerlogger=Logger.getLogger(this.getClass().getName());
private ITalk somebody;
public StaticProxyTalk(ITalk somebody){
this.somebody=somebody;
}
public void talk(String name){
log("talking start....");
somebody.talk(name);
log("talking ending...");
}
private void log(String message){
logger.log(Level.INFO,message)
}

感觉好多了,以后我不需要中介服务了,不去找他就行,现在看下这个中介机构做得怎么样,达到我的要求了没?


public class TestProxy{
public static void main(String []args){
ITalk proxy=new StaticProxyTalk(new TalkToSomebody());
proxy.talk("HuYong");
}
}

是的,,它做到了,我可以付钱给它了。。

但是问题还是存在,如果我有N多事都不想自己做(比较懒),我得每一件都去找中介机构吗?能不能一类的就找一次就够了勒??

看下面的一个LogTalk:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.logging.Level;
import java.util.logging.Logger;


public class LogTalk implements InvocationHandler {
private Logger logger =Logger.getLogger(this.getClass().getName());

private Object object;

public Object bind(Object object) {
this.object = object;
returnProxy.newProxyInstance(object.getClass().getClassLoader(),
object.getClass().getInterfaces(), this);

}

public Object invoke(Object proxy, Method method, Object[]args)
throws Throwable {
Object result = null;
try {
log("method starts ...." + method);
result = method.invoke(object, args);
log("method ends...." + method);
} catch (Exception e) {
log(e.toString());
}
return result;
}

private void log(String message) {
logger.log(Level.INFO, message);
}

}

只要我需要做的事是一类事(可以理解一类事物),我就可以先和中介机构签好活动,我以后所有的你帮我做就是了,我只需要结构就ok了,中介机构也承诺,只要你给我们的都符合这个约定(都是Object),我就接了。

也来测试下:
public class TestDynamicProxy{
public static void main(String []args){
LogTalk dynamicproxy=new LogTalk();
ITalk proxy=(ITalk)dynamicproxy.bind(new TalkToSomebody());
proxy.talk("YangYi");
}
}

可以通过了,,以后这些事你都可以帮我做了,我列个清单给中介机构有哪些事了,这些事你就帮我做了,如果哪天有事不需要做了,我打电话给你取消那项就可以了,不影响其他事情的继续做下去,也不需要去改动相关的约定了。。


关于LogTalk的讲解:
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
返回一个指定接口的代理类实例,该接口可以将方法调用指派到指定的调用处理程序


public Object bind(Object object) {
this.object = object;
returnProxy.newProxyInstance(object.getClass().getClassLoader(),
object.getClass().getInterfaces(), this);


绑定,只要是Object的子类就可以绑定(呵呵,所有的都是Object的子类勒!)

总结:这其实是AOP的最底层实现,AOP的的好处就是用到了代理,把各种业务逻辑分离开来了,不管是核心要处理的还是作为辅助功能(或者测试)的业务逻辑,比如日志作为一个切面可以去测试每个方法是否都执行了,用AOP就不需要去改动任何核心业务,如果不要了,就不指定Pointcut就可以了(关于AOP的各种术语可以参考spring reference),这应该算是一种思想的转变。

补充:可能我用到的"核心业务",和其他"业务逻辑"理解有点不同,个人理解是这样的:核心业务就是我需要去关心的,这是核心。其他业务逻辑(很多书上说是与业务逻辑无关的系统服务逻辑)比如说日志,安全方面等,只是做为核心的一个外壳,没有外壳核心照样可以存活,只是没有那么美观了。
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics