java的动态代理

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

posted @ 2019-05-10 22:38  myLittleGarden  阅读(208)  评论(0编辑  收藏  举报