代理,是一种设计模式,提供了对目标对象另外的访问方式;即通过代理对象访问目标对象。这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能。
这里用到一个编程思想:不要随意去修改别人已经写好的代码或者方法,如果需要修改,可以通过代理的方式去扩展该方法。
代理模式的关键点在于:代理对象和目标对象。代理对象是对目标对象的扩展,并且会调用目标对象。
1.静态代理
静态代理在使用时,需要定义接口或者父类,目标对象与代理对象一起实现相同的接口或者是继承相同的父类。
下面举个案例来解释:
模拟保存动作,定义一个保存动作的接口:Save
package proxy;
public interface Save {
public void save();
}
然后目标对象实现这个接口:Saver
package proxy;
public class Saver implements Save {
public void save(){
System.out.println("---完成存储任务!---");
}
}
此时使用静态代理方式:
即通过调用目标对象的方式实现代理对象的实现。
package proxy;
public class SaverProxy implements Save{
private Saver s;
public SaverProxy(Saver s){
this.s=s;
}
public void save(){
System.out.println("---系统正在加载中---");
s.save();
System.out.println("---系统加载完成---");
}
}
最后,是实验类:
package proxy;
public class Test {
public static void main(String[] args){
Saver s=new Saver();
SaverProxy sp=new SaverProxy(s);
sp.save();
}
}
实验结果:
---系统正在加载中---
---完成存储任务!---
---系统加载完成---
由此可见,静态代理可以做到在不修改目标对象的功能前提下,对目标进行功能扩展。当然,缺点也显而易见,因为代理对象需要与目标对象实现同样的接口,所以会有很多代理类,类太多。同时,一旦接口增加方法,目标对象和代理对象都要进行维护。
如何解决静态代理中的缺点呢?答案是可以使用动态代理方式。
2.动态代理
动态代理由以下特点:
1.代理对象只能代理接口
2.代理对象的生成,是利用JDK的API,动态地在内存中构建代理对象
JDK中生成代理对象的API
代理类所在包:java.lang.reflect.Proxy
JDK实现代理只需使用newProxyInstance方法,但是该方法需要接收三个参数:
------首先是指定当前目标对象使用的类加载器,获取加载器的方法是固定的,目前,用null表示使用默认的类加载器。
2.一个Class对象数组,其中每个元素都是需要实现的接口类型。
3.一个调用处理器。
动态调用过程如下图所示:
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsICM38FdsYkRGZkRG9lcvx2bjxiNx8VZ6l2cs0TPR5kMJRkT5NGVNBDOsJGcohVYsR2MMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2X0hXZ0xCMx81dvRWYoNHLrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZwpmLxYTO0UTN1kTMxEjNwAjMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.jpg)
我们举一个简单的例子:
目标接口:
package proxy;
public interface Subject{
public void rent();
public void hello(String str);
}
目标接口的实现类:
package proxy;
public class RealSubject implements Subject{//原对象
public void rent() {
System.out.println("原对象的rent函数主体");
}
public void hello(String str) {
System.out.println("原对象的hello函数主体:hello"+str);
}
}
调用处理器的实例化:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class DynamicProxy implements InvocationHandler{//调用处理器类,用于调用原对象
private Object subject;
public DynamicProxy(Object subject){
this.subject=subject;
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// TODO Auto-generated method stub
if("rent".equals(method.getName())){
System.out.println("before rent house");
System.out.println("Method:" + method);
method.invoke(subject, args);
System.out.println("rent over");
}else if("hello".equals(method.getName())){
System.out.println("before ");
System.out.println("Method:" + method);
method.invoke(subject, args);
System.out.println("hello over");
}
return null;
}
}
动态生成类对象的过程:
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class Client{
public static void main(String[] args){
Subject realSubject=new RealSubject();
InvocationHandler handler=new DynamicProxy(realSubject);
Subject subject=(Subject)Proxy.newProxyInstance(realSubject.getClass().getClassLoader(), realSubject.getClass().getInterfaces(), handler);
//动态生成类对象,由于Java是单继承语言,且生成的类对象已经默认继承Proxy类,所以只能根据接口进行代理
System.out.println(subject.getClass().getName());
subject.rent();
subject.hello("world");
}
}