大厂高级工程师面试必问系列:Java动态代理机制和实现原理详解

  • 生成的代理类为public final,不能被继承

  • 类名的格式为:“$ProxyN”

  • N 是逐一递增的数字,代表Proxy是被第N次动态代理生成的代理类

  • 对于同一组接口,接口的排列顺序也相同,不会重复创建动态代理类,而是返回一个先前已经创建并缓存了的代理类对象,以此提高效率

synchronized (cache) {

/*

  • 不必担心获取到清除掉弱引用的缓存

  • 因为如果一个代理类已经被垃圾回收,代理类的类加载器也会被垃圾回收

  • 所以获取到的缓存都是加载到缓存中的映射

*/

do {

Object value = cache.get(key);

if (value instanceof Reference) {

proxyClass = (Class) ((Reference) value).get();

if (proxyClass != null) {

/*

  • 代理类已经生成,返回代理类

*/

return proxyClass;

} else if (value == pendingGenerationmarker) {

/*

  • 代理类正在生成,等待代理类生成

*/

try {

cache.wait();

} catch (InterruptedException e) {

/*

  • 等待生成的代理类有一个极小的限定的时间,因此可以忽略线程在这里的影响

*/

}

continue;

} else {

/*

  • 如果没有这个接口列表已经生成或者正在生成的代理类

  • 需要去生成这些接口的代理类,将这些接口标记为待生成

*/

cache.put(key, pendingGenerationMarker);

break;

}

}while (true);

}

  • 类继承关系:

imgProxy 类是父类,这个规则适用于所有由 Proxy 创建的动态代理类(这也导致Java动态代理的缺陷,由于Java不支持多继承,所以无法实现对 class 的动态代理,只能对于 Interface 进行代理),该类实现了所有代理的一组接口,所以 Proxy 类能够被安全地类型转换到其所代理的某接口

  • 代理类的根类 java.lang.Object 中的 hashCode(),equals()和().toString 方法同样会被分派到调用处理器 invoke 方法执行

Java动态代理测试


创建一个动态代理类

public class serviceProxy implements InvocationHandler {

private Object target;

/**

  • 绑定委托对象并返回一个代理对象

  • @param target 真实对象

  • @return 代理对象

*/

public Object bind(Object target, Class[] interfaces) {

this.target = target;

// 取得代理对象

return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);

}

/**

  • 通过代理对象调用方法首先进入这个方法

  • @param proxy 代理对象

  • @param Method 方法,被调用方法

  • @param args 方法的参数

*/

@Override

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

/*

  • JDK动态代理

*/

Object result = null;

// 反射方法前调用

System.err.println(“–反射方法前执行的方法–”);

// 反射执行方法,相当于调用target.xXX()

result = method.invoke(target, args);

// 反射方法后调用

System.err.println(“–反射方法后执行的方法–”);

return result;

}

}

  • bind方法:

  • bind方法中的newProxyInstance方法,就是生成一个代理对象

  • 第一个参数: 类加载器

  • 第二个参数: 真实委托对象所实现的接口. 代理对象挂在那个接口下

  • 第三个参数: this 代表当前 HelloServiceProxy 类, 也就是使用HelloServiceProxy作为对象的代理

  • invoke方法:

  • invoke方法有三个参数:

  • 第一个 proxy 是代理对象

  • 第二个是当前调用那个方法

  • 第三个是方法的参数

ProxyTest

public class ProxyTest {

public static void main(String[] args) {

HelloServiceProxy proxy = new HelloServiceProxy();

HelloService service = new HelloServiceImpl();

// 绑定代理对象

service = (HelloService) proxy.bind(service, new Class[] {HelloService.class});

service.sayHello(“user”);

}

}

  • 12
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值