项目源码在哪里找(哪里找java的开源项目)
项目源码在哪里找(哪里找java的开源项目),新营销网红网本栏目通过数据整理汇集了项目源码在哪里找(哪里找java的开源项目)相关信息,下面一起看看。
1.前言为什么联系JavaAgent?
这是由于作者最近看了Dubbo的源代码。Dubbo有一个有趣的函数,——SPI,它可以根据运行时URI参数自适应地调用特定的实现类。其实大致原理你也能猜到,无非就是生成一个代理类,反射并解析URI参数中的值,然后调用相应的实现类。虽然你大概能猜到实现原理,毕竟只是猜测。本着科学严谨的精神,我还是想看看Dubbo的实现源代码。这时,我有了一个想法。可以把Dubbo生成的代理对象的Class类转储,然后反编译看它的源代码吗?
理论上是完全可行的。阿里有一个非常有用的开源工具Arthas,它的jad命令支持反编译JVM已经加载的类来检查源代码。笔者下载了Arthas项目的源代码,查了一下发现需要JavaAgent技术。
2.JavaAgent规范在JDK1.5之后,我们可以使用JavaAgent技术以“零入侵”的方式增强Java程序。比如阿里云的Arms应用监控服务,可以通过JavaAgent接入一个探头,探头会将应用的运行数据上报给阿里云,开发者可以在后台查看应用的运行数据。这样,我们可以轻松地实现应用程序监控,而无需对应用程序进行任何更改。
JavaAgent是一种规范,分为两类:主程序运行前的代理和主程序运行后的代理。它可以在JVM加载类文件之前修改字节码,甚至允许修改已经加载的类,这样我们就可以增强应用,实现代码热部署。
主程序运行前的代理步骤:
1.编写代理类,它必须具有静态premain()。
类MyAgentClass {//JVM执行公共静态void premain (string agent args,instrumentation inst){ system . err . println( main before . ))第一;} public static void premain(String agent args){ system . err . println( main before . ));}}2.写清单。MF文件,指定Premain-Class,然后把程序做成Jar包。
manifest-version : 1.0 can-redefine-classes : true can-re transform-classes 3360 true premain-class 3360 top.javap.agent.MyAgentClass//注意,这里必须有一个空行。使用Maven builder时,还可以使用以下配置。
plugin groupId org . Apache . maven . plugins/groupId artifactId maven-jar-plugin/artifactId配置存档清单add Class path true/add Class path/manifest entries Premain-Class top . javap . agent . myagentclass/Premain-Class Can-re transform-Classes true/Can-re transform-Classes Can-redefine-Classes true/Can-redefine-Classes/manifest entries/archive/configuration/plugin 3。启动目标程序时,按如下方式指定JVM参数:
Java-Java agent : agent-1.0-snapshot . jar Java app主程序运行代理的步骤:
这是针对已经运行的JVM进程的。我们可以通过附加机制启动一个新的JVM进程,并向它发送执行指令。
1.编写代理类,该类必须有静态agentmain()。
public class MyAgentClass { public static void agent main(String agent args,Instrumentation inst){ system . err . println( main after . ));}}2.写清单。MF文件,指定Premain-Class,然后把程序做成Jar包。
manifest-version : 1.0 can-redefine-classes : true can-re transform-classes : true agent-class 3360 top.javap.agent.MyAgentClass//注意,这里必须有一个空行。3.编写附加程序,启动并附加到目标JVM进程。
公共静态void main(String[] args)引发异常{ virtual machine VM=virtual machine . attach( 8080 );VM . load agent(/dev/agent . jar );}3.相关部件3.1仪器
entation
编写的AgentClass类必须有premain() ,其中一个比较重要的参数就是Instrumentation。它是JavaAgent技术用到的主要API,接口定义如下:
public interface Instrumentation {/*** 添加Class文件转换器,底层采用数组存储* JVM加载Class文件前,需要依次经过转换* @param transformer* @param canRetransform 是否允许转换*/void addTransformer(ClassFileTransformer transformer, boolean canRetransform);void addTransformer(ClassFileTransformer transformer);// 删除Class文件转换器boolean removeTransformer(ClassFileTransformer transformer);boolean isRetransformClassesSupported();// 重新转换Classvoid retransformClasses(Class ? ... classes) throws UnmodifiableClassException;boolean isRedefineClassesSupported();// 重新定义Class,热更新void redefineClasses(ClassDefinition... definitions)throws ClassNotFoundException, UnmodifiableClassException;boolean isModifiableClass(Class ? theClass);@SuppressWarnings("rawtypes")Class[] getAllLoadedClasses();@SuppressWarnings("rawtypes")Class[] getInitiatedClasses(ClassLoader loader);// 获取对象大小long getObjectSize(Object objectToSize);void appendToBootstrapClassLoaderSearch(JarFile jarfile);void appendToSystemClassLoaderSearch(JarFile jarfile);boolean isNativeMethodPrefixSupported();void setNativeMethodPrefix(ClassFileTransformer transformer, String prefix);}
重要的 笔者已经写上注释了,本文会用到的 主要是addTransformer()。它可以用来添加Class转换器,JVM在加载Class前,会先经过这些转换器进行加工。
3.2 ClassFileTransformer
Class文件转换器,JVM加载某个Class前,会先经过它转换,我们可以在这里去修改字节码以达到功能增强的目的。它只有一个 transform():
public interface ClassFileTransformer{/*** 转换Class* @param loader 类加载器* @param className 类名* @param classBeingRedefined 原始Class* @param ProtectionDomain* @param classfileBuffer Class文件字节数组*/byte[] transform( ClassLoader loader,String className,Class ? classBeingRedefined,ProtectionDomain protectionDomain,byte[] classfileBuffer)throws IllegalClassFormatException;}
本文主要用到的就是classfileBuffer,有了Class的字节数组,只要把它导出到磁盘,通过IDEA反编译就能看到源码了。
4. 实战
【需求】
支持将任意Java对象的Class文件导出到磁盘,通过反编译查看源码,包括动态生成的类。
【实现】
1、编写InstrumentationHolder,持有Instrumentation实例,后续操作全靠它。
public class InstrumentationHolder {private static Instrumentation INSTANCE;public static void init(Instrumentation ins) {INSTANCE = ins;}public static Instrumentation get() {if (INSTANCE == null) {throw new RuntimeException("检查 -javaagent 配置");}return INSTANCE;}}
2、编写MyAgentClass,保存Instrumentation实例。
public class MyAgentClass {public static void premain(String agentArgs, Instrumentation inst) {System.err.println("main before...");InstrumentationHolder.init(inst);}}
3、编写ClassDumpTransformer,获取Class文件字节数组,导出到磁盘。
public class ClassDumpTransformer implements ClassFileTransformer {private final File file;private final Set Class ? classes = new HashSet ();public ClassDumpTransformer(String path, Class ? ... classes) {this.file = new File(path);this.classes.addAll(Arrays.asList(classes));}@Overridepublic byte[] transform(ClassLoader loader, String className, Class ? classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {if (classes.contains(classBeingRedefined)) {FileUtil.writeBytes(classfileBuffer, file);}return null;}}
4、编写ClassUtil工具类,支持导出Class文件。
public class ClassUtil {public static void classDump(Class ? c, String path) {ClassDumpTransformer transformer = new ClassDumpTransformer(path, c);Instrumentation inst = InstrumentationHolder.get();inst.addTransformer(transformer, true);try {inst.retransformClasses(c);} catch (UnmodifiableClassException e) {e.printStackTrace();} finally {inst.removeTransformer(transformer);}}}
5、编写MANIFEST.MF文件,构建Jar包。
Manifest-Version: 1.0Can-Redefine-Classes: trueCan-Retransform-Classes: truePremain-Class: top.javap.agent.MyAgentClass
6、编写测试类,利用JDK动态代理生成代理类,然后将代理类的Class文件导出。
public class AgentDemo {public static void main(String[] args) throws Exception {Object instance = Proxy.newProxyInstance(A.class.getClassLoader(), new Class[]{A.class}, new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {return null;}});ClassUtil.classDump(instance.getClass(),"/target/X.class");}public static interface A {void a();}}
7、设置-javaagent参数并启动程序。
java -javaagent:agent.jar AgentDemo
此时,target目录下就会生成X.class文件,通过IDEA打开即可看到JDK生成的代理类源码。
5. 总结
JavaAgent十分强大,通过它可以在JVM加载Class文件前修改字节码,甚至修改JVM已经加载的Class。基于此,我们可以「零侵入」的对应用程序做增强,服务实现热部署等等。
本文通过一个小示例,编写ClassFileTransformer实现类导出对象的Class文件,反编译查看其源码。这对于ASM操作字节码、JDK动态代理等动态生成类的场景下,而我们又想看对象的具体实现时,提供了帮助。
相关文章
粤语歌曲网(经典粤语歌曲汇总)
北京奥特莱斯(来北京必逛的12个商场)
豪杰超级解霸(还记得豪杰超级解霸吗?)
龚自珍的资料(清代诗人龚自珍一生功绩简介)
象牙塔是什么意思(“象牙塔”里怎么了?)
水色风信子(水培风信子容易养)
婧字怎么读
虞姬是哪里人(古代著名美人虞姬到底是哪里人?)
公办三本院校(我们还有哪些“三本”?)
电子酒柜(酒柜最全选购指南)
德州景点(德州市景区景点62个)
玉兰油官方网(OLAY发布高端臻粹系列)
更多项目源码在哪里找(哪里找java的开源项目)相关信息请关注本文章,本文仅仅做为展示!