代理简析(静态代理与动态代理)

来源:互联网 发布:wps文字软件下载 编辑:程序博客网 时间:2024/06/01 10:44

1、代理
代理,简称为Proxy。意思就是你什么都不用去做,别人代替你去做。
她在程序开发中起到了非常重要的作用,比如AOP,就是针对代理的一种应用。此外,在设计模式中,还有一个“代理模式”。
接下来,通过一个例子,由浅及深学习

public interface Hello{    void say(String name)}

上面是一个Hello的接口,接下来是实现类

public class HelloImpl implements Hello{    @Override    public void say(String name){        System.out.println("Hello!"+name);    }}

如果要在println方法前面和后面分别需要处理一些逻辑,如果把这些逻辑写进say方法了,肯定是不行的。
那么此时,就需要用代理模式,写一个HelloProxy类,让他去调用HelloImpl的say方法,在调用前后分别进行逻辑处理。具体如下:

public class HelloProxy implements Hello{    private Hello hello;    public HelloProxy(){        hello=new HelloImpl();    }    @Override    public void say(String name){        before();        hello.say(name);        after();    }    private void before(){        System.out.println("Before");    }    private void after(){        System.out.println("After");    }}

用HelloProxy类实现了Hello接口,并且哎构方法中new出一个HelloImpl类的实例。这样,我们就可以在HelloProxy的say方法里面调用HelloImpl的say方法了。更重要的是,我们在调用前加上了before和after方法,在这两个方法实现那些前后逻辑。

用一个main方法测试一下:

public static void main(String[] args){    Hello helloProxy=new HelloProxy();    helloProxy.say("Jack");}

打印的结果为:

BeforeHello!JackAfter

这样,我们就写了一个HelloProxy的“代理模式”。

2、JDK动态代理

上述中,使用的就是静态代理,那么什么是动态代理呢?

下面用JDK提供额动态代理方案写一个DynamicProxy:

public class DynamicProxy implements InvocationHandler{    private Object target;    public DynamicProxy(Object target){        this.target=target;    }    @Override    public Object invoke(Object proxy,Method method,Object[] args) throws Throwable{        before();        Object result=method.invoke(target,args);        after();        return result;    }    .....}

在DynamicProxy类中,定义了一个Object类型的target变量他就是被代理的目标对象,通过构造函数来初始化,也就是注入。构造方法称为反射。

在DynamicProxy类中,实现了 InvocationHandler接口 ,那么必须实现该接口的invoke方法。该方法是jar“反射”过来的。在invoke中,在调用前后分别处理before和after,左后result返回。

public static void main(String[] args){    Hello hello=new HelloImpl();    DynamicProxy dynamicProxy=new DynamicProxy(hello);    Hello helloProxy=(Hello)Proxy.newProxyInstance(        hello.getClass().getClassLoader(),        hello.getClass().getInterfaces(),        dynamicProxy    );    helloProxy.say("Jack");}

意思就是通过用这个通用的DynamicProxy 类去包装HelloImpl实例,然后再调用JDK给我们提供的Proxy类的工厂方法newProxyInstance去动态创建一个Hello接口的代理类,最后调用这个代理类的say方法。

运行的结果是一样的,动态代理成功了。那么,动态代理就是帮我们自动生成XxxProxy类的法宝。
但是,Proxy.newProxyInstance方法参数有点令人烦躁

  • 参数1:ClassLoader
  • 参数2:该实现类的所有接口
  • 参数3:动态代理对象

    调用完后,还需要强制转换一下。
    如果需要的代理对象比较多,那么意味着,到处都出现Proxy.newProxyInstance方法的情况。所有需要把DynamicProxy 重构一下:

public class DynamicProxy implements InvocationHandler{    @SuppressWarnings("unchecked")    public <T> T getProxy(){        return (T)Proxy.newProxyInstance(        target.getClass().getClassLoader(),        target..getClass().getInterfaces(),        this        );    }    .....}

在DynamicProxy 里添加了一个getProxy方法,无须传入任何参数,将刚才说的那一块代码放入这个方法中,并且该方法返回一个泛型类型就不会强制转换类型。方法上添加一个@SuppressWarnings(“unchecked”)注解表示忽略编译时的警告(因为Proxy.newProxyInstance方法返回的是一个Object,这里强制转换为T了,这是向下转型。)

那么此时使用DynamicProxy 就简单了。

public static void main(String[] args){    DynamicProxy dynamicProxy=new DynamicProxy(new HelloImpl());    Hello helloProxy=dynamicProxy.getProxy();    helloProxy.say("Jack");}

此时,代码简洁多了,那么动态代理大概也就懂了。

3、CGlib动态代理
动态代理并不是万能的,总有用不了的地方。那么在Spring、Hibernate中的高端框架中都有用到过CGlib类库。它是一个在运行期间动态生成字节码的工具,也就是动态生成代理类。
下面通过代码简洁的说下,我理解的也不深~

public class CGlibProxy implements MethodInterceptor{    public <T> T getProxy(Class<T> cls){        return(T)Enhancer.create(cls,this);    }    public Object intercept(Object obj,Method method,Object[] args,MethodProxy proxy) throws Throwable{        before();        Object result=proxy.invokeSuper(obj,args);        after();        result result;    }    ...}

需要实现CGlib给我们提供的MethodInterceptor实现类,并填充intercept方法。方法中最后一个MethodProxy类型的参数proxy值得注意。Cglib给我们提供的是方法级别的代理,也可以理解为对方法的拦截(这就是“方法拦截器”)。我们直接调用proxy的invokeSuper方法,将被代理的对象obj以及方法参数args传入其中即可。

与DynamicProxy 类似,在CGlib中也添加一个泛型的getProxy方法,便于我们快速地获取自动生成的代理对象。

public static void main(String[] args){    CGlibProxy cglibProxy=new CGlibProxy();    Hello helloProxy=cglibProxy.getProxy(HelloImpl.class);    helloProxy.say("Jack");}

对于此刻的代码,如果用“单例模式”后,会不会更加简洁些呢。

public class CGlibProxy implements MethodInterceptor{    private static CGlibProxy instance=new CGlibProxy();    private CGlibProxy(){    }    public static CGlibProxy getInstance(){        return instance;    }    ...}

那么此时,main中:

public static void main(String[] args){    Hello helloProxy=CGlibProxy.getInstance.getProxy(HelloImpl.class);    helloProxy.say("Jack");}

以上,简述了静态代理和动态代理,如果有更好的见解,欢迎指点~

原创粉丝点击