JDK动态代理案例实现:实现 InvocationHandler 接口重写 invoke 方法,其中包含一个对象变量和提供一个包含对象的构造方法;

public class MyInvocationHandler implements InvocationHandler {
Object target;//目标对象
public MyInvocationHandler(Object target){
this.target=target;
}
/**
* @param proxy 代理对象
* @param method 目标对象的目标方法
* @param args 目标方法的参数
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("log");
return method.invoke(target,args);
}
}
public class MyInvocationHandlerTest {
public static void main(String[] args) {
//参数: 当前类的classLoader(保证MyInvocationHandlerTest当前类可用)
// 接口数组:通过接口反射得到接口里面的方法,对接口里面的所有方法都进行代理
// 实现的InvocationHandler:参数是目标对象
UserDao jdkproxy = (UserDao) Proxy.newProxyInstance(MyInvocationHandlerTest.class.getClassLoader(),
new Class[]{UserDao.class},new MyInvocationHandler(new UserService()));
jdkproxy.query("query");
//-----结果------
//log
//query
}
}

  接下来查看 Proxy.newProxyInstance 源码探究它的实现过程:  

    public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
//检查InvocationHandler是否为空,为空抛出空指针异常
Objects.requireNonNull(h);
//克隆拿到接口
final Class<?>[] intfs = interfaces.clone();
//进行安全校验
final SecurityManager sm = System.getSecurityManager();
//检查是否能被代理
if (sm != null) {
checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
} /*
* Look up or generate the designated proxy class.
* 得到代理类
*/
Class<?> cl = getProxyClass0(loader, intfs); /*
* Invoke its constructor with the designated invocation handler.
*/
try {
if (sm != null) {
checkNewProxyPermission(Reflection.getCallerClass(), cl);
}
//通过构造方法得到代理类的对象
final Constructor<?> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
if (!Modifier.isPublic(cl.getModifiers())) {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
cons.setAccessible(true);
return null;
}
});
}
//new得到代理对象
return cons.newInstance(new Object[]{h});
} catch (IllegalAccessException|InstantiationException e) {
throw new InternalError(e.toString(), e);
} catch (InvocationTargetException e) {
Throwable t = e.getCause();
if (t instanceof RuntimeException) {
throw (RuntimeException) t;
} else {
throw new InternalError(t.toString(), t);
}
} catch (NoSuchMethodException e) {
throw new InternalError(e.toString(), e);
}
}

  从上面可以看出 Class<?> cl = getProxyClass0(loader, intfs); 这行代码最重要,它可以得到一个代理对象,下面是 Proxy#getProxyClass0 的源码

    private static Class<?> getProxyClass0(ClassLoader loader,
Class<?>... interfaces) {
if (interfaces.length > 65535) {
throw new IllegalArgumentException("interface limit exceeded");
} // If the proxy class defined by the given loader implementing
// the given interfaces exists, this will simply return the cached copy;
// otherwise, it will create the proxy class via the ProxyClassFactory
    //如果接口的代理类已经存在缓存中了,直接从缓存中取出来返回,如果不存在则通过ProxyClassFactory创建一个并放入缓存中供下次使用 
return proxyClassCache.get(loader, interfaces);
}

  proxyClassCache.get() 的实现在 WeakCache#get() 中:

    public V get(K key, P parameter) {
Objects.requireNonNull(parameter); expungeStaleEntries();
//从缓存中取出代理类的key值,因为代理类的生成需要耗时间和性能,所有缓存起来方便下次直接使用
Object cacheKey = CacheKey.valueOf(key, refQueue); // lazily install the 2nd level valuesMap for the particular cacheKey
ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);
if (valuesMap == null) {
ConcurrentMap<Object, Supplier<V>> oldValuesMap
= map.putIfAbsent(cacheKey,
valuesMap = new ConcurrentHashMap<>());
if (oldValuesMap != null) {
valuesMap = oldValuesMap;
}
} // create subKey and retrieve the possible Supplier<V> stored by that
// subKey from valuesMap 获取到接口信息
Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
Supplier<V> supplier = valuesMap.get(subKey);
Factory factory = null;
//开始进来supplier是null,所以执行后面的代码创建一个Factory然后赋值给supplier
while (true) {
if (supplier != null) {
// supplier might be a Factory or a CacheValue<V> instance
//获取到代理类
V value = supplier.get();
if (value != null) {
//返回代理类
return value;
}
}
// else no supplier in cache
// or a supplier that returned null (could be a cleared CacheValue
// or a Factory that wasn't successful in installing the CacheValue) // lazily construct a Factory
if (factory == null) {
factory = new Factory(key, parameter, subKey, valuesMap);//通过接口信息和classLoader创建一个工厂
} if (supplier == null) {
supplier = valuesMap.putIfAbsent(subKey, factory);
if (supplier == null) {
// successfully installed Factory
supplier = factory;
}
// else retry with winning supplier
} else {
if (valuesMap.replace(subKey, supplier, factory)) {
// successfully replaced
// cleared CacheEntry / unsuccessful Factory
// with our Factory
supplier = factory;//将工厂赋值给supplier
} else {
// retry with current supplier
supplier = valuesMap.get(subKey);
}
}
}
}

  下面查看 supplier.get():WeakCache.Factory#get()

        public synchronized V get() { // serialize access
// re-check
Supplier<V> supplier = valuesMap.get(subKey);
if (supplier != this) {
// something changed while we were waiting:
// might be that we were replaced by a CacheValue
// or were removed because of failure ->
// return null to signal WeakCache.get() to retry
// the loop
return null;
}
// else still us (supplier == this) // create new value
V value = null;
try {
//创建获取到value
value = Objects.requireNonNull(valueFactory.apply(key, parameter));
} finally {
if (value == null) { // remove us on failure
valuesMap.remove(subKey, this);
}
}
// the only path to reach here is with non-null value
assert value != null; // wrap value with CacheValue (WeakReference)
CacheValue<V> cacheValue = new CacheValue<>(value);//根据代理类创建一个缓存对象 // put into reverseMap
reverseMap.put(cacheValue, Boolean.TRUE);//将代理放入缓存中 // try replacing us with CacheValue (this should always succeed)
if (!valuesMap.replace(subKey, this, cacheValue)) {
throw new AssertionError("Should not reach here");
} // successfully replaced us with new CacheValue -> return the value
// wrapped by it
return value;
}

  接下来查看 Objects.requireNonNull() 中的 apply方法:Proxy.ProxyClassFactory#apply()

        public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
//获取到所有实现接口
Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
//遍历所有接口
for (Class<?> intf : interfaces) {
/*
* Verify that the class loader resolves the name of this
* interface to the same Class object.
*/
Class<?> interfaceClass = null;
try {
//对接口再次装载,相当classLoader.loadClass
interfaceClass = Class.forName(intf.getName(), false, loader);
} catch (ClassNotFoundException e) {
}
//判断两个接口是不是同一个接口(同一个类加载器加载的):判断对象是否是同一个
if (interfaceClass != intf) {
throw new IllegalArgumentException(
intf + " is not visible from class loader");
}
/*
* Verify that the Class object actually represents an
* interface.
*/
if (!interfaceClass.isInterface()) {
throw new IllegalArgumentException(
interfaceClass.getName() + " is not an interface");
}
/*
* Verify that this interface is not a duplicate.
*/
if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
throw new IllegalArgumentException(
"repeated interface: " + interfaceClass.getName());
}
}
//代理对象的包名
String proxyPkg = null; // package to define proxy class in
int accessFlags = Modifier.PUBLIC | Modifier.FINAL; /*
* Record the package of a non-public proxy interface so that the
* proxy class will be defined in the same package. Verify that
* all non-public proxy interfaces are in the same package.
*/
for (Class<?> intf : interfaces) {
int flags = intf.getModifiers();
//判断接口的类型是否是public,如果不是public,将代理类放到目标对象同一目录下
if (!Modifier.isPublic(flags)) {
accessFlags = Modifier.FINAL;
String name = intf.getName();
int n = name.lastIndexOf('.');
String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
if (proxyPkg == null) {
proxyPkg = pkg;
} else if (!pkg.equals(proxyPkg)) {
throw new IllegalArgumentException(
"non-public interfaces from different packages");
}
}
} if (proxyPkg == null) {
// if no non-public proxy interfaces, use com.sun.proxy package
//默认定义包名
//public static final String PROXY_PACKAGE = "com.sun.proxy";
proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
} /*
* Choose a name for the proxy class to generate.
*/
long num = nextUniqueNumber.getAndIncrement();
//标识:private static final String proxyClassNamePrefix = "$Proxy";
//随机数(防止多线程测试相同的类名):long num = nextUniqueNumber.getAndIncrement();
//代理类的名字:代理包名+ 标识+ 随机数
String proxyName = proxyPkg + proxyClassNamePrefix + num; /*
* Generate the specified proxy class.
* 产生指定的代理类信息,是二进制信息,可以使用IO流输出代理类的Java文件(可查看前文有介绍)
* ProxyGenerator.generateProxyClass()是一个静态方法,所以可以外部直接调用
*/
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces, accessFlags);
try {
//产生代理类,返回一个class:将byte字节码转换成class
//defineClass0是一个native方法,由JVM实现的:private static native Class<?> defineClass0();
return defineClass0(loader, proxyName,
proxyClassFile, 0, proxyClassFile.length);
} catch (ClassFormatError e) {
/*
* A ClassFormatError here means that (barring bugs in the
* proxy class generation code) there was some other
* invalid aspect of the arguments supplied to the proxy
* class creation (such as virtual machine limitations
* exceeded).
*/
throw new IllegalArgumentException(e.toString());
}
}

Proxy.newProxyInstance源码探究的更多相关文章

  1. Vue源码探究-全局API

    Vue源码探究-全局API 本篇代码位于vue/src/core/global-api/ Vue暴露了一些全局API来强化功能开发,API的使用示例官网上都有说明,无需多言.这里主要来看一下全局API ...

  2. Vue源码探究-状态初始化

    Vue源码探究-状态初始化 Vue源码探究-源码文件组织 Vue源码探究-虚拟DOM的渲染 本篇代码位于vue/src/core/instance/state.js 继续随着核心类的初始化展开探索其他 ...

  3. spring-cloud-sleuth+zipkin源码探究

    1. spring-cloud-sleuth+zipkin源码探究 1.1. 前言   粗略看了下spring cloud sleuth core源码,发现内容真的有点多,它支持了很多类型的链路追踪, ...

  4. spring-boot-2.0.3之quartz集成,数据源问题,源码探究

    前言 开心一刻 着火了,他报警说:119吗,我家发生火灾了. 119问:在哪里? 他说:在我家. 119问:具体点. 他说:在我家的厨房里. 119问:我说你现在的位置. 他说:我趴在桌子底下. 11 ...

  5. Vue源码探究-事件系统

    Vue源码探究-事件系统 本篇代码位于vue/src/core/instance/events.js 紧跟着生命周期之后的就是继续初始化事件相关的属性和方法.整个事件系统的代码相对其他模块来说非常简短 ...

  6. Vue源码探究-源码文件组织

    Vue源码探究-源码文件组织 源码探究基于最新开发分支,当前发布版本为v2.5.17-beta.0 Vue 2.0版本的大整改不仅在于使用功能上的优化和调整,整个代码库也发生了天翻地覆的重组.可见随着 ...

  7. SpringBoot读取配置文件源码探究

    1. SpringBoot读取配置文件源码探究 1.1. 概览 springboot的源码是再原来的Spring源码上又包了一层,看过spring源码都知道,当我们从入口debug进去的时候,原来的S ...

  8. @Async源码探究

    1. @Async源码探究 1.1. 上代码 @SpringBootApplication @EnableAsync public class SpringbootLearnApplication { ...

  9. Sharding-Jdbc源码探究-读写分离

    1. Sharding-Jdbc源码探究-读写分离 1.1. 主入口 找到源码入口 这一个类围绕了springboot配置属性的加载,加载了spring.shardingsphere.datasour ...

随机推荐

  1. Android获取OneNET云平台数据

    尝试HttpURLConnection "get"方式获取了www.baidu.com的数据后,试着获取OneNET云平台的设备数据(设备数据已成功上传至云平台) .java文件 ...

  2. JS遍历对象的属性和值

    对于需要动态获取对象的某些属性和对应的值的时候,就需要遍历对象的属性和值. const user = { name: '张三', age: 20, addr: '湖北武汉', sex: '男' } / ...

  3. 视频+图文串讲:MySQL 行锁、间隙锁、Next-Key-Lock、以及实现记录存在的话就更新,如果记录不存在的话就插入如何保证并发安全

    导读 Hi,大家好!我是白日梦!本文是MySQL专题的第 27 篇. 下文还是白日梦以自导自演的方式,围绕"如何实现记录存在的话就更新,如果记录不存在的话就插入."展开本话题.看看 ...

  4. 看完我的笔记不懂也会懂----MarkDown使用指南

    目录 语法 [TOC] 自动生成目录 1. 标题 2. 文本强调 3. 列表 4. 图片 5. 超链接 6. 文本引用 7. 分割线 8. 代码 9. 任务列表 (MPE专属) 10. 表格 11. ...

  5. 京东 Vue3 组件库闪亮登场

    京东零售开源项目 NutUI 是一套京东风格的轻量级移动端 Vue 组件库,是开发和服务于移动 Web 界面的企业级产品.经过长时间的开发与打磨,NutUI 3.0 终于要和大家见面了!3.0 版本在 ...

  6. 详解JavaScript中的原型

    前言 原型.原型链应该是被大多数前端er说烂的词,但是应该还有很多人不能完整的解释这两个内容,当然也包括我自己. 最早一篇原型链文章写于2019年07月,那个时候也是费了老大劲才理解到了七八成,到现在 ...

  7. Mybatis(一):手写一套持久层框架

    作者 : 潘潘 未来半年,有幸与导师们一起学习交流,趁这个机会,把所学所感记录下来. 「封面图」 自毕业以后,自己先创业后上班,浮沉了近8年,内心着实焦躁,虽一直是走科班路线,但在技术道路上却始终没静 ...

  8. AI换脸

    AI换脸 技术 调用到百度的AI接口,layui的图片上传,栅格化布局 核心代码 纯py文件运行 # encoding:utf-8 import requests import base64 impo ...

  9. 十一. SpringCloud Alibaba

    1. SpringCloud Alibaba简介 1.1 为什么会出现SpringCloud Alibaba Spring Cloud Netflix项目进入到维护模式 什么是维护模式?=> 将 ...

  10. U盘重装系统:手把手教你怎么使用U盘重装系统、清除登录密码

    前言 之前讲过<不懂电脑也能自己重装系统,可视化傻瓜式一键重装系统不求人!!!>,这是针对可以正常开机的情况下直接使用浏览器功能重装系统, 那不能正常开机或者忘记密码的怎么办呢? 不慌,今 ...