Java反射包中的Proxy类通过创建一个类的代理,让我们轻松地拦截该类实例的方法,甚至可以改变方法的行为。下面是使用Proxy的一个简单例子。
主要有4步:
- 定义接口
- 实现接口
- 定义拦截处理器
- 创建代理对象
1. 定义接口
public interface Student {
public void study();
}
2. 实现接口
public class StudentImpl implements Student {
public void study() {
System.out.println("I'm studying.");
}
}
3. 定义拦截处理器
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class StudentInvocationHandler implements InvocationHandler {
//一般来讲,handler需要负责持有被代理对象的引用
private Student target;
/** Creates a new instance of MyHandler */
public StudentInvocationHandler(Student target) {
this.target = target;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("adding somthing before the method " + method.getName());
method.invoke(target, args);
System.out.println("adding somthing after the method " + method.getName());
return null;
}
}
4. 创建代理对象
public class ProxyTest {
public static void main(String[] args) {
Student student = (Student) Proxy.newProxyInstance(Student.class.getClassLoader(),
new Class[] { Student.class }, //必须为接口
new StudentInvocationHandler(new StudentImpl())); //传进被代理对象
student.study();
}
}
Proxy通过静态方法newProxyInstance为我们创建了一个student的代理类,当调用此类实例的方法时,StudentInvocationHandler进行了拦截,并在调用其study()方法之前与之后分别输出了一行字。
而对于用户代码来讲,其只是要求调用student的study()方法,根本不知道此方法已被拦截,甚至不知道此方法已被修改。如果更彻底,通过以下的工厂方法来产生一个student,那么用户就不会怀疑所返回的student竟然不会他所要的:
Student student = StudentFactory.getStudent();
工厂类:
public class StudentFactory() {
public static Student getStudent() {
return (Student) Proxy.newProxyInstance(Student.class.getClassLoader(),
new Class[] { Student.class },
new StudentInvocationHandler(new StudentImpl()));
}
}
我想到了一个场景:我让我的男秘书帮我去把我相中的姑娘带回来,而实际上,他带给我的却是她的孪生妹妹。以后的事实证明,我爱的姑娘跟他私奔了!
结论:
因此,通过Proxy,我们可以在运行时动态地改变类的行为。而活用工厂模式,将产生一个类实例的时间从编译时延缓到运行时,将使我们的类更加灵活。