Jdk8 动态编译 Java 源码为 Class 文件(三)

Jdk8 动态编译 Java 源码为 Class 文件

  • 一.JDK版本
  • 二.工程介绍
    • 1.依赖
    • 2.启动类
    • 3.配置类(用于测试依赖注入)
    • 4.工具类
      • 1.Java 源码文件读取类
      • 2.SpringBoot 容器实例管理类
    • 5.测试类
      • 1.抽象类
      • 2.接口类
      • 3.默认抽象实现
      • 4.默认接口实现
    • 6.接口类
      • 1.测试接口
      • 2.类重载控制接口
    • 7.动态编译类
      • 1.类加载器
      • 2.类管理器
      • 3.类对象
      • 4.Java 文件类
    • 8.配置文件
  • 三.测试
    • 1.测试用类
      • 1.测试类原类修改
    • 2.测试
      • 1.原类直接打印
      • 2.原类修改
  • 四.Jar 反编译记录

一.JDK版本

在这里插入图片描述

二.工程介绍

动态源码编译需要自定义类加载器,JVM会根据所属类加载器和全类名判断是否为同一个类,所以动态编译和加载时,同一个类无法用同一个类加载器加载两次,除非从 JVM 层面移除旧的类。
同一个类由不同类加载器加载时,JVM 会判断为非同类,所以无法直接实例化后强转为同一类型的实例,需要基于接口、抽象类来实现动态替换

在这里插入图片描述

1.依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>org.example</groupId><artifactId>spring-dynamic</artifactId><version>1.0-SNAPSHOT</version><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><spring.version>2.7.4</spring.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><version>${spring.version}</version><exclusions><exclusion><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-logging</artifactId></exclusion></exclusions></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-log4j2</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.26</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-loader</artifactId><version>${spring.version}</version></dependency><dependency><groupId>com.sun</groupId><artifactId>tools</artifactId><version>1.8.0_341</version><scope>system</scope><systemPath>${JAVA_HOME}\lib\tools.jar</systemPath></dependency></dependencies><build><finalName>dynamic-demo</finalName><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><version>2.7.4</version><executions><execution><goals><goal>repackage</goal></goals></execution></executions><!-- for tools.jar -->
<!--                <configuration>-->
<!--                    <includeSystemScope>true</includeSystemScope>-->
<!--                </configuration>--></plugin></plugins></build>
</project>

2.启动类

package com.example;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;/*** @author* @date 2023-08-10 9:51* @since 1.8*/
@SpringBootApplication
public class DynamicApp {public static void main(String[] args) {SpringApplication.run(DynamicApp.class,args);}
}

3.配置类(用于测试依赖注入)

package com.example.config;import org.springframework.stereotype.Component;/*** @author moon* @date 2023-08-30 14:58* @since 1.8*/
@Component
public class KafkaConfig {public void getConfig(){System.out.println("kafka config");}
}

4.工具类

1.Java 源码文件读取类

package com.example.util;import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;/*** @author moon* @date 2023-08-31 9:25* @since 1.8*/
public class FileUtil {public static String readJson(String filePath){if (org.springframework.util.StringUtils.hasLength(filePath)){InputStream inputStream = null;StringBuilder builder = new StringBuilder();try {int batchSize = 2048;inputStream = new FileInputStream(filePath);byte[] temp = new byte[batchSize];int read;while ((read = inputStream.read(temp)) != -1){if (read < batchSize){byte[] tail = Arrays.copyOf(temp,read);builder.append(new String(tail));} else {builder.append(new String(temp));}}return builder.toString();} catch (IOException e) {return "";} finally {if (null != inputStream){try {inputStream.close();} catch (IOException e) {throw new RuntimeException(e);}}}}return "";}}

2.SpringBoot 容器实例管理类

package com.example.util;import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.stereotype.Component;import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;/*** @author moon* @date 2023-08-31 11:18* @since 1.8*/
@Component
public class SpringBeanUtil implements ApplicationContextAware {private static ApplicationContext applicationContext;private static ConfigurableApplicationContext context ;/*** 获取 Bean 工厂*/private static DefaultListableBeanFactory beanFactory ;@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {SpringBeanUtil.applicationContext = applicationContext;SpringBeanUtil.context= (ConfigurableApplicationContext) applicationContext;SpringBeanUtil.beanFactory= (DefaultListableBeanFactory) context.getBeanFactory();}/*** 替换 bean 并获取新的* @param beanName* @param clazz* @return*/public static Object replace(String beanName,Class clazz){//卸载unregister(beanName);//注册register(beanName,clazz);//获取return getBean(beanName);}/*** 注册 Bean* @param clazz*/public static void register(String beanName,Class clazz){BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(clazz);BeanDefinition definition = builder.getBeanDefinition();//为 definition 设置额外属性definition.setScope("singleton");//注册beanFactory.registerBeanDefinition(beanName,definition);}/*** 卸载 Bean* @param beanName*/public static void unregister(String beanName){if (beanFactory.containsBean(beanName)){beanFactory.removeBeanDefinition(beanName);}}/*** 获取所有 Bean* @return*/public static List<String> getBeans(){String[] names = applicationContext.getBeanDefinitionNames();List<String> beans = new ArrayList<>(names.length);for (String name:names){beans.add(applicationContext.getBean(name).getClass().getName());}return beans;}/*** bean 是否存在* @param name* @return*/public static boolean isBeanExist(String name){return applicationContext.containsBean(name);}/*** 通过名称获取 Bean* @param name* @return* @param <T>* @throws BeansException*/public static <T> T getBean(String name) throws BeansException{return (T) applicationContext.getBean(name);}/*** 通过类型获取 Bean* @param clazz* @return* @param <T>* @throws BeansException*/public static <T> T getBean(Class<?> clazz) throws BeansException{return (T) applicationContext.getBean(clazz);}/*** 获取指定类型的 Bean 的名称* @param className* @return* @throws BeansException*/public static List<String> getBeanName(String className) throws BeansException, ClassNotFoundException {Class<?> clazz = Class.forName(className);return Arrays.asList(applicationContext.getBeanNamesForType(clazz));}
}

5.测试类

1.抽象类

package com.example.service;/*** @author moon* @date 2023-08-30 14:15* @since 1.8*/
public abstract class TestAbstract {/*** 抽象方法* @param str*/public abstract void hand(String str);
}

2.接口类

package com.example.service;/*** @author moon* @date 2023-08-31 10:58* @since 1.8*/
public interface TestService {/*** 处理* @param str*/void hand(String str);}

3.默认抽象实现

package com.example.service.impl;import com.example.config.KafkaConfig;
import com.example.service.TestAbstract;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;/*** @author moon* @date 2023-08-31 11:01* @since 1.8*/
@Component
public class TestAbstractImpl extends TestAbstract {@AutowiredKafkaConfig config;@Value("${my.ip}")String ip;@Overridepublic void hand(String str) {config.getConfig();System.out.println(str);System.out.println(ip);}
}

4.默认接口实现

package com.example.service.impl;import com.example.config.KafkaConfig;
import com.example.service.TestService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;/*** @author moon* @date 2023-08-31 10:59* @since 1.8*/
@Service
public class TestServiceImpl implements TestService {@AutowiredKafkaConfig config;@Overridepublic void hand(String str) {config.getConfig();System.out.println("hand: " + this);}
}

6.接口类

1.测试接口

package com.example.controller;import com.example.service.TestAbstract;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import javax.annotation.Resource;/*** @author moon* @date 2023-08-30 17:27* @since 1.8*/
@RestController
@RequestMapping("/test")
public class TestController {/*** 引入抽象类依赖*/@Resource(name = "testAbstractImpl")TestAbstract testAbstract;@GetMapping("/print")public void print(String content){testAbstract.hand("Hello : " + content);}
}

2.类重载控制接口

package com.example.controller;import com.example.dynamic.MemoryClassLoader;
import com.example.service.TestAbstract;
import com.example.util.FileUtil;
import com.example.util.SpringBeanUtil;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.lang.reflect.InvocationTargetException;
import java.net.MalformedURLException;/*** @author moon* @date 2023-08-30 14:10* @since 1.8*/
@RestController
@RequestMapping("/reload")
public class Reload extends ClassLoader{@GetMapping("/re")public void re(String name,String beanName) throws InstantiationException, IllegalAccessException, InvocationTargetException, MalformedURLException, NoSuchMethodException, ClassNotFoundException {String className = "com.example.service.impl." + name;String classPath = "C:\\Users\\administrator\\Desktop\\jar\\"+name+".java";String javaStr = FileUtil.readJson(classPath);/*** 定义新的 MemoryClassLoader 同一个 MemoryClassLoader 不能两次加载同一个类*/MemoryClassLoader loader = new MemoryClassLoader();loader.registerJava(className,javaStr);Class clazz = loader.findClass(className);TestAbstract handler = (TestAbstract) clazz.getDeclaredConstructor().newInstance();// 将外部Jar包中的Bean注入到Spring容器中Object obj = SpringBeanUtil.replace(beanName,clazz);TestAbstract test = (TestAbstract) obj;test.hand("sss");System.out.println();}}

7.动态编译类

1.类加载器

package com.example.dynamic;import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.system.ApplicationHome;
import org.springframework.stereotype.Component;import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.ToolProvider;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Arrays;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;/*** @author moon*/
@Slf4j
@Component
public class MemoryClassLoader extends URLClassLoader {/*** 缓存字节码*/private Map<String, byte[]> classBytesMap = new ConcurrentHashMap<>();/*** 构造*/public MemoryClassLoader() {super(new URL[0], MemoryClassLoader.class.getClassLoader());}/*** 注册 Java 字符串到内存类加载器中** @param className 类名字* @param javaStr   Java字符串*/public void registerJava(String className, String javaStr) {try {this.classBytesMap.putAll(compile(className, javaStr));} catch (Exception e) {log.error("register java class exception:");}}/*** 编译 Java 源码** @param className 类名字* @param javaStr   Java代码* @return class 二进制*/private Map<String, byte[]> compile(String className, String javaStr) {//初始化编译器JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();//获取Java文件管理器try (MemoryJavaFileManager manager = new MemoryJavaFileManager()) {JavaFileObject javaFileObject = manager.makeStringSource(className, javaStr);JavaCompiler.CompilationTask task = compiler.getTask(null, manager, null, null, null, Arrays.asList(javaFileObject));if (task.call()) {return manager.getClassBytes();}} catch (Exception e) {log.error("compile java str exception:",e);}return null;}/*** 获取 Class* @param name the name of the class* @return* @throws ClassNotFoundException*/@Overridepublic Class<?> findClass(String name) throws ClassNotFoundException {byte[] buf = classBytesMap.get(name);if (buf == null) {return super.findClass(name);}classBytesMap.remove(name);return defineClass(name, buf, 0, buf.length);}/*** 获取jar包所在路径** @return jar包所在路径*/public static String getPath() {ApplicationHome home = new ApplicationHome(MemoryJavaFileManager.class);String path = home.getSource().getPath();return path;}/*** 判断是否jar模式运行** @return*/public static boolean isJar() {return getPath().endsWith(".jar");}}

2.类管理器

package com.example.dynamic;import com.sun.tools.javac.file.JavacFileManager;
import com.sun.tools.javac.util.Context;
import com.sun.tools.javac.util.Log;
import org.springframework.boot.loader.jar.JarFile;
import javax.tools.*;
import java.io.*;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.jar.JarEntry;
import java.util.stream.Collectors;/*** Java 文件管理器* 用于加载 SpringBoot 下面的依赖资源** @author moon* @date 2023-08-10 9:58* @since 1.8*/
public class MemoryJavaFileManager extends ForwardingJavaFileManager<JavaFileManager> {/*** 缓存字节码*/final Map<String, byte[]> classBytesMap = new ConcurrentHashMap<>();/*** 缓存文件对象*/final Map<String, List<JavaFileObject>> classObjectPackageMap = new ConcurrentHashMap<>();/*** 文件管理器*/private JavacFileManager javaFileManager;/*** 包名 / JavaFile(.java)*/public final static Map<String, List<JavaFileObject>> CLASS_OBJECT_PACKAGE_MAP = new ConcurrentHashMap<>();/*** 锁对象*/private static final Object lock = new Object();/*** 初始化标识*/private static boolean isInit = false;/*** 初始化*/public void init() {try {JarFile tempJarFile;List<JavaFileObject> javaFiles;String packageName,className;//获取当前 Jar 包String jarBaseFile = MemoryClassLoader.getPath();//加载 Jar 包JarFile jarFile = new JarFile(new File(jarBaseFile));//取包自身文件for (JarEntry entry:jarFile){//SpringBoot repackage 打包 class 文件带一个 BOOT-INF/classes/ 之后才是包名String name = entry.getName().replace("BOOT-INF/classes/","");String classPath = name.replace("/", ".");//如果不是 class 文件跳过if (name.endsWith(".class")){//取出包名packageName = classPath.substring(0, name.lastIndexOf("/"));//取类名className = classPath.replace(".class", "");//创建集合javaFiles = Optional.ofNullable(CLASS_OBJECT_PACKAGE_MAP.get(packageName)).orElse(new ArrayList<>()) ;//取 JavaFilefilterClass(packageName,className,jarFile.getUrl(),entry.getName(),javaFiles);}}//遍历取内部 Jar 包List<JarEntry> entries = jarFile.stream().filter(jarEntry -> {return jarEntry.getName().endsWith(".jar");}).collect(Collectors.toList());// Jar Filefor (JarEntry entry : entries) {//取内部文件tempJarFile = jarFile.getNestedJarFile(jarFile.getEntry(entry.getName()));//跳过工具包 Jarif (tempJarFile.getName().contains("tools.jar")) {continue;}//遍历 Jar 文件Enumeration<JarEntry> tempEntriesEnum = tempJarFile.entries();while (tempEntriesEnum.hasMoreElements()) {JarEntry jarEntry = tempEntriesEnum.nextElement();String classPath = jarEntry.getName().replace("/", ".");//如果不是 class 文件跳过if (!classPath.endsWith(".class") || jarEntry.getName().lastIndexOf("/") == -1) {continue;} else {//取出包名packageName = classPath.substring(0, jarEntry.getName().lastIndexOf("/"));//取类名className = jarEntry.getName().replace("/", ".").replace(".class", "");//创建集合javaFiles = Optional.ofNullable(CLASS_OBJECT_PACKAGE_MAP.get(packageName)).orElse(new ArrayList<>()) ;//取 JavaFilefilterClass(packageName,className,tempJarFile.getUrl(),jarEntry.getName(),javaFiles);}}}} catch (Exception e) {e.printStackTrace();}isInit = true;}/*** 取 class* @param packageName* @param className* @param url* @param entryName* @param javaFiles*/private void filterClass(String packageName,String className,URL url,String entryName,List<JavaFileObject> javaFiles) throws MalformedURLException {//取 JavaFilejavaFiles.add(new MemorySpringBootInfoJavaClassObject(className, new URL(url, entryName), javaFileManager));//缓存 Package / JavaFileCLASS_OBJECT_PACKAGE_MAP.put(packageName, javaFiles);}/*** 构造*/MemoryJavaFileManager() {super(getStandardFileManager(null, null, null));this.javaFileManager = (JavacFileManager) fileManager;}/*** 获取文件对象集合* @param packageName* @return*/public List<JavaFileObject> getLibJarsOptions(String packageName) {synchronized (lock) {if (!isInit) {init();}}return CLASS_OBJECT_PACKAGE_MAP.get(packageName);}@Overridepublic Iterable<JavaFileObject> list(Location location,String packageName,Set<JavaFileObject.Kind> kinds,boolean recurse)throws IOException {if ("CLASS_PATH".equals(location.getName()) && MemoryClassLoader.isJar()) {List<JavaFileObject> result = getLibJarsOptions(packageName);if (result != null) {return result;}}Iterable<JavaFileObject> it = super.list(location, packageName, kinds, recurse);if (kinds.contains(JavaFileObject.Kind.CLASS)) {final List<JavaFileObject> javaFileObjectList = classObjectPackageMap.get(packageName);if (javaFileObjectList != null) {if (it != null) {for (JavaFileObject javaFileObject : it) {javaFileObjectList.add(javaFileObject);}}return javaFileObjectList;} else {return it;}} else {return it;}}@Overridepublic String inferBinaryName(Location location, JavaFileObject file) {if (file instanceof MemoryInputJavaClassObject) {return ((MemoryInputJavaClassObject) file).inferBinaryName();}return super.inferBinaryName(location, file);}@Overridepublic JavaFileObject getJavaFileForOutput(Location location, String className, JavaFileObject.Kind kind,FileObject sibling) throws IOException {if (kind == JavaFileObject.Kind.CLASS) {return new MemoryOutputJavaClassObject(className);} else {return super.getJavaFileForOutput(location, className, kind, sibling);}}/*** 设置源码* @param className* @param code* @return*/JavaFileObject makeStringSource(String className, final String code) {String classPath = className.replace('.', '/') + JavaFileObject.Kind.SOURCE.extension;return new SimpleJavaFileObject(URI.create("string:///" + classPath), JavaFileObject.Kind.SOURCE) {@Overridepublic CharBuffer getCharContent(boolean ignoreEncodingErrors) {return CharBuffer.wrap(code);}};}/*** 设置字节码* @param className* @param bs*/void makeBinaryClass(String className, final byte[] bs) {JavaFileObject javaFileObject = new MemoryInputJavaClassObject(className, bs);String packageName = "";int pos = className.lastIndexOf('.');if (pos > 0) {packageName = className.substring(0, pos);}List<JavaFileObject> javaFileObjectList = classObjectPackageMap.get(packageName);if (javaFileObjectList == null) {javaFileObjectList = new LinkedList<>();javaFileObjectList.add(javaFileObject);classObjectPackageMap.put(packageName, javaFileObjectList);} else {javaFileObjectList.add(javaFileObject);}}/*** 内部输入类*/class MemoryInputJavaClassObject extends SimpleJavaFileObject {final String className;final byte[] bs;MemoryInputJavaClassObject(String className, byte[] bs) {super(URI.create("string:///" + className.replace('.', '/') + Kind.CLASS.extension), Kind.CLASS);this.className = className;this.bs = bs;}@Overridepublic InputStream openInputStream() {return new ByteArrayInputStream(bs);}public String inferBinaryName() {return className;}}/*** 内部输出类*/class MemoryOutputJavaClassObject extends SimpleJavaFileObject {final String className;MemoryOutputJavaClassObject(String className) {super(URI.create("string:///" + className.replace('.', '/') + Kind.CLASS.extension), Kind.CLASS);this.className = className;}@Overridepublic OutputStream openOutputStream() {return new FilterOutputStream(new ByteArrayOutputStream()) {@Overridepublic void close() throws IOException {out.close();ByteArrayOutputStream bos = (ByteArrayOutputStream) out;byte[] bs = bos.toByteArray();classBytesMap.put(className, bs);makeBinaryClass(className, bs);}};}}/*** 获取编译结果* @return*/public Map<String, byte[]> getClassBytes() {return new HashMap<>(this.classBytesMap);}/*** 刷新* @throws IOException*/@Overridepublic void flush() throws IOException {}/*** 关闭* @throws IOException*/@Overridepublic void close() throws IOException {classBytesMap.clear();}/*** 自定义 Java 文件管理器** @param var1* @param var2* @param var3* @return*/public static SpringJavaFileManager getStandardFileManager(DiagnosticListener<? super JavaFileObject> var1, Locale var2, Charset var3) {Context var4 = new Context();var4.put(Locale.class, var2);if (var1 != null) {var4.put(DiagnosticListener.class, var1);}PrintWriter var5 = var3 == null ? new PrintWriter(System.err, true) : new PrintWriter(new OutputStreamWriter(System.err, var3), true);var4.put(Log.outKey, var5);return new SpringJavaFileManager(var4, true, var3);}
}

3.类对象

package com.example.dynamic;import com.sun.tools.javac.file.BaseFileObject;
import com.sun.tools.javac.file.JavacFileManager;import javax.tools.JavaFileObject;
import java.io.*;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;/*** 用来读取 spring boot 的 class** @author moon* @date 2023-08-10 9:57* @since 1.8*/
public class MemorySpringBootInfoJavaClassObject extends BaseFileObject {private final String className;private URL url;public MemorySpringBootInfoJavaClassObject(String className, URL url, JavacFileManager javacFileManager) {super(javacFileManager);this.className = className;this.url = url;}@Overridepublic JavaFileObject.Kind getKind() {return JavaFileObject.Kind.valueOf("CLASS");}@Overridepublic URI toUri() {try {return url.toURI();} catch (URISyntaxException e) {e.printStackTrace();}return null;}@Overridepublic String getName() {return className;}@Overridepublic InputStream openInputStream() {try {return url.openStream();} catch (IOException e) {e.printStackTrace();}return null;}@Overridepublic OutputStream openOutputStream() throws IOException {return null;}@Overridepublic CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {return null;}@Overridepublic Writer openWriter() throws IOException {return null;}@Overridepublic long getLastModified() {return 0;}@Overridepublic boolean delete() {return false;}public String inferBinaryName() {return className;}@Overridepublic String getShortName() {return className.substring(className.lastIndexOf("."));}@Overrideprotected String inferBinaryName(Iterable<? extends File> iterable) {return className;}@Overridepublic boolean equals(Object o) {return false;}@Overridepublic int hashCode() {return 0;}@Overridepublic boolean isNameCompatible(String simpleName, JavaFileObject.Kind kind) {return false;}
}

4.Java 文件类

package com.example.dynamic;import com.sun.tools.javac.file.JavacFileManager;
import com.sun.tools.javac.util.Context;
import com.sun.tools.javac.util.ListBuffer;
import java.io.File;
import java.lang.reflect.Constructor;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.charset.Charset;
import java.util.Iterator;/*** Java 文件管理器** @author moon* @date 2023-08-10 9:53* @since 1.8*/
public class SpringJavaFileManager extends JavacFileManager {/**** @param context* @param b* @param charset*/public SpringJavaFileManager(Context context, boolean b, Charset charset) {super(context, b, charset);}/*** 重写类加载器* @param location a location* @return*/@Overridepublic ClassLoader getClassLoader(Location location) {nullCheck(location);Iterable var2 = this.getLocation(location);if (var2 == null) {return null;} else {ListBuffer var3 = new ListBuffer();Iterator var4 = var2.iterator();while (var4.hasNext()) {File var5 = (File) var4.next();try {var3.append(var5.toURI().toURL());} catch (MalformedURLException var7) {throw new AssertionError(var7);}}return this.getClassLoader((URL[]) var3.toArray(new URL[var3.size()]));}}/*** 获取 LaunchedURLClassLoader 加载器** @param var1* @return*/@Overrideprotected ClassLoader getClassLoader(URL[] var1) {ClassLoader var2 = this.getClass().getClassLoader();try {Class loaderClass = Class.forName("org.springframework.boot.loader.LaunchedURLClassLoader");Class[] var4 = new Class[]{URL[].class, ClassLoader.class};Constructor var5 = loaderClass.getConstructor(var4);return (ClassLoader) var5.newInstance(var1, var2);} catch (Throwable var6) {}return new URLClassLoader(var1, var2);}}

8.配置文件

server:port: 8082
my:ip: 123.456.789.1

三.测试

启动 Java 服务(Xbootclasspath 引入 tools.jar)

java -Xbootclasspath/a:C:\Progra~1\Java\jdk1.8.0_341\jre\lib\tools.jar -jar dynamic-demo.jar

在这里插入图片描述

1.测试用类

1.测试类原类修改

package com.example.service.impl;import com.example.config.KafkaConfig;
import com.example.service.TestAbstract;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;/*** @author moon* @date 2023-08-31 11:01* @since 1.8*/
@Component
public class TestAbstractImpl extends TestAbstract {@AutowiredKafkaConfig config;@Value("${my.ip}")String ip;@Overridepublic void hand(String str) {config.getConfig();System.out.println("How are you" + str);System.out.println(ip);}
}

2.测试

1.原类直接打印

http://127.0.0.1:8082/test/print?content=lisi

在这里插入图片描述

2.原类修改

重载
http://127.0.0.1:8082/reload/re?name=TestAbstractImpl&beanName=testAbstractImpl

在这里插入图片描述
调用测试
http://127.0.0.1:8082/test/print?content=zhangsan

在这里插入图片描述

四.Jar 反编译记录

1.IDEA 安装插件 Java Decompiler

在这里插入图片描述

2.找到插件包(可以将该Jar包取到其他位置使用):C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2022.2\plugins\java-decompiler\lib

创建一个 SRC 目录
反编译命令
%JAVA_HOME_19%\java -cp java-decompiler.jar org.jetbrains.java.decompiler.main.decompiler.ConsoleDecompiler -dgs=true tools.jar src

在这里插入图片描述

结果是一个 tools.jar 文件,将其扩展名改为 .zip 并解压就可以看到实际已经是 java 文件了

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/119314.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SpringWeb(SpringMVC)

目录 SpringWeb介绍 搭建 SpringWeb SpringWeb介绍 Spring Web是一个基于 Servlet API 构建的原始 web 框架&#xff0c;用于构建基于MVC模式的Web应用程序。在 web 层框架历经 Strust1&#xff0c;WebWork&#xff0c;Strust2 等诸多产品的历代更选 之后&#xff0c;目前业界普…

QT DAY4

一、使用鼠标时间完成组件的移动 #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include<QDebug> #include<QMouseEvent>QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACEclass Widget : public QWidget {Q_OBJECTpublic:Widg…

LLMs:OpenAI官方重磅更新——新增GPT-3.5Turbo调和API更新功能

LLMs&#xff1a;OpenAI官方重磅更新——新增GPT-3.5Turbo调和API更新功能 导读&#xff1a;2023年8月22日&#xff0c;OpenAI官方发布&#xff0c;开发者现在可以使用自己的数据来定制适用于其用例的GPT-3.5 Turbo模型。GPT-3.5 Turbo的微调现在已经可用&#xff0c;GPT-4的微…

【算法与数据结构】106、LeetCode从中序与后序遍历序列构造二叉树

文章目录 一、题目二、解法三、完整代码 所有的LeetCode题解索引&#xff0c;可以看这篇文章——【算法和数据结构】LeetCode题解。 一、题目 二、解法 思路分析&#xff1a;首先我们要知道后序遍历数组的最后一个元素必然是根节点&#xff0c;然后根据根节点在中序遍历数组中的…

【LeetCode-中等题】994. 腐烂的橘子

文章目录 题目方法一&#xff1a;bfs层序遍历 题目 该题值推荐用bfs&#xff0c;因为是一层一层的感染&#xff0c;而不是一条线走到底的那种&#xff0c;所以深度优先搜索不适合 方法一&#xff1a;bfs层序遍历 广度优先搜索&#xff0c;就是从起点出发&#xff0c;每次都尝…

Android GB28181客户端开发(1):GB28181协议简介

Android GB28181客户端开发(1):GB28181协议简介 公共安全视频监控联网系统信息传输、交换、控制技术要求(2016版) 源码请翻到文章结尾 介绍GB28181协议 GB28181协议是一种基于IP网络的远程视频监控系统,它定义了设备之间的通信协议和数据格式。GB28181协议的主要特点是支…

【Rust】001-基础语法:变量声明及数据类型

【Rust】001-基础语法&#xff1a;变量声明及数据类型 文章目录 【Rust】001-基础语法&#xff1a;变量声明及数据类型一、概述1、学习起源2、依托课程 二、入门程序1、Hello World2、交互程序代码演示执行结果 3、继续上难度&#xff1a;访问链接并打印响应依赖代码执行命令 三…

Collections和CollectionUtils集合操作

0.引入依赖 <dependency><groupId>org.apache.commons</groupId><artifactId>commons-collections4</artifactId><version>4.4</version> </dependency> 一.Collections用法&#xff1a; 01、排序操作 reverse(List list)…

【摆烂之小左】Maven配置IDEA教程

Maven是什么 Maven项目对象模型(POM)&#xff0c;可以通过一小段描述信息来管理项目的构建&#xff0c;报告和文档的项目管理工具软件。 Maven 除了以程序构建能力为特色之外&#xff0c;还提供高级项目管理工具。由于 Maven 的缺省构建规则有较高的可重用性&#xff0c;所以常…

数学建模:模糊综合评价分析

&#x1f506; 文章首发于我的个人博客&#xff1a;欢迎大佬们来逛逛 数学建模&#xff1a;模糊综合评价分析 文章目录 数学建模&#xff1a;模糊综合评价分析综合评价分析常用评价方法一级模糊综合评价综合代码 多级模糊综合评价总结 综合评价分析 构成综合评价类问题的五个…

go语言基础操作--二

a : 10str : "mike"//匿名函数&#xff0c;没有函数名字 形成一个闭包,函数定义&#xff0c;还没有调用f1 : func() { //:自动推到类型fmt.Println("a ", a)fmt.Println("str ", str)}f1()//给一个函数类型起别名 这个写法不推荐type FuncType …

Flutter状态管理 — 探索Flutter中的状态

前言 随着响应式编程的理念&Flutter被大众所了解以来&#xff0c;状态管理一直是一个引人深思的话题。如果想要学习好Flutter这样的响应式的编程框架就一定是离不开状态管理的。我遇到过很多没有了解过响应式编程框架的&#xff0c;或者从事后端开发&#xff0c;自己想用F…

docker笔记4:高级复杂安装-mysql主从复制

1.主从搭建步骤 1.1新建主服务器容器实例3307 docker run -p 3307:3306 --name mysql-master \ -v /mydata/mysql-master/log:/var/log/mysql \ -v /mydata/mysql-master/data:/var/lib/mysql \ -v /mydata/mysql-master/conf:/etc/mysql \ -e MYSQL_ROOT_PASSWORDroot \ -d…

Linux的目录结构特点

Linux的目录结构特点 1、使用树形目录结构来组织和管理文件。 2、整个系统只有一个根目录&#xff08;树根&#xff09;&#xff0c;Linux的根目录用“/”表示。 3、其他所有分区以及外部设备&#xff08;如硬盘&#xff0c;光驱等&#xff09;都是以根目录为起点&#xff0…

【已解决】激活虚拟环境报错:此时不应有Anaconda3\envs\[envs]\Library\ssl\cacert.pem。

新建虚拟环境后&#xff0c;进入虚拟环境的时候出现这样的报错&#xff1a; 此时不应有Anaconda3 envs yolov5 Library ssl cacert.pem。 但是之前装的虚拟环境也还能再次激活&#xff0c;base环境也无任何问题&#xff0c;仅新装的虚拟环境无法激活。 查遍了百度谷歌&#xff…

ThreadLocal源码剖析(简单理解)

Thread部分源码 public class Thread implements Runnable {ThreadLocal.ThreadLocalMap threadLocals null; }ThreadLocal源码,其中ThreadLocal有一个静态内部类ThreadLocalMap,这个Map不是类似二叉树类型的,只是一个普通数组,其中具体使用什么算法其实我也不太理解. 然后对…

通过ref 操作dom , 点击按钮后跳转到页面指定图片位置

滚动图片到视图 定义了一个名为 scrollToIndex 的函数&#xff0c;它接受一个参数 index。当按钮被点击时&#xff0c;这个函数会被调用&#xff0c;并根据传入的 index 值来滚动到对应的图片。 以 alt 来标记图片位置 alt“Tom” import { useRef } from "react";c…

1.(python数模)单函数读取常用文件

Python单函数读取常用文件 代码如下&#xff1a; import pandas as pd# 读取数据文件 def readDataFile(readPath): # readPath: 数据文件的地址和文件名try:if (readPath[-4:] ".csv"):dfFile pd.read_csv(readPath, header0, sep",") # 间隔符为逗…

I2C与I3C的对比

I2C与I3C的对比 电气特性 I2C 1.半双工 2.串行数据线(SDA)和串行时钟线(SCL) 3.数据线漏极开路&#xff0c;即I2C接口接上拉电阻 4.I2C总线运行速度&#xff1a;**标准模式100kbit/s&#xff0c;快速模式400kbit/s&#xff0c;快速模式plus 1Mbit/s&#xff0c;**高速模式…

机器学习:可解释学习

文章目录 可解释学习为什么需要可解释机器学习可解释还是强模型可解释学习的目标可解释机器学习Local ExplanationGlobal Explanation 可解释学习 神马汉斯&#xff0c;只有在有人看的时候能够答对。 为什么需要可解释机器学习 贷款&#xff0c;医疗需要给出理由&#xff0c;让…