首页 > 其他 > 详细

代理模式

时间:2020-03-29 14:33:25      阅读:60      评论:0      收藏:0      [点我收藏+]

代理模式

一,简介

为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。假设某公司的老板需要和某小公司签订一份合同,但老板正好没空,于是便赋予秘书签合同的权利,让秘书代表自己去和这家公司签订合同.

二,组成

抽象角色:通过接口或抽象类声明真实角色实现的业务方法。

代理角色:实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作。

真实角色:实现抽象角色,定义真实角色所要实现的业务逻辑,供代理角色调用。

② 实现方式

代理模式的实现可以分为静态代理模式和动态代理模式。

三,实现

1.静态代理

① 抽象角色

/**
 * 抽象角色
 * 签合同
 */
public interface SignContract {
    void signContract();
}

② 真实角色

/**
 * 真实角色
 * 老板
 */
public class Boos implements SignContract{

    @Override
    public void signContract() {
        System.out.println("和***公司签订合同");
    }
}

③ 代理角色

/**
 * 代理角色
 * 秘书
 */
public class Secretray implements SignContract{
    private Boos boos;
    public Secretray(final Boos boos){
        this.boos=boos;
    }
    @Override
    public void signContract() {
        System.out.println("签合同前的准备");
        boos.signContract();
        System.out.println("签合同后的准备");
    }
}

④ 测试

class Test{
    public static void main(String[] args) {
        Boos boos=new Boos();
        Secretray secretray=new Secretray(boos);
        secretray.signContract();
    }
}

缺点:因为代理对象,需要与目标对象实现一样的接口,我们得为每一个服务都得创建代理类,工作量太大,不易管理。同时接口一旦发生改变,代理对象与目标对象都要改变。不利于后期的维护。

优点:可以做到在符合开闭(不修改目标对象的功能)原则的情况下对目标对象进行功能扩展。

设想:我们能不能只编写一个代理类生成器,当我们需要某个类的代理对象时,代理类生成器会帮我
们自动创建对应的代理类。这就是动态代理的实现思路。

2.动态代理

动态代理模式:动态代理模式又可以分为 JDK 动态代理和 CGLIB 动态代理。

JDK 动态代理的实现

我们不再需要再手动的创建代理类,我们只需要编写一个动态处理器就可以了。真正的代理对象
由 JDK 在运行时为我们动态的来创建。

① 抽象角色

/**
 * 抽象角色
 * 签合同
 */
public interface SignContract {
    void signContract();
}

② 真实角色

/**
 * 真实角色
 * 老板
 */
class Boos implements SignContract{

    @Override
    public void signContract() {
        System.out.println("和***公司签订合同");
    }
}

③ 动态处理器

/**
 * 动态代理类
 * 需要实现 InvocationHandle接口,并实现invoke方法
 * public static Object newProxyInstance(ClassLoader loader,
 *                                           Class<?>[] interfaces,
 *                                           InvocationHandler h)
 */
public class JdkDynamicProxy implements InvocationHandler {
    //目标对象
    private Object target;
    public Object build(Object target){
        this.target=target;
        //给目标对象生成代理对象
        Object proxy = Proxy.newProxyInstance(target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),this);
        return proxy;
    }
    @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()方法三个参数:

  • ClassLoader loader:指定当前目标对象使用的类加载器,获取加载器的方法是固定的
  • Class[] interfaces:指定目标对象实现的接口的类型,使用泛型方式确认类型
  • InvocationHandler:指定动态处理器,`执行目标对象的方法时,会触发事件处理器的方法

④ 测试

public class TestJdkProxy {
    public static void main(String[] args) {
        //获取代理对象
        JdkDynamicProxy jdkPro=new JdkDynamicProxy();
        SignContract signContract = (SignContract) jdkPro.build(new Boos());
        signContract.signContract();
    }
}

特点:JDK 实现动态代理需要实现类通过接口定义业务方法
缺点:对于没有接口的类,如何实现动态代理呢,这就需要 CGLib 了

CGLIB 动态代理的实现

CGLib 采用了非常底层的字节码技术,其原理是通过字节码技术为一个类创建子类,并在子类中
采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。

采用 CGLIB 代理方式时需要导入 jar 文件:cglib.jar 和 asm.jar

代理类生成器

public class CglibProxy implements MethodInterceptor {

    private Object target;

    public Object getInstance(final Object target) {
        this.target = target;
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(this.target.getClass());
        enhancer.setCallback(this);
        return enhancer.create();
    }
	@Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("签合同之前");
         Object result = methodProxy.invokeSuper(o, objects);
        System.out.println("签合同之前");
        return result;
    }
}

测试

public class CglibProxyTest {
    public static void main(String[] args) {
        CglibProxy cglibProxy=new CglibProxy();
        SignContract proxyInstance = (SignContract) cglibProxy.getInstance(new Boos());
        proxyInstance.signContract();
    }
}

由于CGLib由于是采用动态创建子类的方法,对于final修饰的方法无法进行代理。

JDK 动态代理与 CGLIB 动态代理的区别

JDK 动态代理:
能够继承静态代理的全部优点.并且能够实现代码的复用.
动态代理可以处理一类业务.只要满足条件 都可以通过代理对象进行处理.
动态代理的灵活性不强.
JDK 的动态代理要求代理者必须实现接口, , 否则不能生成代理对象.
CGLIB 动态代理:
不管有无接口都可以创建代理对象.
cglib 创建的代理对象是目标对象的子类.
不能对 final 修饰的类进行代理

代理模式

原文:https://www.cnblogs.com/lzhya/p/12591539.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!