设计模式-代理模式

定义:

代理模式:使用代理对象完成用户请求,屏蔽用户对真实对象的访问。
在软件设计中,使用代理模式的场景很多,比如处于安全考虑,需要屏蔽用户直接访问真实对象;或者在远程调用中,需要使用代理类处理远程方法调用的技术细节;也可以为了提升系统性能,对象真实对象进行封装,从而达到延迟加载的目的。

结构:
角色作用
主题接口定义代理类和真实主题对外方法,也是代理类代理真实主题的方法
真实主题真正实现业务逻辑的类
代理类用来代理和封装真实主题
Main客户端,使用代理类和主题接口完成工作
应用场景:

假设有个数据据查询数据功能,在查询数据前,需要获得数据库连接。软件启动时,初始化所有类,此时尝试获取数据库连接。当系统有大量类似操作叠加时,会使得系统启动速度变得非常缓慢。
在系统启动时,将消耗资源阿娜最多的方法使用代理模式分离,就可以加快系统启动速度,减少用户等待时间。而用户在真正查询数据时,再由代理类,单独去加载真实的数据库查询类。这个过程就是使用代理模式实现延迟加载

UML:

这里写图片描述

代码:
public interface IDBQuery {
    String request();
}
public class DBQuery implements IDBQuery {

    public DBQuery() {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }
    @Override
    public String request() {
        return "request string";
    }
}
public class DBQueryProxy implements IDBQuery {

    private DBQuery real;

    @Override
    public String request() {
        //在真正需要时,才创建真实对象
        if (real == null) {
            real = new DBQuery();
        }
        return real.request();
    }
}
public class Main {
    public static void main(String[] args) {
        IDBQuery query = new DBQueryProxy();
        query.request();
    }
}
动态代理:

动态代理是指在运行时,动态生成代理类。即,代理类的字节码将在运行时生成并加载到当前的ClassLoader。
好处:
1. 不需要为真实主题写一个形式上完全一样的封装类
2. 使用动态代理的生成方法可以在运行时指定代理类的执行逻辑,提升系统的灵活性

实现方式:
  1. JDK自带的动态代理
  2. CGLIB
  3. Javassist
  4. ASM

动态代理步骤

JDK动态代理使用:
public class JDKDBQueryHandler implements InvocationHandler{

    IDBQuery real;
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if (real ==null) {
            real = new DBQuery();
        }
        return real.request();
    }
}
public static IDBQuery createJDKProxy() {
        return (IDBQuery) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(),
            new Class[]{IDBQuery.class}, new JDKDBQueryHandler());
    }
CDLIB使用:
public class CglibDBQueryInterceptor implements MethodInterceptor {
    IDBQuery real;
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        if (real == null) {
            real = new DBQuery();
        }
        return real.request();
    }
}
public static IDBQuery createCglibProxy() {
    Enhancer enhancer = new Enhancer();
    //指定切入器,定义代理类逻辑
    enhancer.setCallback(new CglibDBQueryInterceptor());
    //指定实现接口
    enhancer.setInterfaces(new Class[]{IDBQuery.class});
    //生成代理类实例
    return (IDBQuery) enhancer.create();
}
Javassist使用:

Javassist生成动态代理类可以使用两种方式:一种是使用代理工厂创建,另一种通过使用动态代码创建。
使用代理工厂:

public class JavassistDBQueryHandler implements MethodHandler {
    IDBQuery real;
    @Override
    public Object invoke(Object o, Method method, Method method1, Object[] objects) throws Throwable {
        if (real == null) {
            real = new DBQuery();
        }
        return real;
    }
}
public static IDBQuery createJavassistPRoxy() throws IllegalAccessException, InstantiationException {
        ProxyFactory proxyFactory = new ProxyFactory();
        proxyFactory.setInterfaces(new Class[]{IDBQuery.class});
        Class aClass = proxyFactory.createClass();
        IDBQuery query = (IDBQuery) aClass.newInstance();
        ((ProxyObject) query).setHandler(new JavassistDBQueryHandler());
        return query;
    }

使用动态代码:

public static IDBQuery createJavassistByteCodeDynProxy() throws NotFoundException, CannotCompileException, IllegalAccessException, InstantiationException {
        ClassPool classPool = new ClassPool(true);
        //定义类名
        CtClass ctClass = classPool.makeClass(IDBQuery.class.getSimpleName() + "Javassist-ByteCodeProxy");
        //需要实现接口
        ctClass.addInterface(classPool.get(IDBQuery.class.getName()));
        //添加构造函数
        ctClass.addConstructor(CtNewConstructor.defaultConstructor(ctClass));
        //添加类的字段信息
        ctClass.addField(CtField.make("public " + IDBQuery.class.getName() + " real;", ctClass));
        String name = DBQuery.class.getName();
        //添加方法
        ctClass.addMethod(CtMethod.make("public String request() {if(real ==null) real = new  "
            + name + "(); return real.request();}", ctClass));
        //基于以上信息,生成动态类
        Class aClass = ctClass.toClass();
        //生成动态类的实例
        return (IDBQuery) aClass.newInstance();
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值