1. 什么是动态代理
代理模式是为了提供额外或不同的操作,而插入的用来替代”实际”对象的对象,这些操作涉及到与”实际”对象的通信,因此代理通常充当中间人角色。Java的动态代理比代理的思想更前进了一步,它可以动态地创建并代理并动态地处理对所代理方法的调用。在动态代理上所做的所有调用都会被重定向到单一的调用处理器上,它的工作是揭示调用的类型并确定相应的策略。
大道理上讲代理是一种软件设计模式,目的地希望能做到代码重用。具体上讲,代理这种设计模式是通过不直接访问被代理对象的方式,而访问被代理对象的方法。这个就好比 商户---->明星经纪人(代理)---->明星这种模式。我们可以不通过直接与明星对话的情况下,而通过明星经纪人(代理)与其产生间接对话。
2. 代理的使用场景
(1)设计模式中有一个设计原则是开闭原则,是说对修改关闭对扩展开放,我们在工作中有时会接手很多前人的代码,里面代码逻辑让人摸不着头脑(sometimes the code is really like shit),这时就很难去下手修改代码,那么这时我们就可以通过代理对类进行增强。
(2)我们在使用RPC框架的时候,框架本身并不能提前知道各个业务方要调用哪些接口的哪些方法 。那么这个时候,就可用通过动态代理的方式来建立一个中间人给客户端使用,也方便框架进行搭建逻辑,某种程度上也是客户端代码和框架松耦合的一种表现。
(3)Spring的AOP机制就是采用动态代理的机制来实现切面编程。Spring Aop学习总结
3. 代理分类
- 静态代理:静态代理是在编译时就将接口、实现类、代理类一股脑儿全部手动完成
- 动态代理:在程序运行期间根据需要动态的创建代理类及其实例,来完成具体的功能
4. 静态代理使用举例
我们先创建一个接口,java api代理机制求被代理类必须要实现某个接口,对于静态代理方式代理类也要实现和被代理类相同的接口。
public interface Person {
public void sayHello(String name);
public void interduce(String name, int age);
}
public class Student implements Person{
@Override
public void sayHello(String name) {
System.out.println("Student sayHello start");
System.out.println("Hello " + name);
System.out.println("Student sayHello end");
}
@Override
public void interduce(String name, int age){
System.out.println("Student interduce start");
System.out.println("My name is " + name + ". I'm " + age + " years old");
System.out.println("Student interduce end");
}
}
import java.lang.reflect.Proxy;
public class StaticProxyTest implements Person{
private Person person;
public StaticProxyTest(Person person){
this.person = person;
}
@Override
public void sayHello(String name){
System.out.println("Static Proxy Test sayHello begin");
person.sayHello(name);
System.out.println("Static Proxy Test sayHello end");
}
@Override
public void interduce(String name, int age){
System.out.println("Static Proxy Test interduce start");
person.interduce(name, age);
System.out.println("Static Proxy Test interduce end");
}
public static void main(String[] args){
Student student = new Student();
StaticProxyTest staticProxyTest = new StaticProxyTest(student);
staticProxyTest.sayHello("static proxy test");
staticProxyTest.interduce("static proxy test", 1);
}
}
5. 动态代理
在java的动态代理机制中,有两个重要的类或接口,一个是 InvocationHandler(Interface),另一个则是 Proxy(Class)。这一个类和接口是实现我们动态代理所必须用到的。
每一个动态代理类都必须要实现InvocationHandler这个接口,并且每个代理类的实例都关联到了一个handler,当我们通过代理对象调用一个方法的时候,这个方法的调用就会被转发为由InvocationHandler这个接口的 invoke 方法来进行调用。我们来看看InvocationHandler这个接口的唯一一个方法 invoke 方法:
Object invoke(Object proxy, Method method, Object[] args) throws Throwable
proxy: 指代我们所代理的那个真实对象
method: 指代的是我们所要调用真实对象的某个方法的Method对象
args: 指代的是调用真实对象某个方法时接受的参数
接下来我们来看看Proxy这个类,Proxy这个类的作用就是用来动态创建一个代理对象的类,它提供了许多的方法,但是我们用的最多的就是 newProxyInstance 这个方法:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
loader: 一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载
interfaces: 一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了
h: 一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上
动态代理举例:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class MyInvocationHandler implements InvocationHandler {
public Object object;
public MyInvocationHandler(Object object){
this.object = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable{
System.out.println("MyInvocationHandle proxy begins");
System.out.println("proxy: " + proxy.getClass().getName());
System.out.println("method: " + method.getName());
for(Object o : args) System.out.println("arg: " + o);
method.invoke(object, args);
System.out.println("MyInvocationHandle proxy ends");
return null;
}
public static void main(String[] args){
Student student = new Student();
MyInvocationHandler myInvocationHandler = new MyInvocationHandler(student);
Person proxyPerson = (Person) Proxy.newProxyInstance(student.getClass().getClassLoader(), student.getClass().getInterfaces(),
myInvocationHandler);
proxyPerson.sayHello("proxyPersonSayHello");
proxyPerson.interduce("proxyPersonInterduce", 1);
}
}
参考文档:
详解java动态代理机制以及使用场景:https://blog.csdn.net/u011784767/article/details/78281384
java动态代理作用及源码分析:https://www.jianshu.com/p/9d5ef621f2d1
java动态代理机制详解:https://www.cnblogs.com/xiaoluo501395377/p/3383130.html