代理模式
代理模式类图:
被代理类和代理类都实现同一个接口,通过在代理类对象中注入一个被代理对象,通过调用代理对象的办法,在其办法中间接调用被代理对象,从而实现代理的作用。
代理模式要点:
- 代理和被代理类实现同一接口
- 代理对象中持有被代理对象的实例
动态代理
动态代理就是代理模式的具体实现。首先定义一个接口
/** * 创立Person接口 * @author Gonjan */public interface Person { //上交班费 void giveMoney();}
接口的实现类,也是被代理类
public class Student implements Person { private String name; public Student(String name) { this.name = name; } @Override public void giveMoney() { System.out.println(name + "上交班费50元"); }}
再定义一个代理类,同样实现接口:
/** * 学生代理类,也实现了Person接口,保留一个学生实体,这样既能够代理学生产生行为 * @author Gonjan * */public class StudentsProxy implements Person{ //被代理的学生 Student stu; public StudentsProxy(Person stu) { // 只代理学生对象 if(stu.getClass() == Student.class) { this.stu = (Student)stu; } } //代理上交班费,调用被代理学生的上交班费行为 public void giveMoney() { // 这里写加强代码 stu.giveMoney(); }}
具体应用代理类:
public class StaticProxyTest { public static void main(String[] args) { //被代理的学生张三,他的班费上交有代理对象monitor(班长)实现 Person zhangsan = new Student("张三"); //生成代理对象,并将张三传给代理对象 Person monitor = new StudentsProxy(zhangsan); //班长代理上交班费 monitor.giveMoney(); }}
为什么要有动静代理?
动态代理有余在于,加强代码只能对固定的某一个类起作用,如对 Student 类加强,那么就要编写针对 Student 类的接口 Person 的实现类,在实现类中编写加强代码。
如果加强代码是统计办法执行工夫,那么就须要在各种各样不同的类的接口上,反复做上述的事件:编写实现类,类中实现接口办法,编写加强代码等。
而动静代理就是解决一套加强代码,用在各种不同类之上的形式。
动静代理 JDK 实现
如果被代理类有接口,则能够是要用 JDK 的形式。JDK 提供了一组编写动静代理的基类。
Person 类不变:
public interface Person { //上交班费 void giveMoney(); void hello();}
编写 java.lang.reflect.InvocationHandler 接口的实现类,在这个接口中只有一个办法须要实现,就是 invoke 办法,在这个类中编写加强代码,将来代理性能就是通过调用这里实现的代理成果。
类中的泛型 T 曾经证实这个代码能够用在不同的类上。
import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;public class MyInvocationHandler<T> implements InvocationHandler { // invocationHandler持有的被代理对象 T target; public MyInvocationHandler(T target) { this.target = target; } /** * proxy:代表动静代理对象 * method:代表正在执行的办法 * args:代表调用指标办法时传入的实参 */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("代理执行" +method.getName() + "办法"); //代理过程中插入监测办法,计算该办法耗时 MonitorUtil.start(); Object result = method.invoke(target, args); result = method.invoke(target, args); result = method.invoke(target, args); MonitorUtil.finish(method.getName()); System.out.println("------"); return result; }}
应用 java.lang.reflect.Proxy 依据 InvocationHandler 来生成动静代理类,接着调用动静代理类:
import java.lang.reflect.InvocationHandler;import java.lang.reflect.Proxy;public class ProxyTest { public static void main(String[] args) { Person zhangsan = new Student("张三"); // 把Person接口传给泛型T,表明这是一个针对Person接口的代理,并将被代理对象传入其中让其持有 InvocationHandler stuHandler = new MyInvocationHandler<Person>(zhangsan); // 类加载器、代理须要实现的接口,能够有多个、办法调用的理论解决者 // 这一步是为了生成动静代理类的对象 // 类加载器为了可能找到指定的接口地位、须要代理的接口示意动静代理应该实现哪些接口,以及加强代码。 Person stuProxy = (Person) Proxy.newProxyInstance(Person.class.getClassLoader(), new Class<?>[]{Person.class}, stuHandler); // stuProxy.giveMoney(); stuProxy.hello(); stuProxy.hello(); stuProxy.hello(); // 同一套加强代码,替换不同的泛型 T ,实现加强不同的类 Dog dog = new Dog("小白"); MyInvocationHandler dogHandler = new MyInvocationHandler<Animal>(dog); Animal dogProxy = (Animal) Proxy.newProxyInstance(Animal.class.getClassLoader(), new Class<?>[]{Animal.class}, dogHandler); dogProxy.woo(); }}
动静代理 CGLib 实现
JDK 动静代理是基于接口的,要求被代理类须要实现接口。如果其没有接口,能够应用 CGLib 形式,这种形式基于继承。
一个具体类,也就是被代理类:
public class HelloConcrete { public String sayHello(String str) { return "HelloConcrete: " + str; }}
编写实现了 org.springframework.cglib.proxy.MethodInterceptor 接口的类,是一个办法拦截器类,即拦挡被代理办法,在其中做加强:
import org.springframework.cglib.proxy.MethodInterceptor;import org.springframework.cglib.proxy.MethodProxy;import java.lang.reflect.Method;import java.util.Arrays;class MyMethodInterceptor implements MethodInterceptor { @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("拦挡办法输入: You said: " + Arrays.toString(args)); return proxy.invokeSuper(obj, args); }}
应用 org.springframework.cglib.proxy.Enhancer 基于被代理类结构出代理对象
import org.springframework.cglib.proxy.Enhancer;public class TestMain { public static void main(String[] args) { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(HelloConcrete.class); enhancer.setCallback(new MyMethodInterceptor()); HelloConcrete hello = (HelloConcrete)enhancer.create(); System.out.println(hello.sayHello("I love you!")); }}
enhancer 对象的创立和应用跟后面 Proxy.newProxyInstance 的目标是一样的。
参考:
- java动静代理实现与原理详细分析:https://www.cnblogs.com/gonjan-blog/p/6685611.html
- Java Proxy和CGLIB动静代理原理:https://www.cnblogs.com/carpenterlee/p/8241042.html
本文由mdnice多平台公布