代理模式
1、原理(百度)
代理模式的主要作用是为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
代理模式的思想是为了提供额外的处理或者不同的操作而在实际对象与调用者之间插入一个代理对象。这些额外的操作通常需要与实际对象进行通信。
2、静态代理模式
原理讲解
- 代理类与被代理类都必须实现同一个接口。
- 代理类对被代理类进行封装,由代理类决定 被代理类的对象的创建、创建时间、何时调用方法。
- 被代理类的方法调用放在代理类中执行。
- 代理类中执行被代理类的方法时可以进行其他操作。
以手机厂商为例:
现在有一个手机工厂的接口
public interface PhoneFactory {
void producePhone();//生产一批手机
}
现在有两个实现类:代理类与被代理类都实现了PhoneFactory接口
1、代理类ProxyFactory
//代理类
public class ProxyFactory implements PhoneFactory{
private PhoneFactory factory;//被代理类对象进行实例化
public ProxyFactory(PhoneFactory factory) {
this.factory = factory;
}
@Override
public void producePhone() {
System.out.println("代理工厂做前期准备工作");
factory.producePhone();
System.out.println("代理工厂的后期工作");
}
}
2、被代理类MiFactory
//被代理类
public class MiFactory implements PhoneFactory{
@Override
public void producePhone() {
System.out.println("生产一批手机");
}
}
3、静态代理模式实现:
public class Test {
public static void main(String[] args) {
MiFactory mi = new MiFactory();//创建被代理类对象
ProxyFactory proxyFactory = new ProxyFactory(mi);//创建代理类的对象
proxyFactory.producePhone();//代理类对象对被代理类方法的封装与其他处理
}
}
结果:
静态代理过程描述:
- 创建被代理类的对象
- 将被代理类的对象mi 传入 代理类的实例化对象 proxyFactory 中
- 在proxyFactory 调用同名方法 (实际上时调用代理类的对象mi 的方法,在proxyFactory 中进行其他操作。
三、动态代理模式
1、静态代理存在的问题:
代理类和目标对象的类都是在编译期间确认下来,不利于程序的扩展。
同时,每一个代理类只能为一组接口服务,
这样一来程序开发中必然产生过多的代理。
2、动态代理模式说明:
①动态代理时指客户通过代理类来调用其他对象的方法,并且时在程序运行时根据需要动态的创建目标类的代理对象。
②动态代理使用的场合:
- 调试
- 远程方调用
优点:
抽象角色中(接口)声明的所有方法都被转移到调试处理器一个集中的方法中处理,这样,我们可以更灵活和统一的处理众多的方法
3、代码举例说明
首先,我们需要创建一个共同的接口。(以Human为例)
public interface Human {
String getBelief();//获取信仰的方法
void eat(String food);//吃的方法
}
其次,我们需要一个代理类
public class DynamicProxy {
//调用此方法 动态的创建代理类的对象
//参数为 被代理类的对象
public static Object getInstance(Object obj){
MyInvocationHandler handler = new MyInvocationHandler(obj);//InvocationHandler接口的实现类
return Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),handler );
}
}
Proxy.newProxyInstance();
Proxy是 java.lang.reflect.Proxy;
.newProxyInstance(); // 方法会使用反射的原理 动态的生成一个对象
方法的三个参数
obj.getClass().getClassLoader() // 获取被代理类的Class类的类加载器
obj.getClass().getInterfaces() // 获取被代理类的Class类的接口数组
InvocationHandler的实现类
//InvocationHandler的实现类
public class MyInvocationHandler implements InvocationHandler {
private Object obj;//需要一个被代理类的对象
//构造器
public MyInvocationHandler(Object obj) {
this.obj = obj;
}
/**
*当我们通过代理类调用方法时 会自动的调用如下方法
* invoke(Object proxy, Method method, Object[] args);
* Object proxy代理类
* Method method 被调用方法
* Object[] args 参数列表
* returnValue 返回值
**/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object returnValue = method.invoke(obj, args);
return returnValue;
}
}
最后,我们需要一个被代理类
//被代理类
public class SuperMan implements Human{
@Override
public String getBelief() {
return "I believe i can fly";
}
@Override
public void eat(String food) {
System.out.println("我喜欢一直吃"+food);
}
}
动态代理模式实现:
public class test {
public static void main(String[] args) {
//创建被代理类的对象
SuperMan superMan = new SuperMan();
Human proxy = (Human) DynamicProxy.getInstance(superMan);//动态的创建代理类的对象
//调用方法
proxy.eat("小鱼");
String belief = proxy.getBelief();
System.out.println(belief);
}
}
结果:
动态代理过程说明
-
代理类的动态创建需要 传入 被代理类的对象,
-
通过getInstance()方法返回一个代理类的对象
-
Proxy.newProxyInstance()方法需要三个参数 (代理类的对象的类加载器,代理类的对象的接口集合,InvocationHandler的实现类);
-
InvocationHandler接口的主要作用是将代理类与被代理类进行链接。
-
正因为需要连接 所以我们需要传入被代理类的对象
InvocationHandler接口的实现类需要实现
invoke方法 (Object proxy, Method method,Object[] args)
proxy 代理类
method 将被调用的方法
args 被调用的方法 的参数数组 -
invoke方法 中调用 被代理类的对象的invoke方法即可实现代理模式
-
InvocationHandler接口的实现类的invoke方法 中 可以增加其他操作
-
InvocationHandler接口的实现类作为Proxy.newProxyInstance()方法的参数,进行绑定 当调用代理类的方法时会自动的调用InvocationHandler接口的实现类的invoke方法,实现动态代理