今天继续学习。接着之前的代理模式继续。
先是想到了代理模式的作用,就搜素了一下。代理模式的作用:
- 安全考虑:这点很容易理解,比如我只想暴露A类的方法f()给外界,但是还有其他的方法g()、h(),那么用代理模式就能达到目的了。
- 性能增前:延迟重量级对象创建
- 方法增强:这点貌似是装饰器模式的特长,但是代理模式也可以做到
以上是静态代理代理模式,与之对应的还有动态代理模式,动态代理模式比静态代理模式更加灵活,因为不再需要为每个接口写一个形式上完全一样的封装类,将来接口变得也基本不需要做改动。
下面来看一下动态代理机制:
贴出动态代理里面核心的代码:
// 数据库查询接口类
public interface IDBQuery {
public void request(String requestParamStr);
}
//数据库查询实现类
public DBQuery implements IDBQuery {
public DBQuery() {
// 连接数据库,初始化等等耗时操作,略
}
@Override
public void request(String requestParamStr) {
// 略
}
}
// 代理类
public class DBQueryProxy implements IDBQuery {
private DBQuery real= null; // 被代理对象
@Override
public void request(String requestParamStr) {
if(real == null)
real = new DBQuery(); // 延迟到这里创建DBQuery对象
real.request();
}
}
// 使用
IDBQuery query = new DBQueryProxy();
query.requst(); // 真正使用时才会创建真实的DBQuery对象
public Object invoke(Object proxy, Method method, Object[] args)throws Throwable
处理代理实例上一个方法的调用并返回处理结果。
当一个代理实例上的一个方法被调用时,则其关联的调用处理程序这个方法将被调用。
proxy:被调用方法的代理实例
method:与代理实例上调用的接口方法对应的方法对象,该方法对象将是接口中声明的方法,也可以是代理类通过代理接口的父接口继承的方法
args:包含代理实例上方法调用被传递的参数值对象数组,如接口方法没有参数则为null,原始类型的参数用适当的原始包装类的实例 如java.lang.Integer 等
return:从代理实例上方法调用返回的值。如果接口方法声明的返回类型是原始类型,则返回与之相应的原始包装类的实例,否则 返回其声明指定的类型。
若返回值为null并且接口的方法是返回类似是原始类型,则抛出NullPointerException。
若返回值与接口方法声明的返回类型不兼容,则抛出ClassCastException
throws:从代理实例上方法调用抛出的异常。异常类型是接口方法可抛出的任何异常类型or未受检查异常or错误
若抛出一个受检查异常而该受检查不是接口方法中声明的异常类型,则一个UndeclaredThrowableException抛出
此时我们再从两者的区别来比较一下:
与静态代理类对照的是动态代理类,动态代理类的字节码在程序运行的时候有java反射机制动态生成,无需程序员手工编写它的源代码。动态代理不仅简化了编程工作,而且提高了软件系统的可扩展性,因为java反射机制可以生成任意类型的动态代理。