1. java代理静态代理和动态代理:
静态代理
package onlyfun.caterpillar;
import java.util.logging.Level;
import java.util.logging.Logger;
public classHelloSperker {
private Logger logger = Logger.getLogger(this.getClass().getName());
public void hello(String name){
//方法执行开始时留下记录
logger.log(Level.INFO, "hello method starting ...");;
System.out.println("name: "+name);
//方法结束时留下记录
logger.log(Level.INFO,"hello method ending ...");
}
public static void main(String []args){
HelloSperkerhelloSperk= newHelloSperker();
helloSperk.hello("adu");
}
}
如果分析这段代码,当执行hello时在方法开始和结束都进行相应的记录,最简单的方法就是如上面使用日志动作,然而对于HelloSperker来说,日志的这几个动作并不属于它的业务逻辑,因此是给HelloSperker增加了额外的工作。
如果有大量的类似的程序,里面都需要进行与业务无关的日志记录、权限检查、事务管理等,而且如果要维护这些代码,如果仍然是这样写法,维护必要要耗费大量时间,负担不可谓不重啊。而且这样的代码,如果哪一天不需要相关的日志等服务了,那么修改也会让我们很痛苦。如何解决这样令我们痛苦的事情那?
一个好的方法就是使用代理proxy。代理可分为静态代理和动态代理。
静态代理:在静态代理中,代理对象与被代理对象必须实现同一个接口,在代理对象中可以实现日志等相关服务,并在需要的时候再调用被代理的对象,被代理对象当中就可以仅保留与业务相关的职责。
例子:
#Interface:IHello
package onlyfun.caterpillar;
public interfaceIHello {
public voidhell(String name);
}
#Class:HelloSperker1 :implements IHello
package onlyfun.caterpillar;
public classHelloSperker1 implements IHello {
@Override
public void hell(String name) {
// TODO Auto-generated method stub
System.out.println("name:"+name);
}
}
#class:HelloProxy:implements IHello
package onlyfun.caterpillar;
import java.util.logging.Level;
import java.util.logging.Logger;
public classHelloProxy implementsIHello {
private Logger logger = Logger.getLogger(this.getClass().getName());
private IHello helloObject;
public HelloProxy(IHello helloObject){
this.helloObject = helloObject;
}
@Override
public void hell(String name) {
// TODO Auto-generated method stub
log("hello method starting ....");
helloObject.hell(name);
log("hello method ending ...");
}
public void log(String msg){
logger.log(Level.INFO,msg);
}
}
#StaticProxyTest
package onlyfun.caterpillar;
public classStaticProxyTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
IHellohelloObject = new HelloSperker1();
HelloProxyproxy= newHelloProxy(helloObject);
proxy.hell("along");
}
}
这里确实是将业务和与业务无关的内容分开了,比较之前确实是有较大改善,但是如果这样每个业务类都需要对应一个这样的proxy,那也是工作量巨大,有没有更好的方式那。
自己的说明:这里代理类可以不实现IHello接口,只不过在该代理类内部写一个一样的方法,即可,只不过不是实现,貌似也能实现效果。有点像设计模式里的门面模式(装饰模式)吧。
下面将动态代理:
在jdk1.3之后加入了可协助开发动态代理功能的API,使用动态代理,因此可以使用一个handler处理服务于各个对象,但是这个处理者的类handler必须实现java.lang.reflect.InvocationHandler接口。
具体的实现是:
package onlyfun.caterpillar;
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 classLogHandler implementsInvocationHandler {
private Logger logger = Logger.getLogger(this.getClass().getName());
//声明一个代理对象
private Object delegate;
//绑定该代理对象,返回一个代理,期间需要指定所要代理的接口
public Object bind(Object delegate){
this.delegate = delegate;
return Proxy.newProxyInstance(delegate.getClass().getClassLoader(),
delegate.getClass().getInterfaces(),
this);
}
//重写invoke方法(使用代理时每次操作都会执行的方法,实际上执行的是
//method.invoke,在它前后加上日志动作即可)
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// TODO Auto-generated method stub
Objectresult = null;
try{
log("method starts: ....["+method+"]...");
result = method.invoke(delegate, args);
log("method end:...["+method+"]...");
}catch(Exception e){
log(e.toString());
}
return result;
}
public void log(String msg){
logger.log(Level.INFO,msg);
}
}
#动态代理测试
package onlyfun.caterpillar;
public classProxyDemo {
public static void main(String[] args) {
// TODO Auto-generated method stub
//初始化动态代理handler对象
LogHandlerlogHandler= newLogHandler();
//绑定需要被代理的对象实例,并返回一个代理对象,
IHello helloSperk = (IHello)logHandler.bind(new HelloSperker1());
//执行输出
helloSperk.hell("dudu");
}
}
这里可以看出LogHandler不在执行与特定的接口,这里根据指定的接口代替了原来静态代理中的实现接口的方式,从而达到通用。这种从单独设计,到使用静态代理,再到使用动态代理,逐层精进、业务独立,达到设计上的复用、可维护性的特征,正是设计的发展方向。