Java中使用代理的作用是对目标对象的增强,在实际中我们可以在执行目标方法前后进行一些必要的处理。
1.静态代理
静态代理比较容易理解,我们直接给出例子。比如我们的目标方法是request方法,但是我们希望在每次调用request方法前都进行处理,如打印日志,那么久需要使用代理来处理。
接口
public interface Subject{
public void request();
}
目标类
class SubjectImpl implements Subject{
public void request(){
System.out.println("I am dealing the request.");
}
}
静态代理类
在静态代理类中我们接受实际的目标对象,并且在目标方法前后可以进行处理。
class StaticProxy implements Subject{
//实际目标对象
private Subject subject;
public StaticProxy(Subject subject){
this.subject = subject;
}
public void request(){
System.out.println("PreProcess");
subject.request();
System.out.println("PostProcess");
}
}
测试方法
在我们调用p.request()方法的时候则会打印出目标方法前后的信息
public class StaticProxyDemo {
public static void main(String args[]){
//创建实际对象
SubjectImpl subject = new SubjectImpl();
//把实际对象封装到代理对象中
StaticProxy p = new StaticProxy(subject);
p.request();
}
}
总结:静态代理的优缺点很明显,优点是代码简单,缺点是当目标对象有多个方法时,我们要对每个方法都进行处理,因此会非常繁琐。
2.动态代理
动态代理克服了静态代理的缺点,在动态代理中,目标对象的方法每次被调用都进行动态拦截。
简单解释一下下面的图:客户端每次调用都是代理对象的方法,不可能直接调用目标对象的方法,所有的调用方法都会被拦截下来,转发给代理处理器的invoke方法进行处理,在代理处理器的invoke方法中我们可以判定该方法是什么方法,有什么参数。最后再调用目标对象的真实方法来进行工作,真实方法执行结束以后,一路返回执行结果。
下面举例
接口和目标类与静态代理的相同
接口
public interface Subject {
public void request();
}
目标类
public class SubjectImpl implements Subject {
@Override
public void request() {
System.out.println("I am dealing the request.");
}
}
代理处理器
/*
* 代理处理器,实现了InvocationHandler接口
* */
public class ProxyHandler implements InvocationHandler {
//持有目标对象的句柄
private Subject subject;
public ProxyHandler(Subject subject){
this.subject = subject;
}
/*
* invoke()方法
* 此方法在代理对象调用任何一个方法时都会被调用
*
* 第一个参数:proxy 代理对象
* 第二个参数:method 反射里面的Method类,查看具体调用哪个方法
* 第三个参数:args 具体的形参
* */
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
//输出代理类的名字
System.out.println(proxy.getClass().getName());//代理对象所属的类是虚拟机自动生成的
//定义预处理工作,当然也可以根据method的不同进行不同的预处理工作
System.out.println("=========before========");
//调用真实的目标对象来进行工作
Object result = method.invoke(subject, args);
System.out.println("=========before========");
return result;//返回结果
}
}
测试类
//动态代理模式
public class TestDynamicProxy {
public static void main(String[] args) {
//1.创建目标对象
final Subject subject = new SubjectImpl();
//2.创建代理处理器对象
ProxyHandler proxyHandler = new ProxyHandler(subject);
//3.动态生成代理对象
Subject proxySubject = (Subject) Proxy.newProxyInstance(
subject.getClass().getClassLoader(), //类加载器
subject.getClass().getInterfaces(), //具体的接口
proxyHandler); //代理对象需要代理处理器对象,代理处理器重写了invoke方法
//4.客户端通过代理对象调用方法,本次调用将自动地被代理处理器的invoke方法接收
proxySubject.request();
System.out.println(proxySubject.getClass().getName());
}
}
测试结果:
com.sun.proxy.$Proxy0是代理对象所属的类,它是由虚拟机自动生成的。
对代理处理器 的理解:
代理处理器持有目标对象的句柄,并实现InvocationHandler接口
- 主要是实现了invoke方法
- 所有的代理对象方法调用,都会转发到invoke方法来
- invoke的形参method,就是指代理对象方法的调用
- 在invoke内部,可以根据method,使用目标对象不同的方法来响应请求