引入动态代理
在传统的静态代理模式中,真实角色和代理角色都已经事先定义好了,而实际使用中,因为一个真实角色必须对应一个代理角色,如果大量使用会导致类的急剧膨胀,而且有些情况事先并不知道代理角色,为了解决这一问题就引出了动态代理。
动态代理定义
动态代理是代理模式的一种扩展形式,能够让系统在运行时根据实际需要来动态创建代理类,并且可以让同一个代理类能够代理多个不同的真实角色类而且可以代理不同的方法。
动态代理涉及的类
(1)InvocationHandler
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
proxy参数:代理类
method:被代理的方法
args:方法的参数数组
(2)Proxy
构造函数,给InvocationHandler 赋值
protected Proxy(InvocationHandler h) {
doNewInstanceCheck();
this.h = h;
}
获得一个代理类,其中loader是类装载器,interfaces是真实类所拥有的全部接口的数组。
public static Class<?> getProxyClass(ClassLoader loader,
Class<?>... interfaces)
返回代理类的一个实例,返回后的代理类可以当作被代理类使用。
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
还有其他一些方法,这里就不一一探讨了。
动态代理示例
我们将《Java与模式》中的静态代理模式做一些修改
//抽象角色[修改为接口]
public interface Subject {
abstract public void request();
}
//真实角色
public class RealSubject implements Subject {
public RealSubject() {
super();
}
@Override
public void request() {
System.out.println("From real subject.");
}
}
//代理角色
public class DynamicSubject implements InvocationHandler {
private Object sub;
public DynamicSubject(Object sub){
this.sub = sub;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("before calling " + method);
method.invoke(sub,args);
System.out.println("after calling " + method);
return null;
}
}
该代理类的内部属性为Object类,实际使用时通过该类的构造函数DynamicSubject(Object sub)对其赋值;此外,在该类还实现了invoke方法,该方法中的"method.invoke(sub,args)" 其实就是调用被代理对象的将要被执行的方法,方法参数sub是实际的被代理对象,args为执行被代理对象相应操作所需的参数。通过动态代理类,我们可以在调用之前或之后执行一些相关操作。
public class TestDynamicProxy {
public static void main(String[] args) {
RealSubject rs = new RealSubject(); // 在这里指定被代理类
InvocationHandler ds = new DynamicSubject(rs); // 初始化代理类
Class cls = rs.getClass();
// 以下是分解步骤
/*
* Class c =
* Proxy.getProxyClass(cls.getClassLoader(),cls.getInterfaces());
* Constructor ct=c.getConstructor(new
* Class[]{InvocationHandler.class}); Subject subject =(Subject)
* ct.newInstance(new Object[]{ds});
*/
// 以下是一次性生成
Subject subject = (Subject) Proxy.newProxyInstance(
cls.getClassLoader(), cls.getInterfaces(), ds);
subject.request();
}
通过这种方式,被代理的对象(RealSubject)可以在运行时动态改变,需要控制的接口(Subject接口)可以在运行时改变,控制的方式(DynamicSubject类)也可以动态改变,从而实现了非常灵活的动态代理关系。
查看结果:
before calling public abstract void com.review.proxy.dynamicDemo.Subject.request()
From real subject.
after calling public abstract void com.review.proxy.dynamicDemo.Subject.request()