中流砥柱java的动态代理

2020-08-26 14:45:14 浏览数 (1)

背景

在我们学习Spring框架的时候我们是否思考过,Spring是如何实现bean实列注入到IOC容器中呢?我们如何去

权威指南

代理是基本的设计模式之一,他是为了提供额外的或不同的操作,而插入的用来代替“实际”对象的对象。这些操作通常涉及与“实际”对象的通信,因此代理通常充当着中间人的角色。 Java的动态代理比代理的思想更迈进了一步,因为他可以动态地创建代理并动态的处理对所代理的方法的调用。在动态代理上所做的所有调用都会被重定向到单一的调用处理器上,他的工作是揭示调用的类型并确定相应的对策。 -------《ThinKing in Java》

个人理解

  • 类比生活 代理,平时生活中代理无处不在,如手机生产商的代理商A,A不仅能帮忙给生产商卖手机而且也提供了售后功能。代码中被代理对象就是生产商,而代理商A就是代理对象,可以做生产商的事情,为了方便客户还提供了售后的功能。但是此时这个生产商不固定,且随时会变,且为了利益最大化,那个生产商拿货便宜,就拿谁的货,就在这个时候我们是不是就得成为一个动态代理商?这样就可以方便用户,还能和生产商解耦合。
  • 抽象层面 将一个对象被另一个对象代理,代理对象可以扩展被代理对象的方法,且能在被代理对象对象增加方法。这样实现好之后我们所代理的对象会在编译和累加载之后将带代理对象和被代理对象绑定到一块了。为了让代理更加方便和实用于是就得出了动态代理,也就是再程序运行时可以根据被代理对象生成代理对象。(在java中反射机制就是可以让代码进行动态加载和生成对象)

jdk动态代理

  1. JDK的动态代理也就是基于Java的反射机制实现的。
  2. 我们先来看一下Java中的动态代理在代码中是如何实现的:
代码语言:javascript复制
package dynamicproxy;

import java.lang.reflect.*;

/**
 * @Author:yuanxindong
 * @Date:2020/5/90:53
 */
public class Client {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {

        //实例化一个对象
        //分别分为两种方事实现的,一个是直接new 关键字创建一个对象,
        // 第二种是通过反射机制穿件一个对象
        //UserServiceImpl userServiceLmpl = new UserServiceImpl();
        //1。 读取加载"dynamicproxy.UserServiceImpl"路径下的class对象
        Class aClass = Class.forName("dynamicproxy.UserServiceImpl");

        //使用class对象中的方法获取父类加载器
        //ClassLoader classLoader = userServiceLmpl.getClass().getClassLoader();
        ClassLoader classLoader = aClass.getClassLoader();
        //Class []  interfaces = userServiceLmpl.getClass().getInterfaces();
        //获取实现class实现的接口
        Class[] interfaces = aClass.getInterfaces();

        //获取这个类的、构造方法
        Constructor constructors = aClass.getConstructor();
        //通过构造方法 去实例化这个对象
        UserServiceImpl userServiceLmpl = (UserServiceImpl) constructors.newInstance();
        //将获取到的对象传入对应的处理器上,通过反射的方式拿到对应的方法切织入
        InvocationHandler logHandler = new LogHandler(userServiceLmpl);
        //创建动态代理对象的接口
        UserService proxy = (UserService) Proxy.newProxyInstance(classLoader, interfaces, logHandler);

        proxy.select();
        proxy.update();
        ProxyUtils.generateClassFile(userServiceLmpl.getClass(), "UserServiceProxy");

    }
}

被代理的对象

代码语言:javascript复制
/**
 * @Author:yuanxindong
 * @Date:2020/5/90:56
 */
public interface UserService {
    public void select();
    public void update();
}
代码语言:javascript复制
package dynamicproxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

/**
 * @Author:yuanxindong
 * @Date:2020/5/90:47
 */
public class LogHandler  implements InvocationHandler {
    private Object  target;
    //使用构造方法将代理对象传入代理对象
    public LogHandler(Object target){
        this.target = target;
    }

    //通过反射的方式执行并织入(不知道用的是否合理)代理方法,这个接口实现方法会被newProxyInstance()方法使用
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        before();
        //
        Object  result  = method.invoke(target,args);
        after();
        return result;
    }
    private void before(){
        System.out.println("log start"  System.currentTimeMillis());
    }

    private  void after(){
        System.out.println("log end"   System.currentTimeMillis());
    }

}

执行结果:

demo中的InvocationHandler

  1. 从demo中看我们将代理对象的其他方法是在实现InvocationHandler的类中写的,通过实现的invoke()方法将被代理类织入代理类的方法中 然后在newProxyInstance()方法中实例化这个 invoke()方法成为代理对象。如下面的源码所示:

总结

jdk的动态代理通过Java反射机制实现 主要的方法是:

  • 实现被代理的方法:继承InvocationHandler接口 实现其invoke方法
代码语言:javascript复制
InvocationHandler logHandler = new LogHandler(userServiceLmpl);
  • 使用Proxy.newProxyInstance(classLoader, interfaces, logHandler),创建代理对象。
代码语言:javascript复制
        UserService proxy = (UserService) Proxy.newProxyInstance(classLoader, interfaces, logHandler);

思考

  • Spring AOP是怎样实现的呢?? 也是像我们上面的方法那样织入的吗???

0 人点赞