【设计模式】代理模式详解

一、基本介绍

核心作用:通过代理,控制对对象的访问,可以详细控制访问某个(某类)对象的方法,在调用这个方法前做前置处理,调用这个方法后做后置处理。

应用场景: 安全代理:屏蔽对真实角色的直接访问。

                   远程代理:通过代理类处理远程方法调用(RMI)

                   延迟加载:先加载轻量级的代理对象,真正需要再加载真实对象。(比如你要开发一个大文档查看软件,大文档中有大的图片,有可能一个图片有100MB,在打开文件时不可能将所有的图片都显示出来,这样就可以使用代理模式,当需要查看图片时,用proxy来进行大图片的打开) 

代理模式分类:静态代理和动态代理

二、静态代理(需要自己手动生成代理类)

核心角色:抽象角色:定义代理角色和真实角色的公共对外方法
                  真实角色:实现抽象角色,定义真实角色所要实现的业务逻辑,供代理角色调用,关注真正的业务逻辑!
                  代理角色:实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作。将统一的流程控制放到代理角色中处理!

举例:比如对于歌手而言都有自己的经纪人,经纪人就相当于一个代理对象,歌手仅仅负责唱歌,其他的接活、门票价格、演出费等等这些是代理对象去操作

           1.首先创建一个接口,接口中定义代理角色和真实角色的公共对外方法

public interface Star {
    //面谈
    void confer();
    //签合同
    void signContract();
    //订票
    void bookTicket();
    //唱歌
    void sing();
    //收钱
    void collectMoney();
}

           2.定义真实的对象(真实的对象只要完善自己需要做的方法即可,比如说歌手就只需完善sing()方法)

public class RealStar implements Star {
    @Override
    public void confer() {
        System.out.println("");
    }

    @Override
    public void signContract() {

    }

    @Override
    public void sing() {
        System.out.println("唱歌");
    }

    @Override
    public void collectMoney() {

    }
}

           3.定义代理对象 ,对于真实对象需要执行的方法就去调用真是对象

public class ProxyStar implements Star {
    private Star realStar;

    public ProxyStar(Star star) {
        this.realStar = star;
    }

    @Override
    public void confer() {
        System.out.println("与邀请方商谈");
    }

    @Override
    public void signContract() {
        System.out.println("与邀请方签合同");
    }

    @Override
    public void sing() {
        realStar.sing();
    }

    @Override
    public void collectMoney() {
        System.out.println("收钱");
    }
}

           4.测试

public class Client {
    public static void main(String[] args) {
        Star realStar = new RealStar();
        Star proxy = new ProxyStar(realStar);
        proxy.confer();
        proxy.signContract();
        proxy.sing();
        proxy.collectMoney();
    }
}

静态代理比较简单,一般常用的是动态代理,接下来研究以下动态代理模式。 

三、动态代理(程序动态生成代理类)

动态代理的实现有多种这里介绍常用的两种:JDK动态代理和CGLIB动态代理

1.JDK动态代理(必须有接口类)

    是java.lang.reflect.*包提供的方式,它必须借助一个接口才能产生代理对象,所以需要先定义接口

public interface HelloWorld {
    public void sayHelloWorld();
}

   创建一个实现类

public class HelloWorldImpl implements HelloWorld {
    @Override
    public void sayHelloWorld() {
        System.out.println("Hello,World!");
    }
}

   在JDK动态代理中,要实现代理类就必须先有一个类要实现java.lang.reflect.InvocationHandler接口,它里面定义了一个invoke方法,并提供接口数组用于下挂代理对象

   下面的JDKProxyExample可以接收任意的对象并为其生成代理对象

public class JDKProxyExample implements InvocationHandler {
    private Object target = null;

    public JDKProxyExample(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("进入代理逻辑方法");
        Object obj = method.invoke(target, args);
        System.out.println("在调度完真实对象后");
        return obj;
    }
}

    生成代理类并运行真实对象的方法

    Proxy.newProxyInstance()方法用来生成代理对象,其中包含三个参数。

    参数1:需要传入一个类加载器,直接传入java系统的类加载器即可

    参数2:把生成的动态代理对象下挂在那个接口下,所以需要传递真实对象实现的接口类

    参数3: 传递实现了java.lang.reflect.InvocationHandler的类

public class testJDkProxy {
    public static void main(String[] args) {
        HelloWorld helloWorld = new HelloWorldImpl();
        JDKProxyExample jdkProxyExample = new JDKProxyExample(helloWorld);

        HelloWorld handler = (HelloWorld) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(),
                    helloWorld.getClass().getInterfaces(), jdkProxyExample);
        
        handler.sayHelloWorld();

    }
}

2.CGLIB动态代理

    JDK动态代理必须提供接口才可以使用,在一些不能提供接口的环境中,只能采用其他的第三方技术,比如CGLIB,它的又是在于不需要提供接口,只要一个非抽象类就能实现动态代理。

    由于cglib是第三方技术,所以需要添加其jar包,下面的代码是cglib的Maven坐标

<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>3.2.5</version>
</dependency>

    首先定义真实对象类
 

public class HelloWorld {
    public void say(){
        System.out.println("Hello,World");
    }
}

      Enhancer可能是CGLIB中最常用的一个类,Enhancer既能够代理普通的class,也能够代理接口。这里Enhancer通过设置传递进来cls为超类,然后通过setCallback方法设置那个类为该超类即传递进来的cls类的代理类(setCallback中设置的类必须实现intercept方法),最后返回代理对象

public class CglibProxyExample implements MethodInterceptor {

    //生成cglib动态代理对象,需传递真实对象的class
    public Object getProxy(Class cls){
        //CGLIB enchancer增强类对象
        Enhancer enhancer = new Enhancer();
        //设置增强类型
        enhancer.setSuperclass(cls);
        //定义代理逻辑对象为当前对象,要求当前对象实现MethodInterceptor方法
        enhancer.setCallback(this);
        //生成并返回代理对象
        return enhancer.create();
    }

    @Override
    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        System.out.println("调用真实对象前");
        Object result = methodProxy.invokeSuper(proxy, args);
        System.out.println("调用真实对象后");
        return result;
    }
}

   测试类:

public class test {
    public static void main(String[] args) {
        CglibProxyExample cglibProxyExample = new CglibProxyExample();
        HelloWorld proxy = (HelloWorld) cglibProxyExample.getProxy(HelloWorld.class);
        proxy.say();
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值