RPC框架手撕之路—java反射以及动态代理机制

在上一篇文章中,我们提到了,RPC框架所需要的java基础,第一点就是java的动态代理机制,动态代理机制的基础是反射,无论是在实际编程或者是面试时,都是java知识的重中之重。

定义:

在运行状态中,对于任意一个类,都能够知道这一个类的所有属性和方法,对于任意一个对象都能够通过反射机制调用一个类的任意方法,这种动态获取类信息以及动态调用类方法的功能称为java的反射机制。

作用:

1、动态的创建类的实例,将类绑定到现有对象中,或从现有对象中获取类型。 2、应用程序需要在运行时从某个特定的程序集中载入一个特定的类。

个人理解的反射机制就是,某些类在程序运行的一开始并没有加载,但是随着程序的运行,我们发现这些类也需要用到,此时就可以通过反射机制,来获取到类的属性和方法。

代理模式:

定义:

委托模式,是为某个对象提供一个代理对象,并且由代理对象控制对原对象的访问。代理模式通俗来讲就是我们生活中常见的中介。代理模式可以提供非常好的访问控制,应用比较广泛。

而其中的代理模式中的动态代理不仅在rpc远程访问中有重要的应用,同样在Spring AOP和其他应用中也起到了很重要的作用。

代理模式的通用类图:

Subject: 抽象主题角色:可以是抽象类,也可以是接口。抽象主题是一个普通的业务类型,无特殊要求。

RealSubject: 具体主题角色:也叫做被委托角色或被代理角色,是业务逻辑的具体执行者。

Proxy: 代理主题角色:也叫做委托类或代理类。它负责对真实角色的应用,把所有抽象主题类定义的方法限制委托给真实主题角色实现,并且在具体主题角色处理完毕前后做预处理和善后处理工作。

按照代理创建的时期来进行分类,可以分为动态代理和静态代理。

静态代理:

一个代理类只能实现一种抽象主题角色,在程序运行之前,代理类.class文件就已经被创建,代理类和委托类的关系在运行前就确定。

动态代理:

一个代理类通过反射机制,可以实现多种不类型的抽象主题角色。动态代理类的源码是在程序运行期间由JVM根据反射等机制动态的生成,所以不存在代理类的字节码文件。代理类和委托类的关系是在程序运行时确定。以下为动态代理概括图:

实现代码块如下:

抽象角色类实现(动态代理的抽象决策类只能使用接口):

public interface Subject {
    /**
     * 接口方法,抽象主题类
     */
    public void request();
}

具体决策类实现:

public class ConcreteSubject implements Subject{

    /**
     * 具体业务实现逻辑
     */
    @Override
    public void request() {
        //业务处理逻辑
        System.out.println("逻辑执行");
    }
}

动态创建代理对象的类(代理类,使用反射机制):

import lombok.extern.slf4j.Slf4j;

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


public class ProxyHandler implements InvocationHandler {
/**
*
* @param proxy
* @param method
* @param args
* @return
* @throws Throwable
*/

    /**
     *目标对象
     */
    private Object target;

    /**

     */

    public Object newProxyInstance(Object target){
       this.target = target;

       Object result = Proxy.newProxyInstance(target.getClass().getClassLoader(),
               target.getClass().getInterfaces(),this);

       return result;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //TODO原对象方法调用添加的预处理逻辑
        Object ret = null;
        try{
            //调用目标方法
            ret = method.invoke(target, args);
        }catch (Exception e){
            //log("调用{}.{}发生异常", target.getClass().getName(), method.getName(), e);
            throw e;
        }
        return ret;
    }
}

客户端类

import lombok.extern.slf4j.Slf4j;

import java.util.logging.Logger;


public class Client {
public static void main(String[] args){
System.out.println(“开始”);
ProxyHandler handler = new ProxyHandler();
Subject subject = (Subject) handler.newProxyInstance(new ConcreteSubject());
subject.request();
System.out.println(“结束”);
}
}

运行结果: