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

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");
}

打印的结果为:

Before
Hello!Jack
After

这样,我们就写了一个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");
}

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

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值