代理模式-静态代理与动态代理

Posted 离线de日常

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了代理模式-静态代理与动态代理相关的知识,希望对你有一定的参考价值。

简介

  • 首先感谢沽泡学院 tom 老师
  • 代理模式是一种结构型模式
  • 代理模式就是代理对象帮被代理对象处理一些问题, 类似中介, 客户只要结果, 中介怎么搞是他的事儿, 他可能再处理过程中赚外快什么的
  • 代理模式的应用: spring中的aop, 日常工作中记录日志, 统计时间,权限控制等
  • 这里我们使用一个客户端代理访问google举例, 具体细节可能不合适, 意会、意会、意会...

静态代理

/**
 * 一个服务器接口, 服务器有很多功能, 可以用来路由, 建站等...
 */
public interface Server {
    boolean internetgoogle(Boolean ispass);
    boolean internetbaidu(Boolean ispass);
}
/**
 * @ClassName: HKProxyServer
 * @description [静态代理类, 帮助被代理对象访问url, 静态代理类和被代理对象实现同一接口, 唯一的区别就是代理类持有被代理对象引用, ]
 *  每次修改接口, 代理类和被代理类都要实现相同的方法, 静态代理, 要做的事情已经是确定的, 只是表面上换了个人去做
 * @create 2018-03-31 上午7:56
 **/
public class HKProxyServer implements Server{

    //传入客户端信息
    private Server client;

    public HKProxyServer(Server client) {
        this.client = client;
    }

    @Override
    public boolean internetgoogle(Boolean ispass) {
        System.out.println("香港代理: ");
        return client.internetgoogle(true);
    }

    @Override
    public boolean internetbaidu(Boolean ispass) {
        System.out.println("香港代理: ");
        return client.internetbaidu(true);
    }
}
/**
 * @ClassName: ChinaServer
 * @description [描述该类的功能]
 * @create 2018-03-31 上午7:45
 **/
public class ChinaClient implements Server {

    @Override
    public boolean internetgoogle(Boolean ispass) {
        if(ispass != null && ispass){
            System.out.println(" 请求地址: www.google.com 通过");
            return true ;
        }else{
            System.out.println(" 请求地址: www.google.com 拒绝");
            return false;
        }
    }

    @Override
    public boolean internetbaidu(Boolean ispass) {
        System.out.println(" 请求地址: www.baidu.com 通过");
        return true;
    }
}
public class AccessGoogle {

    @Test
    public void tryToAccessGoogle(){
        Server chinaServer = new ChinaClient();
        //访问不了google
        Assert.assertFalse(chinaServer.internetgoogle(null));
        //可以访问baidu
        Assert.assertTrue(chinaServer.internetbaidu(null));

        System.out.println("--------------------------------------------------通过代理访问--------------------------------------------------");
        Server proxyServer = new HKProxyServer(chinaServer);
        //可以访问google
        Assert.assertTrue(proxyServer.internetgoogle(null));
        //可以访问baidu
        Assert.assertTrue(proxyServer.internetbaidu(null));

    }
}

jdk实现动态代理

/**
 * @ClassName: HKProxyServer
 * @description [使用jdk动态代理实现, 不用实现与被代理类相同的接口, 接口增加方法也与我无关, 动态调用被代理类方法,
 *                  在调用方法前我可以输出日志, aop, 但是调用的方法的对象是传入的client对象]
 * @create 2018-03-31 上午7:56
 **/
public class HKProxyServer implements InvocationHandler {

    //传入客户端信息
    private Server client;

    public HKProxyServer(Server client) {
        this.client = client;
    }

    public Object getInstence(){
        Class<?> clazz = client.getClass();
        //用来生成一个新的对象(字节码重组来实现)
        return Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(),this);

        //如果直接返回传入对象就不会调用下面的invoke方法
//        return client;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        args = new Object[]{true};//代理执行方法前可以搞事情
        System.out.println("mylog +++++++++ 动态代理调用方法 " + method.getName());
        return method.invoke(this.client, args);
    }
}
/**
 * @ClassName: ChinaServer
 * @description [描述该类的功能]
 * @create 2018-03-31 上午7:45
 **/
public class ChinaClient implements Server {

    @Override
    public boolean internetgoogle(Boolean ispass) {
        System.out.println(this);
        if(ispass){
            System.out.println("请求地址: www.google.com 通过");
            return true ;
        }else{
            System.out.println("请求地址: www.google.com 拒绝");
            return false;
        }
    }

    @Override
    public boolean internetbaidu(Boolean ispass) {
        System.out.println(this);
        System.out.println("请求地址: www.baidu.com 通过");
        return true;
    }
}
public class AccessGoogle {

    @Test
    public void tryToAccessGoogle(){
        //代理对象内部使用传入de被代理对象调用方法(等价 new Object().methodxx())
        Server chinaClient = new ChinaClient();
        Server proxyServer = (Server)new HKProxyServer(chinaClient).getInstence();
        Assert.assertTrue(proxyServer.internetgoogle(false));
        Assert.assertTrue(proxyServer.internetbaidu(true));

        Assert.assertFalse(chinaClient.equals(proxyServer));
    }
}

cglib实现动态代理

/**
 * @ClassName: HKProxyServer
 * @description [使用cglib实现动态代理, 客户端都不用创建对象, 对象由框架创建载入, 体现在客户端像是用接口调用方法]
 * @create 2018-03-31 上午7:56
 **/
public class HKProxyServer implements MethodInterceptor {

    public Object getInstence(Class<?> clazz){

        Enhancer enhancer = new Enhancer();
        //要把哪个设置为即将生成的新类父类
        enhancer.setSuperclass(clazz);

        enhancer.setCallback(this);

        return  enhancer.create();
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("mylog +++++++++++++++ cglib代理实现: 调用方法" + method.getName());
        return methodProxy.invokeSuper(o,objects);
    }
}
public class ChinaClient implements Server {

    @Override
    public boolean internetgoogle(Boolean ispass) {
        System.out.println(this);
        if(ispass){
            System.out.println("请求地址: www.google.com 通过");
            return true ;
        }else{
            System.out.println("请求地址: www.google.com 拒绝");
            return false;
        }
    }

    @Override
    public boolean internetbaidu(Boolean ispass) {
        System.out.println(this);
        System.out.println("请求地址: www.baidu.com 通过");
        return true;
    }
}
public class AccessGoogle {

    @Test
    public void tryToAccessGoogle(){
        //不需要再new对象,传入chinaclient.class即可, 然后使用接口调用方法, 内部创建了个新的子类对象来调用指定方法
        Server proxyServer = (Server)new HKProxyServer().getInstence(ChinaClient.class);
        Assert.assertTrue(proxyServer.internetgoogle(true));
        Assert.assertTrue(proxyServer.internetbaidu(true));
    }
}

三种代理方式的分析

  • 静态代理: 要做的事情已经是确定的, 只是表面上换了个人去做,代理对象和被代理对象实现同样的接口,实际通过传入对象调用
  • jdk动态代理: 与静态代理效果相同, 但是java通过反射实现代理类不用实现与被代理对象同样的接口, 也可以根据传入方法调用被代理对象的方法, 传入对象调用
  • cglib动态代理: 只需要传入被代理对象的类名, 内部会实现创建对象到调用的过程,客户端不需要创建具体的对象, 接口调用方法

代码路径

https://github.com/offline7LY/designpattern

以上是关于代理模式-静态代理与动态代理的主要内容,如果未能解决你的问题,请参考以下文章

Java动态代理与静态代理的定义与区别??

静态代理与动态代理模式

代理模式(静态代理动态代理)代码实战(详细)

Spring AOP JDK动态代理与CGLib动态代理区别

代理模式-静态代理与动态代理

java静态代理与动态代理