首页 文章 精选 留言 我的

精选列表

搜索[智慧轨交],共8980篇文章
优秀的个人博客,低调大师

银河麒麟赋能北京新基建

“我算了算,通勤时间来回能节省一小时!” 7月1日,北京市郊铁路城市副中心线西段整体提升工程(北京西至良乡段)正式开通试运营。线路全长31.5公里,设站5座,实现30分钟内可达,有效缓解房山良乡至北京西站通勤段出行压力。不少通勤族表示,坐着小火车上班不仅通勤时间缩短,还节省了体力。 在这一推动“四网融合”战略落地的重大民生工程中,银河麒麟工业操作系统作为全线多制式融合检票闸机的底层操作系统,为自动售检票系统的安全稳定运行保驾护航。 一、打通国铁与地铁间的“最后一公里” 长期以来,国铁与城市轨道交通分属两套票务体系,乘客换乘时需面对不同的闸机通道和票务载体,通行效率与出行体验均受影响。 作为北京市与国铁集团联合批复的首个市郊铁路改造提升项目,此次全线部署多制式融合检票闸机,同时支持市郊铁路一卡通、手机一卡通、地铁乘车码、身份证、铁路e卡通五种票务方式,首次成体系实现了铁路检票系统与城市轨道交通AFC系统的互联互通。 乘客持任意票务凭证,均可通过同一闸机快速通行,曾经“各刷各闸”的区隔被彻底打破。车站空间得以集约利用,换乘效率显著提升,“四网融合”战略真正从规划蓝图落地为乘客可感知的出行体验。 乘客在房山东站过闸机进站乘车 二、银河麒麟工业操作系统为闸机运行保驾护航 银河麒麟工业操作系统作为多制式融合检票闸机底层支撑,面临多重考验。 首先,闸机作为乘客进出站的第一道关口,承担着票务核验、身份比对、数据回传等关键任务。 其次,市郊铁路通勤客流潮汐特征明显,早晚高峰时段闸机需在极短时间内完成核验并放行,任何卡顿或故障都将直接影响早高峰数万人次的通行效率。 同时,多制式票务融合意味着闸机需同时稳定对接国铁与城轨两套后台系统,对底层操作系统的安全性和稳定性提出了极高要求。 银河麒麟工业操作系统部署于全线闸机设备,面向轨道交通场景深度优化,具备高等级信息安全能力,从内核到应用构建了全方位安全防护体系,为每一笔票务交易的准确性和乘客数据的安全性提供了有力支撑。凭借轻量化系统架构和高效的处理能力,系统在闸机有限的算力环境下始终保持流畅运行,确保检票指令快速执行、数据高效同步。 联调联试阶段,系统在极限客流压力测试中始终保持稳定,有力保障了全线5座车站闸机按期高质量交付! 三、一条新线改变一座城的通勤节奏 副中心线西段的开通,为西南区域与中心城区之间搭建起一条稳定高效的通勤快速通道。早高峰少一次排队,晚高峰早一刻到家,对每日往返的数十万通勤者而言,是实实在在的生活质量提升。与此同时,线路的开通也为首都“一核一主一副”城市空间结构提供了有力的交通支撑。此次全线部署,是银河麒麟操作系统在北京市郊铁路领域的首次落地实践,标志着国产操作系统在轨道交通关键基础设施领域再次迈出坚实一步。 不止于市郊铁路,银河麒麟操作系统已在北京、深圳、上海、天津、贵阳等城市地铁线路,以及全国多条高速公路、干线铁路等关键交通场景中实现规模部署,持续为我国交通运输行业数字化转型提供稳定可靠的国产数字底座。麒麟软件将继续深耕交通关键场景,以更成熟的产品和更优质的服务,助力交通强国建设行稳致远。

优秀的个人博客,低调大师

现在买5G手机,就是智商税?

云栖号资讯:【点击查看更多行业资讯】在这里您可以找到不同行业的第一手的上云资讯,还在等什么,快来! 编者按:本文来自微信公众号“雷科技”(ID:leitech),作者 雷科技,36氪经授权发布。 说起来也是有趣,作为一个数码机构的编辑,即使我已经写过多篇关于5G技术的文章,也评测过多台5G手机,但我到现在为止都没买过任何一台5G手机。是的,即使5G手机已经来到了两千出头的价位,我用着的还是被誉为“智商检测机”的iPhone XR与 “最强4G Android手机”一加7 Pro。 除此之外,在昨天iPhone SE的评测中,也有不少读者反馈说“两千多买台5G手机不香吗?”看来大家对“2020年买4G手机”依然有些无法释怀,所以借着今天的机会,我决定跟大家聊聊为什么我不选择5G手机。对于正在使用5G手机的读者来说,你们可以把当成“一个固执的4G老古董”,但要搞清楚,我说的只是我对5G的个人看法,并不代表其他人的观点。 我觉得5G还不是时候 先说最主要的原因,那就是目前还没有什么事情必须用5G才能做到。举个例子,我以前评测5G手机想体现5G网速时,不外乎就是测速和下载电影。很多人看着都觉得很单调,没办法,5G真的就是这么单调。而且我们平常生活中不会闲着无聊测个速,所以剩下使用方式也就只有下载电影了。 但问题是,我为什么要花个几十秒下载一部电影到手机上看呢? 记得应该是大学的时候,我换上了联通刚刚推出冰激凌套餐。从那时开始,我就再也没有主动在手机上下载任何影音内容,无论电视剧、电影还是音乐,我通通在线观看。而事实证明,即使在线观看Netflix的高清视频,4G的网速也不成任何问题。要知道Netflix高清视频的码率已经超过不少国内视频网站的“HDR”画质了。然而即使在手机上任意拖动进度条,4G的网速也足以支持视频流畅播放了。 虽然我们已经开始铺设5G网络,但必须依托5G才能实现的内容尚未出现,所以就现阶段而言,即使5G资费再怎么降,5G网络对我都没有吸引力。 5G重走了VR的路 不管5G网络再怎么快,只要没有5G专属内容,那这个5G对我来说只是一个更快的4G网络而已。我知道有人会提“5G物联网”、“5G远程医疗”等例子,可如果大家稍作搜索,不难发现这些物联网、远程医疗、远程教学的例子早在4G,甚至是3G时代就有人提到过。而且考虑到能耗,不少物联网设备使用的还是3G甚至是2G网络。 在我看来,现在的5G就像是两年前的VR设备:它们都有不错的硬件,但只有硬件基础不足以让用户为之买单。当时的VR应用几乎都是手机游戏的“VR”版,至于那些“360度环绕看图”的软件,本质上和5G测速软件没什么差。直到像Beat Saber这样的VR专属游戏大作多起来后,VR的接受程度才逐渐提升。 话题回到5G身上。我长期使用过的5G手机不多不少,正好一只手指数得过来。可无论哪台手机,在我手上的表现都跟4G手机差不多——发热与续航时间甚至还不如4G手机。 在这里我无意贬低任何5G手机品牌,我也非常感谢他们愿意推动我国5G事业的建设与发展。但至少就我个人而言,5G的体现真的不明显。由于运营商理念不同,我们的3G与4G建设都落后于不少发达国家,因此当我们用上3G、4G手机时,我们能马上感受到两者之间的差距。 比如我读初中时,手机只能使用2G网络,上课看球只能选择“文字直播”;高中后手机支持3G了,勉强可以看看图片直播了;大学时开始使用4G手机,也看上了视频直播。 但我国的5G建设进度远远领先其他国家,所以在5G网络上,我们不能再像以前那样“前人栽树‘后人乘凉”了,我们必须自己开发5G的使用场景。但就现在的状况来看,5G的使用场景跟4G时代似乎没什么差。正因如此,在我看来2020年选购4G手机,其实并不是什么大问题。适合自己的才是最好的,只要自己觉得好用,那就可以了。 体验不升反降 而且作为一个数码机构的编辑,我们换手机的速度远远超过普通用户,即使是去年最新最热的iPhone 11 Pro,一年后也会被更新款的手机代替。 相信大家身边或多或少也有这样“高频换机”的用户。对于这些用户来说,他们不需要考虑“这款手机”以后好不好用。等5G真的出现了杀手级使用场景,到时候再买一台新的就好了。反正到时候都要换新,何必现在就跟风上5G?况且5G的能耗与发热都不尽人意,更成熟的4G难道不是更好的选择? 那么总结一下我的观点,在我看来,跑分测速并不属于日常使用的一部分。因此5G对于我、以及不少坚持4G的用户来说,不能带来可察觉的提升。所以就现阶段来看,5G手机对我的吸引力还不如iOS严格的权限管理。因此即便我还用着一年前的iPhone XR与一加7 Pro,但我依然没有动力买5G手机。 当然了,5G也不是没有5G的好处。现阶段5G网络的资源相当充裕,因此不容易出现基站繁忙导致的数据拥挤。 抢先体验5G网络在资费上也有一定折扣,甚至不少高端旗舰手机都只推出5G版本。选择5G与否不分对错,5G还是4G看的也只是哪个更适合自己。所以希望大家在选购5G手机前先问自己一个问题;“5G能给我带来什么?” 至于未来5G网络会出现什么“杀手级”应用,继文字、图片与视频后数字内容又能以什么新形态展现在我们面前,就让我们拭目以待吧。 【云栖号在线课堂】每天都有产品技术专家分享!课程地址:https://yqh.aliyun.com/live 立即加入社群,与专家面对面,及时了解课程最新动态!【云栖号在线课堂 社群】https://c.tb.cn/F3.Z8gvnK 原文发布时间:2020-04-26本文作者:雷科技 本文来自:“36Kr”,了解相关信息可以关注“36Kr”

优秀的个人博客,低调大师

java jdk代理,手把手你写java代理

一:常用的java代理模式 一般经常做java开发的知道java的代理模式一共有三种,第一种也就是静态代理,这种用法比较简单,没有什么魔法棒,比较好理解,另外两种分别是JDK代理和cglib代理,他们分别是对接口代理和对class类本身进行代理,jdk代理要求类必须实现有一个或者多个接口,对接口进行字节码增强在内存中实现新的class类去反射调用用户target的实现类,这里需要说明的是不管是cglic代理也好还是jdk代理他们在内存中都要占据方法区资源(jdk8 叫原空间),从而达到代理目的,而cglib代理是对class类本身进行字节码增强配合fastclass来实现代理,关于更多的cglib和jdk代理相关的内容大家可以google搜索一下,网上有很多这里不做再多的说明。下面我们摒弃jdk,和cglib的复杂源码来自己实现一个代理模式,来更深刻的了解一下代理究竟是怎么形成的。 二:java原生jdk代理demo和源码分析 代理模式是指给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。通俗的来讲代理模式就是我们生活中常见的中介。这种模式有什么用呢?它可以在原对象的基础上增强原对象的功能,比如在原对象调用一个方法的前后进行日志、事务操作等。Spring AOP就使用了代理模式。如何实现代理模式呢?首先来看静态代理。静态代理是指在程序运行前就已经存在的编译好的代理类是为静态代理。实现静态代理有四个步骤: ①定义业务接口; ②被代理类实现业务接口; ③定义代理类并实现业务接口; ④最后便可通过客户端进行调用。(这里可以理解成程序的main方法里的内容) 我们按照这个步骤去实现静态代理。需求:在向数据库添加一个用户时前后打印日志。 JDK DEMO示例 IUserService.java public interface IUserService { void add(String name); } UserServiceImpl.java public class UserServiceImpl implements IUserService{ @Override public void add(String name) { System.out.println("数据库中插入: "+name+" 的用户"); } } MyInvocationHandler.java public class MyInvocationHandler implements InvocationHandler { //被代理对象,Object类型 private Object target; public MyInvocationHandler(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("准备向数据库中插入数据"); Object returnvalue = method.invoke(target, args); System.out.println("插入数据库成功"); return returnvalue; } } 测试类 public static void main(String[] args) { IUserService target = new UserServiceImpl(); MyInvocationHandler handler = new MyInvocationHandler(target); IUserService proxyObject = (IUserService) Proxy.newProxyInstance(DynamicProxyTest.class.getClassLoader(), target.getClass().getInterfaces(), handler); proxyObject.add("张玉龙"); } 使用上非常简单、网上demo也很多,不做充分讲解,对jdk代理用法的小伙伴如果还不熟悉这块代码,就先了解一下jdk代理的使用方式,然后在回来继续看下面的源码分析 JDK代理源码深度分析 这部分如果想要更快更好的理解,建议一边对着源码(本文JDK 1.8),一边看着博客。毕竟自己亲身实践效果才好嘛。 Proxy.newProxyInstance( ClassLoaderloader, Class[] interfaces, InvocationHandler h) 产生了代理对象,所以我们进到 newProxyInstance 的实现: public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException { 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; } }); } 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); } } 这段代码核心就是通过 getProxyClass0(loader, intfs)得到代理类的Class对象,然后通过Class对象得到构造方法,进而创建代理对象。下一步看 getProxyClass0这个方法。 //此方法也是Proxy类下的方法 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 //意思是:如果代理类被指定的类加载器loader定义了,并实现了给定的接口interfaces, //那么就返回缓存的代理类对象,否则使用ProxyClassFactory创建代理类。 return proxyClassCache.get(loader, interfaces); } 这里看到proxyClassCache,有Cache便知道是缓存的意思,正好呼应了前面Look up or generate the designated proxy class。查询(在缓存中已经有)或生成指定的代理类的class对象这段注释。 proxyClassCache是个WeakCache类的对象,调用proxyClassCache.get(loader, interfaces); 可以得到缓存的代理类或创建代理类(没有缓存的情况)。说明WeakCache中有 get这个方法。先看下WeakCache类的定义(这里先只给出变量的定义和构造函数): //K代表key的类型,P代表参数的类型,V代表value的类型。 // WeakCache<ClassLoader, Class<?>[], Class<?>> proxyClassCache 说明proxyClassCache存的值是Class<?>对象,正是我们需要的代理类对象。 final class WeakCache<K, P, V> { private final ReferenceQueue<K> refQueue = new ReferenceQueue<>(); // the key type is Object for supporting null key private final ConcurrentMap<Object, ConcurrentMap<Object, Supplier<V>>> map = new ConcurrentHashMap<>(); private final ConcurrentMap<Supplier<V>, Boolean> reverseMap = new ConcurrentHashMap<>(); private final BiFunction<K, P, ?> subKeyFactory; private final BiFunction<K, P, V> valueFactory; public WeakCache(BiFunction<K, P, ?> subKeyFactory, BiFunction<K, P, V> valueFactory) { this.subKeyFactory = Objects.requireNonNull(subKeyFactory); this.valueFactory = Objects.requireNonNull(valueFactory); } 其中map变量是实现缓存的核心变量,他是一个双重的Map结构: (key, sub-key) -> value。其中key是传进来的Classloader进行包装后的对象,sub-key是由WeakCache构造函数传人的 KeyFactory()生成的。value就是产生代理类的对象,是由WeakCache构造函数传人的 ProxyClassFactory()生成的 好,大体上说完WeakCache这个类的作用,我们回到刚才 proxyClassCache.get(loader, interfaces);这句代码。get是WeakCache里的方法。源码如下 //K和P就是WeakCache定义中的泛型,key是类加载器,parameter是接口类数组 public V get(K key, P parameter) { //检查parameter不为空 Objects.requireNonNull(parameter); //清除无效的缓存 expungeStaleEntries(); // cacheKey就是(key, sub-key) -> value里的一级key, Object cacheKey = CacheKey.valueOf(key, refQueue); // lazily install the 2nd level valuesMap for the particular cacheKey //根据一级key得到 ConcurrentMap<Object, Supplier<V>>对象。如果之前不存在,则新建一个ConcurrentMap<Object, Supplier<V>>和cacheKey(一级key)一起放到map中。 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 //这部分就是调用生成sub-key的代码,上面我们已经看过怎么生成的了 Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter)); //通过sub-key得到supplier Supplier<V> supplier = valuesMap.get(subKey); //supplier实际上就是这个factory Factory factory = null; while (true) { //如果缓存里有supplier ,那就直接通过get方法,得到代理类对象,返回,就结束了,一会儿分析get方法。 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 //下面的所有代码目的就是:如果缓存中没有supplier,则创建一个Factory对象,把factory对象在多线程的环境下安全的赋给supplier。 //因为是在while(true)中,赋值成功后又回到上面去调get方法,返回才结束。 if (factory == null) { factory = new Factory(key, parameter, subKey, valuesMap); } 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; } else { // retry with current supplier supplier = valuesMap.get(subKey); } } } } 所以接下来我们看Factory类中的get方法。 public synchronized V get() { // serialize access // re-check Supplier<V> supplier = valuesMap.get(subKey); //重新检查得到的supplier是不是当前对象 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 { //代理类就是在这个位置调用valueFactory生成的 //valueFactory就是我们传入的 new ProxyClassFactory() //一会我们分析ProxyClassFactory()的apply方法 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) //把value包装成弱引用 CacheValue<V> cacheValue = new CacheValue<>(value); // put into reverseMap // 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; } } 拨云见日,来到ProxyClassFactory的apply方法,代理类就是在这里生成的。 //这里的BiFunction<T, U, R>是个函数式接口,可以理解为用T,U两种类型做参数,得到R类型的返回值 private static final class ProxyClassFactory implements BiFunction<ClassLoader, Class<?>[], Class<?>> { // prefix for all proxy class names //所有代理类名字的前缀 private static final String proxyClassNamePrefix = "$Proxy"; // next number to use for generation of unique proxy class names //用于生成代理类名字的计数器 private static final AtomicLong nextUniqueNumber = new AtomicLong(); @Override 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 { 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 //代理类访问控制符: public ,final 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. */ //验证所有非公共的接口在同一个包内;公共的就无需处理 //生成包名和类名的逻辑,包名默认是com.sun.proxy,类名默认是$Proxy 加上一个自增的整数值 //如果被代理类是 non-public proxy interface ,则用和被代理类接口一样的包名 for (Class<?> intf : interfaces) { int flags = intf.getModifiers(); 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 proxyPkg = ReflectUtil.PROXY_PACKAGE + "."; } /* * Choose a name for the proxy class to generate. */ long num = nextUniqueNumber.getAndIncrement(); //代理类的完全限定名,如com.sun.proxy.$Proxy0.calss String proxyName = proxyPkg + proxyClassNamePrefix + num; /* * Generate the specified proxy class. */ //核心部分,生成代理类的字节码 byte[] proxyClassFile = ProxyGenerator.generateProxyClass( proxyName, interfaces, accessFlags); try { //把代理类加载到JVM中,至此动态代理过程基本结束了 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()); } } } 到这里其实已经分析完了,但是本着深究的态度,决定看看JDK生成的动态代理字节码是什么,于是我们将字节码保存到磁盘上的class文件中。代码如下: public static void main(String[] args) { IUserService target = new UserServiceImpl(); MyInvocationHandler handler = new MyInvocationHandler(target); //第一个参数是指定代理类的类加载器(我们传入当前测试类的类加载器) //第二个参数是代理类需要实现的接口(我们传入被代理类实现的接口,这样生成的代理类和被代理类就实现了相同的接口) //第三个参数是invocation handler,用来处理方法的调用。这里传入我们自己实现的handler IUserService proxyObject = (IUserService) Proxy.newProxyInstance(DynamicProxyTest.class.getClassLoader(), target.getClass().getInterfaces(), handler); proxyObject.add("张玉龙"); String path = "D:/$Proxy0.class"; byte[] classFile = ProxyGenerator.generateProxyClass("$Proxy0", HelloworldImpl.class.getInterfaces()); FileOutputStream out = null; try { out = new FileOutputStream(path); out.write(classFile); out.flush(); } catch (Exception e) { e.printStackTrace(); } finally { try { out.close(); } catch (IOException e) { e.printStackTrace(); } } } 运行这段代码,会在D盘生成一个名为$Proxy0.class的文件。通过反编译工具,得到JDK为我们生成的代理类是这样的: // Decompiled by Jad v1.5.8e2. Copyright 2001 Pavel Kouznetsov. // Jad home page: http://kpdus.tripod.com/jad.html // Decompiler options: packimports(3) fieldsfirst ansi space import com.zhb.jdk.proxy.IUserService; import java.lang.reflect.*; public final class $Proxy0 extends Proxy implements IUserService { private static Method m1; private static Method m2; private static Method m3; private static Method m0; //代理类的构造函数,其参数正是是InvocationHandler实例, //Proxy.newInstance方法就是通过通过这个构造函数来创建代理实例的 public $Proxy0(InvocationHandler invocationhandler) { super(invocationhandler); } // Object类中的三个方法,equals,toString, hashCode public final boolean equals(Object obj) { try { return ((Boolean)super.h.invoke(this, m1, new Object[] { obj })).booleanValue(); } catch (Error ) { } catch (Throwable throwable) { throw new UndeclaredThrowableException(throwable); } } public final String toString() { try { return (String)super.h.invoke(this, m2, null); } catch (Error ) { } catch (Throwable throwable) { throw new UndeclaredThrowableException(throwable); } } //接口代理方法 public final void add(String s) { try { // invocation handler的 invoke方法在这里被调用 super.h.invoke(this, m3, new Object[] { s }); return; } catch (Error ) { } catch (Throwable throwable) { throw new UndeclaredThrowableException(throwable); } } public final int hashCode() { try { // 在这里调用了invoke方法。 return ((Integer)super.h.invoke(this, m0, null)).intValue(); } catch (Error ) { } catch (Throwable throwable) { throw new UndeclaredThrowableException(throwable); } } // 静态代码块对变量进行一些初始化工作 static { try { m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") }); m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]); m3 = Class.forName("com.zhb.jdk.proxy.IUserService").getMethod("add", new Class[] { Class.forName("java.lang.String") }); m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]); } catch (NoSuchMethodException nosuchmethodexception) { throw new NoSuchMethodError(nosuchmethodexception.getMessage()); } catch (ClassNotFoundException classnotfoundexception) { throw new NoClassDefFoundError(classnotfoundexception.getMessage()); } } } 生成了Object类的三个方法:toString,hashCode,equals。还有我们需要被代理的方法。 JDK代理类的cache clear机制 大家都知道、在项目中被代理的class越来越多,所以jdk会搞一个cache的方式来防止相同的代理接口重复生成class,影响性能不说,实现也不是很优雅,那么现在就会有一个问题了,当classloader已经在内存中没有依赖的时候,被代理的proxy class其实也没有什么意义了,这样就需要清空无用的cache,java Proxy采用了非常巧妙的“弱引用机制”,我们来看下面的代码 我们还是继续看get方法的源码 public V get(K key, P parameter) { Objects.requireNonNull(parameter); expungeStaleEntries(); 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; } } ....... } 其中源码中有一个方法expungeStaleEntries、我们进去这个方法一窥究竟 private void expungeStaleEntries() { CacheKey<K> cacheKey; while ((cacheKey = (CacheKey<K>)refQueue.poll()) != null) { cacheKey.expungeFrom(map, reverseMap); } } 在看看expungeFrom方法源码干了些什么 void expungeFrom(ConcurrentMap<?, ? extends ConcurrentMap<?, ?>> map, ConcurrentMap<?, Boolean> reverseMap) { // removing just by key is always safe here because after a CacheKey // is cleared and enqueue-ed it is only equal to itself // (see equals method)... ConcurrentMap<?, ?> valuesMap = map.remove(this); // remove also from reverseMap if needed if (valuesMap != null) { for (Object cacheValue : valuesMap.values()) { reverseMap.remove(cacheValue); } } } 代码很清晰了,清空被代理的对象。现在的关键就是refQueue对象是怎么来的。我们继续找一下跟refQueue相关的源码、在get中还有一段代码是这样的 Object cacheKey = CacheKey.valueOf(key, refQueue); private static final class CacheKey<K> extends WeakReference<K> { // a replacement for null keys private static final Object NULL_KEY = new Object(); static <K> Object valueOf(K key, ReferenceQueue<K> refQueue) { return key == null // null key means we can't weakly reference it, // so we use a NULL_KEY singleton as cache key ? NULL_KEY // non-null key requires wrapping with a WeakReference : new CacheKey<>(key, refQueue); } private final int hash; private CacheKey(K key, ReferenceQueue<K> refQueue) { super(key, refQueue); this.hash = System.identityHashCode(key); // compare by identity } ..... } 这样看就非常清晰了、原来是CacheKey继承了WeakReference弱引用机制,当弱引用依赖的key没有引用的时候,当前失效的对象就会进入ReferenceQueue中来实现清空cache的功能、这种实现思路和ThreadLocal的实现原理是一样的、大家有兴趣可以去阅读以下相关源码。 三:手把手写基于接口的java代理 上面我们分析了jdk动态代理源码、那我们是不是可以自己用自己的方式去写一个属于自己的jdk代理呢,答案是可以的 首先我们写一个基类,当然我并没有在基类里面写什么东西,只是模拟java中的proxy类而已,当然我们也可以丰富的去拓展一下这个类的方法,来实现更多的功能,读者可以通过读完这篇文章之后自己去考虑一下如何来拓展。 1 package meituan.zylproxy.handlder; 2 public class ZylProxy { 3 public ZylProxy(){ 4 } 5 } 代理的核心接口,我们去做代理的时候一定是通过反射去调用的,不管jdk也好还是cglib也好,永远也无法脱离反射,我们照猫画虎,自己写一个代理接口核心类,这并不是什么难题,看起来和jdk的核心类接口也没有什么区别。 1 package meituan.zylproxy.handlder; 2 3 import java.lang.reflect.Method; 4 5 public interface ZYLInvocationHandler { 6 7 public Object invoke(Object proxy, Method method, Object[] args) 8 throws Exception; 9 } 说明一下 第一个参数proxy是代表代理类,而不是用户自己写的原生类实现。参数Method是接口的方法,args是运行时参数列表,在运行时传递过来的实际上就是实现类的参数,好了,下面让我们去深入核心。 我们自定义两个接口和接口的实现Idto,Idto2,和Dtoimpl如下: 1 package meituan.zylproxy.test.i; 2 3 public interface Idto { 4 5 public void add(); 6 7 public String get(); 8 9 } package meituan.zylproxy.test.i; public interface Idto2 { public void adda(); public String geta(); } package meituan.zylproxy.test.i.impl; import meituan.zylproxy.test.i.Idto; import meituan.zylproxy.test.i.Idto2; public class DtoImpl implements Idto,Idto2{ @Override public void add() { System.out.println("add"); } @Override public String get() { System.out.println("get"); return "return get"; } @Override public void adda() { System.out.println("adda"); } @Override public String geta() { System.out.println("geta"); return "return geta"; } } 这是几个再简单不过的接口和实现类了,也没有什么可说的。接下来我们想对接口进行代理,无非是我们动态将接口进行实现,从而达到对使用者进行自定义handle接口暴露而已,下面看一下我们需要生成一个什么样的代理类。 import java.lang.reflect.Method; import meituan.zylproxy.handlder.ZylProxy; import meituan.zylproxy.handlder.ZYLInvocationHandler; import meituan.zylproxy.test.i.Idto; import meituan.zylproxy.test.i.Idto2; public class IdtoPorxy extends ZylProxy implements Idto, Idto2 { public ZYLInvocationHandler zYLInvocationHandler; public static Method add1; public static Method get2; public static Method adda3; public static Method geta4; static { try { add1 = Class.forName ( "meituan.zylproxy.test.i.Idto" ).getMethod ( "add", new Class[0] ); get2 = Class.forName ( "meituan.zylproxy.test.i.Idto" ).getMethod ( "get", new Class[0] ); adda3 = Class.forName ( "meituan.zylproxy.test.i.Idto2" ).getMethod ( "adda", new Class[0] ); geta4 = Class.forName ( "meituan.zylproxy.test.i.Idto2" ).getMethod ( "geta", new Class[0] ); } catch (Exception e) { } } public IdtoPorxy(ZYLInvocationHandler zYLInvocationHandler) { this.zYLInvocationHandler = zYLInvocationHandler; } public void add() { Object[] o = {}; try { this.zYLInvocationHandler.invoke ( this, add1, o ); return; } catch (Throwable e) { e.printStackTrace (); } } public java.lang.String get() { Object[] o = {}; try { return (java.lang.String) this.zYLInvocationHandler.invoke ( this, get2, o ); } catch (Exception e) { e.printStackTrace (); } return null; } public void adda() { Object[] o = {}; try { this.zYLInvocationHandler.invoke ( this, adda3, o ); return; } catch (Throwable e) { e.printStackTrace (); } } public java.lang.String geta() { Object[] o = {}; try { return (java.lang.String) this.zYLInvocationHandler.invoke ( this, geta4, o ); } catch (Exception e) { e.printStackTrace (); } return null; } } 这个类不是由用户写的,而是我们动态生成的,对于jdk来说是生成了字节码,对cglib来说是通过字节码增强,其实实现的方式有多种,后面为了更方便大家理解我用字符串的形式来动态生成这么一个"家伙",先看看这个类干了些什么吧,也很简单。 public class IdtoPorxy extends ZylProxy implements Idto, Idto2 首先是继承了刚才我们所说的ZylProxy,留着今后拓展,可以参照java的Proxy,然后并且动态的实现了这两个接口。很简单 public ZYLInvocationHandler zYLInvocationHandler; public IdtoPorxy(ZYLInvocationHandler zYLInvocationHandler) { this.zYLInvocationHandler = zYLInvocationHandler; } 这个是通过构造函数传进来一个handler对象,对实现类的操作都靠它了。 public static Method add1; public static Method get2; public static Method adda3; public static Method geta4; static { try { add1 = Class.forName ( "meituan.zylproxy.test.i.Idto" ).getMethod ( "add", new Class[0] ); get2 = Class.forName ( "meituan.zylproxy.test.i.Idto" ).getMethod ( "get", new Class[0] ); adda3 = Class.forName ( "meituan.zylproxy.test.i.Idto2" ).getMethod ( "adda", new Class[0] ); geta4 = Class.forName ( "meituan.zylproxy.test.i.Idto2" ).getMethod ( "geta", new Class[0] ); } catch (Exception e) { } } 枚举出来所有的接口的方法,通过class.forname来获取到Method元数据。备用 public void add() { Object[] o = {}; try { this.zYLInvocationHandler.invoke ( this, add1, o ); return; } catch (Throwable e) { e.printStackTrace (); } } public java.lang.String get() { Object[] o = {}; try { return (java.lang.String) this.zYLInvocationHandler.invoke ( this, get2, o ); } catch (Exception e) { e.printStackTrace (); } return null; } public void adda() { Object[] o = {}; try { this.zYLInvocationHandler.invoke ( this, adda3, o ); return; } catch (Throwable e) { e.printStackTrace (); } } public java.lang.String geta() { Object[] o = {}; try { return (java.lang.String) this.zYLInvocationHandler.invoke ( this, geta4, o ); } catch (Exception e) { e.printStackTrace (); } return null; } 上面是要枚举出来所有的方法的实现,很简单都一个模样,把实现交给handler去做就可以了。至于怎么实现靠handler,我们动态生成的这个类只负责委托,不做任何事情。看到这里大家一定急不可待的想知道这个类怎么生成的了,我把我写的源码给大家贴出来看一下。 package meituan.zylproxy.util; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import meituan.zylproxy.test.i.Idto; import meituan.zylproxy.test.i.Idto2; public class ClassUtil { public static String mackProxyClass(Class<?> c) throws Exception{ if(!c.isInterface()){ throw new Exception("代理的类必须是接口"); } StringBuffer importsp = new StringBuffer(); importsp.append("import java.lang.reflect.Method;\n"); importsp.append("import meituan.zylproxy.handlder.ZylProxy;\n"); importsp.append("import meituan.zylproxy.handlder.ZYLInvocationHandler;\n"); importsp.append("import " +c.getName() + ";\n"); StringBuilder publicStaticMethods = new StringBuilder(); //public static Method add; StringBuilder publicMethods = new StringBuilder(); publicMethods.append("public ZYLInvocationHandler zYLInvocationHandler;\n"); StringBuilder constructorsp = new StringBuilder(); String interFaceName = c.getName().substring(c.getName().lastIndexOf(".")+1); constructorsp.append("public ").append("" + interFaceName + "Porxy"). append("(ZYLInvocationHandler zYLInvocationHandler) { " + "this.zYLInvocationHandler = zYLInvocationHandler;" + "}"); publicStaticMethods.append(" static { try { "); StringBuilder classsp = new StringBuilder(); classsp.append("public class").append(" " + interFaceName + "Porxy").append(" extends ZylProxy implements ").append(interFaceName).append("{"); StringBuilder allMethods = new StringBuilder(); Method[] Methods = c.getMethods(); int curr=0; for (Method m_:Methods) { curr++; publicMethods.append("public static Method ").append(m_.getName() + String.valueOf(curr)).append(";\n"); publicStaticMethods.append("").append(m_.getName() + String.valueOf(curr)).append("="); publicStaticMethods.append("Class.forName(\"" + c.getName() + "\")" + ".getMethod(\""+ m_.getName() +"\", "); StringBuilder sp =new StringBuilder(); StringBuilder spArgs = new StringBuilder(); spArgs.append("Object[] o ={"); //public sp.append(Modifier.toString(m_.getModifiers()).replace("abstract", "")).append(" "); //void | java.lang.String sp.append(m_.getReturnType().getName()).append(" "); //add()|get() sp.append(m_.getName().concat("(")); StringBuilder methodCLass = new StringBuilder(); if(m_.getParameterTypes().length>0){ Class<?>[] claszz = m_.getParameterTypes(); int methodOffset = 0; methodCLass.append("new Class[] { "); for (Class<?> c_ : claszz) { String paramStr = "obj" + String.valueOf(++methodOffset); spArgs.append(paramStr.concat(",")); sp.append(c_.getName().toString().concat(" ").concat(paramStr)).append(","); methodCLass.append("Class.forName(\"" + c_.getName()).append("\"),"); } sp = new StringBuilder(sp.substring(0, sp.length()-1)); spArgs = new StringBuilder(spArgs.substring(0, spArgs.length()-1)); methodCLass = new StringBuilder(methodCLass.substring(0, methodCLass.length()-1)); } if(methodCLass.length()>0){ methodCLass.append("}"); } else{ methodCLass.append("new Class[0]"); } sp.append("){\n"); spArgs.append("}"); sp.append(spArgs+";\n"); if(sp.toString().contains("void")){ sp.append("try {\n this.zYLInvocationHandler.invoke(this,").append(m_.getName() + String.valueOf(curr)).append(",").append("o);\n return;\n"); sp.append("} catch (Throwable e) {e.printStackTrace();}}"); } else{ sp.append("try {return " + "(" + m_.getReturnType().getName() + ")" + "this.zYLInvocationHandler.invoke(this,").append(m_.getName() + String.valueOf(curr)).append(",").append("o);\n"); sp.append("} catch (Exception e) {e.printStackTrace();} return null;"); } publicStaticMethods.append(methodCLass).append(");\n"); allMethods.append(sp); } publicStaticMethods.append("} catch(Exception e){}}"); classsp.append(publicMethods) .append(publicStaticMethods) .append(constructorsp).append(allMethods).append("}"); classsp.append("}"); importsp.append(classsp); return importsp.toString(); } public static String mackMultiProxyClass(Class<?>[] cs) throws Exception{ StringBuffer importsp = new StringBuffer(); importsp.append("import java.lang.reflect.Method;\n"); importsp.append("import meituan.zylproxy.handlder.ZylProxy;\n"); importsp.append("import meituan.zylproxy.handlder.ZYLInvocationHandler;\n"); StringBuilder publicStaticMethods = new StringBuilder(); publicStaticMethods.append(" static { try { "); //public static Method add; StringBuilder publicMethods = new StringBuilder(); publicMethods.append("public ZYLInvocationHandler zYLInvocationHandler;\n"); int curr=0; StringBuilder constructorsp = new StringBuilder(); String interFaceName = cs[0].getName().substring(cs[0].getName().lastIndexOf(".")+1); constructorsp.append("public ").append("" + interFaceName + "Porxy"). append("(ZYLInvocationHandler zYLInvocationHandler) { " + "this.zYLInvocationHandler = zYLInvocationHandler;" + "}"); StringBuilder allMethods = new StringBuilder(); StringBuilder classsp = new StringBuilder(); classsp.append("public class").append(" " + interFaceName + "Porxy").append(" extends ZylProxy implements "); for (Class<?> c:cs) { if(!c.isInterface()){ throw new Exception("代理的类必须是接口"); } classsp.append(c.getName().substring(c.getName().lastIndexOf(".")+1)).append(","); importsp.append("import " +c.getName() + ";\n"); Method[] Methods = c.getMethods(); for (Method m_:Methods) { curr++; publicMethods.append("public static Method ").append(m_.getName() + String.valueOf(curr)).append(";\n"); publicStaticMethods.append("").append(m_.getName() + String.valueOf(curr)).append("="); publicStaticMethods.append("Class.forName(\"" + c.getName() + "\")" + ".getMethod(\""+ m_.getName() +"\", "); StringBuilder sp =new StringBuilder(); StringBuilder spArgs = new StringBuilder(); spArgs.append("Object[] o ={"); //public sp.append(Modifier.toString(m_.getModifiers()).replace("abstract", "")).append(" "); //void | java.lang.String sp.append(m_.getReturnType().getName()).append(" "); //add()|get() sp.append(m_.getName().concat("(")); StringBuilder methodCLass = new StringBuilder(); if(m_.getParameterTypes().length>0){ Class<?>[] claszz = m_.getParameterTypes(); int methodOffset = 0; methodCLass.append("new Class[] { "); for (Class<?> c_ : claszz) { String paramStr = "obj" + String.valueOf(++methodOffset); spArgs.append(paramStr.concat(",")); sp.append(c_.getName().toString().concat(" ").concat(paramStr)).append(","); methodCLass.append("Class.forName(\"" + c_.getName()).append("\"),"); } sp = new StringBuilder(sp.substring(0, sp.length()-1)); spArgs = new StringBuilder(spArgs.substring(0, spArgs.length()-1)); methodCLass = new StringBuilder(methodCLass.substring(0, methodCLass.length()-1)); } if(methodCLass.length()>0){ methodCLass.append("}"); } else{ methodCLass.append("new Class[0]"); } sp.append("){\n"); spArgs.append("}"); sp.append(spArgs+";\n"); if(sp.toString().contains("void")){ sp.append("try {\n this.zYLInvocationHandler.invoke(this,").append(m_.getName() + String.valueOf(curr)).append(",").append("o);\n return;\n"); sp.append("} catch (Throwable e) {e.printStackTrace();}}"); } else{ sp.append("try {return " + "(" + m_.getReturnType().getName() + ")" + "this.zYLInvocationHandler.invoke(this,").append(m_.getName() + String.valueOf(curr)).append(",").append("o);\n"); sp.append("} catch (Exception e) {e.printStackTrace();} return null;}"); } publicStaticMethods.append(methodCLass).append(");\n"); allMethods.append(sp); } } classsp = new StringBuilder(classsp.substring(0, classsp.length()-1)).append("{"); publicStaticMethods.append("} catch(Exception e){}}"); classsp.append(publicMethods) .append(publicStaticMethods) .append(constructorsp).append(allMethods).append(""); classsp.append("}"); importsp.append(classsp); return importsp.toString(); } public static void main(String[] args) throws Exception { System.out.println(mackMultiProxyClass(new Class<?>[]{Idto.class})); } } 看起来很复杂,仔细看一下就看了那么几个事情,把一个接口class或者多个接口class变成纯字符串的过程,一共两个方法,一个是单接口的实现,很早之前写的,第二个方法是多接口的实现支持多接口,只需要传一个class对象就会生成代理类的字符串,这里仅仅是字符串,需要编译成class使用。那么如何编译成class呢。通过java中的工具类JavaCompiler很简单的就可以生成了。我们来看两个工具类实现 package meituan.zylproxy; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FilterOutputStream; import java.io.IOException; import java.io.OutputStream; import java.io.Reader; import java.io.StringReader; import java.net.URI; import java.nio.CharBuffer; import java.nio.file.WatchEvent.Kind; import java.util.HashMap; import java.util.Map; import javax.tools.FileObject; import javax.tools.ForwardingJavaFileManager; import javax.tools.JavaFileManager; import javax.tools.JavaFileObject; import javax.tools.SimpleJavaFileObject; @SuppressWarnings("unchecked") final class MemoryJavaFileManager extends ForwardingJavaFileManager { private final static String EXT = ".java"; private Map<String, byte[]> classBytes; public MemoryJavaFileManager(JavaFileManager fileManager) { super(fileManager); classBytes = new HashMap<String, byte[]>(); } public Map<String, byte[]> getClassBytes() { return classBytes; } public void close() throws IOException { classBytes = new HashMap<String, byte[]>(); } public void flush() throws IOException { } private static class StringInputBuffer extends SimpleJavaFileObject { final String code; StringInputBuffer(String name, String code) { super(toURI(name), Kind.SOURCE); this.code = code; } public CharBuffer getCharContent(boolean ignoreEncodingErrors) { return CharBuffer.wrap(code); } public Reader openReader() { return new StringReader(code); } } private class ClassOutputBuffer extends SimpleJavaFileObject { private String name; ClassOutputBuffer(String name) { super(toURI(name), Kind.CLASS); this.name = name; } public OutputStream openOutputStream() { return new FilterOutputStream(new ByteArrayOutputStream()) { public void close() throws IOException { out.close(); ByteArrayOutputStream bos = (ByteArrayOutputStream) out; classBytes.put(name, bos.toByteArray()); } }; } } public JavaFileObject getJavaFileForOutput(JavaFileManager.Location location, String className, JavaFileObject.Kind kind, FileObject sibling) throws IOException { if (kind == JavaFileObject.Kind.CLASS) { return new ClassOutputBuffer(className); } else { return super.getJavaFileForOutput(location, className, kind, sibling); } } static JavaFileObject makeStringSource(String name, String code) { return new StringInputBuffer(name, code); } static URI toURI(String name) { File file = new File(name); if (file.exists()) { return file.toURI(); } else { try { final StringBuilder newUri = new StringBuilder(); newUri.append("mfm:///"); newUri.append(name.replace('.', '/')); if (name.endsWith(EXT)) newUri.replace(newUri.length() - EXT.length(), newUri.length(), EXT); return URI.create(newUri.toString()); } catch (Exception exp) { return URI.create("mfm:///com/sun/script/java/java_source"); } } } } package meituan.zylproxy; import java.io.IOException; import java.net.URL; import java.net.URLClassLoader; import java.util.Arrays; import java.util.HashMap; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.tools.JavaCompiler; import javax.tools.JavaFileObject; import javax.tools.StandardJavaFileManager; import javax.tools.ToolProvider; public class DynamicLoader { public static Map<String, byte[]> compile(String javaSrc) { Pattern pattern = Pattern.compile("public\\s+class\\s+(\\w+)"); Matcher matcher = pattern.matcher(javaSrc); if (matcher.find()) return compile(matcher.group(1) + ".java", javaSrc); return null; } public static Map<String, byte[]> compile(String javaName, String javaSrc) { JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); StandardJavaFileManager stdManager = compiler.getStandardFileManager(null, null, null); try (MemoryJavaFileManager manager = new MemoryJavaFileManager(stdManager)) { JavaFileObject javaFileObject = manager.makeStringSource(javaName, javaSrc); JavaCompiler.CompilationTask task = compiler.getTask(null, manager, null, null, null, Arrays.asList(javaFileObject)); if (task.call()) return manager.getClassBytes(); } catch (IOException e) { e.printStackTrace(); } return null; } public static class MemoryClassLoader extends URLClassLoader { Map<String, byte[]> classBytes = new HashMap<String, byte[]>(); public MemoryClassLoader(Map<String, byte[]> classBytes) { super(new URL[0], MemoryClassLoader.class.getClassLoader()); this.classBytes.putAll(classBytes); } @Override protected Class<?> findClass(String name) throws ClassNotFoundException { byte[] buf = classBytes.get(name); if (buf == null) { return super.findClass(name); } classBytes.remove(name); return defineClass(name, buf, 0, buf.length); } } } 通过DynamicLoader的compile方法可以把纯字符串的str转成byte[]数组,有了byte[]数组就可以很方便的获取到class对象了,自定义一个MemoryClassLoader通过defineClass方法来获取到class对象。这样基本所有的事情都做完了。下面我们写一个工厂类来获取代理类。 package meituan.zylproxy.util; import java.util.Map; import meituan.zylproxy.DynamicLoader; import meituan.zylproxy.handlder.ZYLInvocationHandler; public class PorxyFactory { //单interface的时候用 public static Object newProxyInstance(Class<?> c,ZYLInvocationHandler h) throws Exception{ String classStr = ClassUtil.mackProxyClass(c); Map<String, byte[]> m = DynamicLoader.compile(classStr); DynamicLoader.MemoryClassLoader classLoader = new DynamicLoader.MemoryClassLoader(m); Class<?> proxy =classLoader.loadClass(m.keySet().toArray(new String[0])[0]); return proxy.getConstructor(ZYLInvocationHandler.class).newInstance(h); } //多interface的时候用 public static Object newProxyInstancewWithMultiClass(Class<?>[] c,ZYLInvocationHandler h) throws Exception{ String classStr = ClassUtil.mackMultiProxyClass(c); System.out.println (classStr); Map<String, byte[]> m = DynamicLoader.compile(classStr); DynamicLoader.MemoryClassLoader classLoader = new DynamicLoader.MemoryClassLoader(m); Class<?> proxy =classLoader.loadClass(m.keySet().toArray(new String[0])[0]); return proxy.getConstructor(ZYLInvocationHandler.class).newInstance(h); } } 最后一步我们测试一下结果吧,写一个测试类 package meituan.zylproxy.test; import meituan.zylproxy.handlder.Hander; import meituan.zylproxy.test.i.Idto; import meituan.zylproxy.test.i.impl.DtoImpl; import meituan.zylproxy.util.PorxyFactory; public class ZylPorxyTest { public static void main(String[] args) throws Exception { Idto d = (Idto) PorxyFactory.newProxyInstancewWithMultiClass(DtoImpl.class.getInterfaces(), new Hander(new DtoImpl())); d.add(); } } 很简单,第一个参数是所有的接口,第二个是handler实现。最后我们看看结果。 大功告成。 作者简介:就职美团外卖业务架构组,有更多的更多的源码交流,请加群825199617交流,spring源码,spring mvc源码,手写企业级高可用rpc框架,java企业级热部署解决方案等等更多精彩源码,等你来。

优秀的个人博客,低调大师

恭喜云上伙伴众安保险港所上市

9月28日,中国互联网保险科技公司众安在线财产保险股份有限公司在香港联交所主板开始交易,股票代号为6060。 众安保险是谁? 众安保险是中国市场上最大的线上保险科技公司,也是第一家将全部业务系统搬上云端的金融企业。凭借先进的技术,众安保险于不同消费场景开发出以生态系统为导向的保险产品及解决方案。 截至2016年12月31日,众安保险已累计销售逾72亿份保单,服务约4.92亿名保单持有人及受保险人。 目前,众安保险的业务涵盖了生活消费、消费金融、健康、车险以及航旅等五大领域。 金融云助力众安保险打造金融科技势能 众安保险诞生于云上,从13年筹备至今,借助阿里金融云安全合规、弹性稳定等特性,其IT资源可以随时随地快速部署,并做到以天为单位构建支持海量数据快速存取及高并发的交易平台。 阿里云从建设之初,就充分考虑各行业的合规问题,尤其对于金融行业,更

资源下载

更多资源
腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

用户登录
用户注册