JavaEE-Java开发框架的基础-代理模式-静态代理与动态代理
概述
代理模式的作用是:为其他对象提供一种以控制对方的访问
某种情况下,一个客户不想或者不能直接引用另一个对象的时候,可以在客户端和目标对象中间起到中介的作用
代理模式的角色有以下三种:
第一种:抽象角色,声明真实对象和代理对象的共同接口
第二种:代理角色,代理对象角色内部含有对真实对象的引用,从而可以操纵真实的对象,同时代理对象提供与真实对象相同的接口以便在任何时刻都能代替真实对象,同时代理对象可以在执行真实对象操作时,附加其他的操作,相当于对真实对象进行封装
第三种:真实角色,代理所代理的真实角色,是我们要引用的对象
静态代理
在程序运行前就已经存在代理类的字节码文件,代理类和委托类的关系在运行前就确定了
抽象角色
租房服务
public interface HireHouse {
public void hire();
}
具体角色
租房者
public class HireHouseReal implements HireHouse{
public void hire(){
System.out.println("租房子");
}
}
代理角色
中介
public class HireHouseProxy implements HireHouse{
private HireHouseReal hr;
public void hire(){
if(hr == null){
hr = new HireHouseReal();
System.out.println("收租金和中介费和押金");
hr.hire();
System.out.println("扣押金");
}
}
}
静态代理的缺陷在于:
- 代理对象的一个接口只服务于一种类型的对象,如果要代理的方法很多,势必要为每一种方法都进行代理,静态代理在程序规模稍大无法胜任
- 如果接口增加一个方法,除了所有实现类需要实现这个方法外,所有代理类也需要实现此方法,增加了代码维护的复杂度
动态代理
动态代理开发步骤
1.创建一个实现接口InvocationHandler的类,它必须实现invoke方法
2.创建被代理的类和接口
3.通过Proxy.newProxyInstance来创建代理类
4.通过代理调用
被代理接口
public interface InterDemo {
//接口方法
public void dosomething();
}
被代理接口实现类
public class InterDemoImpl implements InterDemo {
/**
* 方法实现类
*/
@Override
public void dosomething() {
System.out.println("doing");
}
}
代理类
public class XProxy implements InvocationHandler {
/**
* 被代理的对象-任何接口 (真实角色) */
private Object obj;
/**
* 提供代理类构造器 */
public XProxy(Object obj) {
super();
this.obj = obj;
}
/**
* 通过反射方式来调用被代理的方法
*/
@Override
public Object invoke(Object arg0, Method method, Object[] arg)throws Throwable {
System.out.println("前置工作");
Object result = method.invoke(obj, arg);
System.out.println("后置工作");
return result;
}
}
主函数调用:
public class Client {
public static void main(String[] args) {
//创建接口实现类
InterDemoImpl idi = new InterDemoImpl();
//创建代理的实现类
XProxy xpx = new xProxy(idi);
/*创建动态代理对象
*第一个参数:接口实现类的类加载器
*第二个参数:接口实现类的接口
*第三个参数:代理类实例
*/
InterDemo id = (InterDemo) Proxy.newProxyInstance(idi.getClass().getClassLoader(), idi.getClass().getInterfaces(), xpx);
id.dosomething();
}
}
三段代码就是一句话,代理类为任何实现了被代理接口的类做代理,具体的逻辑由于被封装起来了,故只要记住是这么操作的就行,固定模式
优点:
动态代理与静态代理相比较,最大的好处是接口中声明的所有方法都被转移到调用处理器一个集中的方法中处理(InvocationHandler.invoke),这样,在接口方法数量比较多的时候,我们可以进行灵活处理,而不需要像静态代理那样每一个方法进行中转