在上一篇文章中,我们提到了,RPC框架所需要的java基础,第一点就是java的动态代理机制,动态代理机制的基础是反射,无论是在实际编程或者是面试时,都是java知识的重中之重。
java反射:
定义:
在运行状态中,对于任意一个类,都能够知道这一个类的所有属性和方法,对于任意一个对象都能够通过反射机制调用一个类的任意方法,这种动态获取类信息以及动态调用类方法的功能称为java的反射机制。
作用:
1、动态的创建类的实例,将类绑定到现有对象中,或从现有对象中获取类型。 2、应用程序需要在运行时从某个特定的程序集中载入一个特定的类。
个人理解的反射机制就是,某些类在程序运行的一开始并没有加载,但是随着程序的运行,我们发现这些类也需要用到,此时就可以通过反射机制,来获取到类的属性和方法。
代理模式:
定义:
委托模式,是为某个对象提供一个代理对象,并且由代理对象控制对原对象的访问。代理模式通俗来讲就是我们生活中常见的中介。代理模式可以提供非常好的访问控制,应用比较广泛。
而其中的代理模式中的动态代理不仅在rpc远程访问中有重要的应用,同样在Spring AOP和其他应用中也起到了很重要的作用。
代理模式的通用类图:

Subject: 抽象主题角色:可以是抽象类,也可以是接口。抽象主题是一个普通的业务类型,无特殊要求。
RealSubject: 具体主题角色:也叫做被委托角色或被代理角色,是业务逻辑的具体执行者。
Proxy: 代理主题角色:也叫做委托类或代理类。它负责对真实角色的应用,把所有抽象主题类定义的方法限制委托给真实主题角色实现,并且在具体主题角色处理完毕前后做预处理和善后处理工作。
按照代理创建的时期来进行分类,可以分为动态代理和静态代理。
静态代理:
一个代理类只能实现一种抽象主题角色,在程序运行之前,代理类.class文件就已经被创建,代理类和委托类的关系在运行前就确定。
动态代理:
一个代理类通过反射机制,可以实现多种不类型的抽象主题角色。动态代理类的源码是在程序运行期间由JVM根据反射等机制动态的生成,所以不存在代理类的字节码文件。代理类和委托类的关系是在程序运行时确定。以下为动态代理概括图:

实现代码块如下:
抽象角色类实现(动态代理的抽象决策类只能使用接口):
1public interface Subject { 2 /** 3 * 接口方法,抽象主题类 4 */ 5 public void request(); 6}
具体决策类实现:
1public class ConcreteSubject implements Subject{ 2 3 /** 4 * 具体业务实现逻辑 5 */ 6 @Override 7 public void request() { 8 //业务处理逻辑 9 System.out.println("逻辑执行"); 10 } 11}
动态创建代理对象的类(代理类,使用反射机制):
1import lombok.extern.slf4j.Slf4j; 2 3import java.lang.reflect.InvocationHandler; 4import java.lang.reflect.Method; 5import java.lang.reflect.Proxy; 6 7 8public class ProxyHandler implements InvocationHandler { 9 /** 10 * 11 * @param proxy 12 * @param method 13 * @param args 14 * @return 15 * @throws Throwable 16 */ 17 18 /** 19 *目标对象 20 */ 21 private Object target; 22 23 /** 24 25 */ 26 27 public Object newProxyInstance(Object target){ 28 this.target = target; 29 30 Object result = Proxy.newProxyInstance(target.getClass().getClassLoader(), 31 target.getClass().getInterfaces(),this); 32 33 return result; 34 } 35 36 @Override 37 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 38 //TODO原对象方法调用添加的预处理逻辑 39 Object ret = null; 40 try{ 41 //调用目标方法 42 ret = method.invoke(target, args); 43 }catch (Exception e){ 44 //log("调用{}.{}发生异常", target.getClass().getName(), method.getName(), e); 45 throw e; 46 } 47 return ret; 48 } 49}
客户端类:
1import lombok.extern.slf4j.Slf4j; 2 3import java.util.logging.Logger; 4 5 6public class Client { 7 public static void main(String[] args){ 8 System.out.println("开始"); 9 ProxyHandler handler = new ProxyHandler(); 10 Subject subject = (Subject) handler.newProxyInstance(new ConcreteSubject()); 11 subject.request(); 12 System.out.println("结束"); 13 } 14} 15
运行结果:
