代理模式概念:
理模式的定义
1、为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用,比如我们要去法院申诉,中间需要一个律师帮忙代理一下注意事项等,这个律师就是代理类。
2、当一个复杂对象的多份副本须存在时,代理模式可以结合享元模式以减少存储器用量。典型作法是创建一个复杂对象及多个代理者,每个代理者会引用到原本的复杂对象。而作用在代理者的运算会转送到原本对象。一旦所有的代理者都不存在时,复杂对象会被移除。
抽象角色:通过接口或抽象类声明真实角色实现的业务方法。
代理角色:实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,可以附加自己的操作。
真实角色:实现抽象角色,定义真实角色所要实现的业务逻辑,供代理角色调用。
一个是真正的你要访问的对象(目标类),一个是代理对象,真正对象与代理对象实现同一个接口,先访问代理类再访问真正要访问的对象。
代理模式分为静态代理、动态代理。
静态代理是由程序员创建或工具生成代理类的源码,再编译代理类。所谓静态也就是在程序运行前就已经存在代理类的字节码文件,代理类和委托类的关系在运行前就确定了。
动态代理是在实现阶段不用关心代理类,而在运行阶段才指定哪一个对象。
只看概念有点懵,现在举个例子,比如我们人要去法院申诉用代码演示
静态代理:
1、我们先创建一个接口类打官司接口Law
//打官司接口
public interface Law {
public void law();
}
2、现在是我们进行申诉 目标类
public class Person implements Law {
@Override
public void law() {
// TODO Auto-generated method stub
System.out.println("目标类去法庭申述");
}
}
3、现在是静态代理的核心部分,律师代理类
//代理类
public class Lawyer implements Law {
//引入目标类
private Person person;
@Override
//核心
public void law() {
// TODO Auto-generated method stub
this.a();
//person对象实例化,只有实例化之后,才能将这个对象放到内存中,然后才能在规定的范围内来调用
if(person==null) {
person=new Person();
}
//调用目标类的方法
person.law();
this.b();
}
//律师要处理的事情
public void a() {
System.out.println("开庭前收集证据");
}
public void b() {
System.out.println("案件结案处理");
}
}
静态代理类比较好理解,现在直接创建客户端测试一下
4、创建客户
public class test {
public static void main(String[] args) {
// TODO Auto-generated method stub
Lawyer lawyer=new Lawyer();
lawyer.law();
}
}
运行结果:
上面就是静态代理模式,比较简单,我们就不解释了,动态代理不同于静态代理的特点是它更为灵活,因为动态代理就是在运行期间动态生成代理类。我们沿用上面的例子,假设有五百个不一样的人要打官司,都交给律师来操办,那么按照静态代理的思路来做,我们需要写五百个真实角色,并且代理角色持有这五百个真实角色。这显然不合逻辑。这时候动态代理就应运而生了。下面我们要演示动态代理模式。
动态代理类的接口类和目标类跟静态代理类一样
1、打官司接口Law
//打官司接口
public interface Law {
public void law();
}
2、目标类
public class Person implements Law {
@Override
public void law() {
// TODO Auto-generated method stub
System.out.println(this.getClass().getSimpleName()+"目标类去法庭申述");
}
}
3、现在我们需要创建一个对象类去实现动态代理的一个核心接口InvocationHandler,动态代理本质采用的Java反射机制实现
InvocationHandler 是一个接口,官方文档解释说,每个代理的实例都有一个与之关联InvocationHandler 实现类,如果代理的方法被调用,那么代理便会通知和转发给内部的 InvocationHandler 实现类,由它决定处理。
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
//实现动态代理的一个核心接口,动态代理本质采用的Java反射机制实现
//InvocationHandler 是一个接口,官方文档解释说,每个代理的实例都有一个与之关联的 InvocationHandler 实现类,
//如果代理的方法被调用,那么代理便会通知和转发给内部的 InvocationHandler 实现类,由它决定处理。
public class MyHandler implements InvocationHandler {
private Object object;
public MyHandler(Object object) {
this.object=object;
}
// InvocationHandler 内的 invoke() 方法决定了怎么样处理代理传递过来的方法调用。
// proxy 代理对象
// method 代理对象调用的方法
// args 调用的方法中的参数
// Proxy 动态产生的代理会调用 InvocationHandler 实现类,因此 InvocationHandler 是实际执行者。
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// TODO Auto-generated method stub
System.out.println("开庭前律师收集证据");
Object obj=method.invoke(object, args);
System.out.println("目标类陈述事实");
return obj;
}
上面用到 InvocationHandler 内的 invoke() 方法决定了怎么样处理代理传递过来的方法调用,里面的三个参数分别代表
// proxy 代理对象
// method 代理对象调用的方法
// args 调用的方法中的参数
// Proxy 动态产生的代理会调用 InvocationHandler 实现类,因此 InvocationHandler 是实际执行者。
4、我们直接去创建一个客户端去实现动态代理:
import java.lang.reflect.Proxy;
public class test {
public static void main(String[] args) {
// TODO Auto-generated method stub
//代理目标类
Law law=new Person();
//生成代理对象,Proxy类通过调用newProxyInstance这个方法生产代理对象
//动态代码涉及了一个非常重要的类 Proxy,通过 Proxy 的静态方法 newProxyInstance 才会动态创建代理。
//它的 3 个参数意义。
//loader即这里的Law.class.getClassLoader() 自然是类加载器
//interfaces即new Class[]{Law.class} 代码要用来代理的接口
//h即new MyHandler(law) 一个 InvocationHandler 对象
Law proxy=(Law)Proxy.newProxyInstance(Law.class.getClassLoader(), new Class[] {Law.class}, new MyHandler(law));
proxy.law();
}
// 上面执行person类的结果,那么如果律师接待第二个人Other呢?我们直接载加一个Other对象,然后客户端直接加下面代码就可以了
Law law1=new Other();
Law proxy1=(Law)Proxy.newProxyInstance(Law.class.getClassLoader(), new Class[]{Law.class}, new MyHandler(law1));
proxy1.law();
}
生成代理对象Proxy类通过调用newProxyInstance这个方法生产代理对象
动态代码涉及了一个非常重要的类 Proxy,通过 Proxy 的静态方法 newProxyInstance 才会动态创建代理。
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
//它的 3 个参数意义。
//loader即这里的Law.class.getClassLoader() 自然是类加载器
//interfaces即new Class[]{Law.class} 代码要用来代理的接口
//h即new MyHandler(law) 一个 InvocationHandler 对象
添加的第二个人Other:
public class Other implements Law {
@Override
public void law() {
// TODO Auto-generated method stub
System.out.println(this.getClass().getSimpleName()+"目标类去法庭申述");
}
}
运行结果:
上面就演示完静态代理模式和动态代理模式了,如果还是很懵,可以去https://www.jianshu.com/p/d9e1641fbb6c查看,那里有详细介绍Proxy.newInstance(…)、getProxyClass0(loader, intfs)源码
动态代理模式和静态代理模式的应用场景:
静态代理主要用来处理少部分类的托管或者扩展。静态代理对于被代理的对象很固定,我们只需要去代理一个类或者若干固定的类,数量不是太多的时候,可以使用,而且其实效果比动态代理更好。
动态代理在运行期间动态生成代理类,需要消耗的时间会更久一点。优点是可以做很多类的扩展,而且如果一个类的接口发生了变化,那么静态代理这时候修改起来就很麻烦了。这就是说动态代理灵活的原因。
动态代理主流的实现有两种,一种是基于接口的Java Proxy的代理机制,一种是基于继承的cglib代理机制。两种也都有其应用场景。
转载:https://blog.csdn.net/weixin_44001568/article/details/105639136