参考文献:《Java程序性能优化》.葛一鸣
代理模式也是一种常见的设计模式。它使用代理对象完成用户请求,屏蔽用户对真实对象的访问。该模式下,用户只和代理打交道,而代理需要有当事人的授权,而且一些核心问题需要请示当事人。
代理模式应用很广泛,包括安全访问,远程调用,以及延时加载等,这里主要讲一下如何实现延时加载。
以一个简单的示例来阐述一下代理模式实现延时加载的方法和意义。假设某客户端软件,有根据用户请求,去查询数据库的功能。在查询数据库之前,需要获得数据库连接,软件开启的时候,初始化系统的所有类,此时尝试获取数据库连接。当系统有大量的类似操作时(比如XML解析等),所有这些初始化操作的叠加会使得系统的启动速度变得非常缓慢。为此,采用代理模式,采用代理类,封装对数据库查询中的初始化操作,当系统启动时,初始化这个代理类,而非真实的数据库查询类,而代理类什么都没有做,因此它的构造是相当迅速的。
在系统启动时,讲消耗资源最多的方法都使用代理模式分离,就可以加快系统的启动速度,减少用户的等待时间,而在用户真正做查询操作时,再由代理类单独去加载真实的数据库查询类,完成用户的请求。这个过程就是使用代理模式实现了延时加载。
代理模式的核心思想是:如果当前并没有使用这个组件,则不需要真实的初始化它,使用一个代理类对象替代他原有的位置,只要在真正使用的时候,才对它进行加载。
package com.smf.proxy;
/**
* @author 作者SMF:
* @version 创建时间:2018年9月26日 上午10:15:37
* 类说明
*/
public interface IDBQuery {
String request();
}
IDBQuery是一个主题接口,定义代理类和真实类需要对外部提供的服务。
package com.smf.proxy;
/**
* @author 作者SMF:
* @version 创建时间:2018年9月26日 上午10:16:19
* 类说明
*/
public class DBQuery implements IDBQuery{
public DBQuery(){
try {//比较重量级初始化时间比较长
Thread.sleep(10000);
} catch(InterruptedException e){
e.printStackTrace();
}
}
@Override
public String request () {
// TODO Auto-generated method stub
return null;
}
}
DBQuery是真实的查询类,比较重量级,初始化时间比较长,代理类DBQueryProxy是轻量级对象创建很快,用于代替DBQuery的位置
package com.smf.proxy;
/**
* @author 作者SMF:
* @version 创建时间:2018年9月26日 上午10:38:05
* 类说明
*/
public class DBQueryProxy implements IDBQuery{
private DBQuery real = null;
@Override
public String request () {
//在真实需要的时候才创建真实对象,创建过程可能很慢
if(real==null){
real = new DBQuery();
}
return real.request();
}
}
主函数如下:
package com.smf.proxy;
/**
* @author 作者SMF:
* @version 创建时间:2018年9月26日 上午11:19:32
* 类说明
*/
public class Main {
public static void main(String args[]){
IDBQuery query = new DBQueryProxy();
query.request();
}
}
动态代理介绍:
动态代理是指在运行时动态生成代理类。即,代理类的字节码将在运行时生成并载入当前的ClassLoader。和静态代理类相比,动态代理类有很多好处,首先不需要为真实主题写一个形式上完全一样的封装类,假如主题接口中的方法很多,为每一个接口写一个代理方法也是非常烦人的。如果接口有变动,则真实主题和代理类都需要修改,不利于系统维护;其次使用动态代理类的生成方法甚至可以在运行时制定代理类的执行逻辑,从而大大提升系统的灵活性。
详情见下一篇博客。