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 文件了

相关文章:
Jdk8 动态编译 Java 源码为 Class 文件(三)
Jdk8 动态编译 Java 源码为 Class 文件 一.JDK版本二.工程介绍1.依赖2.启动类3.配置类(用于测试依赖注入)4.工具类1.Java 源码文件读取类2.SpringBoot 容器实例管理类 5.测试类1.抽象类2.接口类3.默认抽象实现4.默认接口实现 6.接口类1.测试接口2.类重载…...
Shell自动化日志维护脚本
简介: 系统日志对于了解操作系统的运行状况、故障排除和性能分析至关重要。然而,长期积累的日志文件可能变得庞大,影响系统性能。在这篇文章中,我们将介绍一个自动化的解决方案,使用 Bash 脚本来监控和维护系统日志文件…...
设计模式入门笔记
1 设计模式简介 在IT这个行业,技术日新月异,可能你今年刚弄懂一个编程框架,明年它就不流行了。 然而即使在易变的IT世界也有很多几乎不变的知识,他们晦涩而重要,默默的将程序员划分为卓越与平庸两类。比如说ÿ…...
存储成本降低85%,携程历史库场景的降本实践
携程,一家中国领先的在线票务服务公司,从 1999 年创立至今,数据库系统历经三次替换。在移动互联网时代,面对云计算卷积而来的海量数据,携程通过新的数据库方案实现存储成本降低 85% 左右,性能提升数倍。本文…...
如何精确掌握函数防抖和函数节流的使用?
前序 函数防抖(Debouncing)和函数节流(Throttling)都是用于控制函数执行频率的技术,通常在处理高频率触发的事件(如窗口滚动、鼠标移动、输入框输入等)时非常有用 一、核心概念 函数防抖 函…...
【Linux系列】离线安装openjdk17的rpm包
首发博客地址 首发博客地址[1] 系列文章地址[2] 视频地址[3] 准备 RPM 包 请从官网下载:https://www.oracle.com/java/technologies/downloads/#java17[4] 如需不限速下载,请关注【程序员朱永胜】并回复 1020 获取。 安装 yum localinstall jdk-17_linux…...
Python 没有 pip 包问题解决
最近需要搞一个干净的Python,从官网上直接下载解压可用的绿色版,发现无法正常使用PiP 一 官网下载Python https://www.python.org/downloads/ 选择 embeddable package,这种是免安装的包,解压后可以直接使用。 二 配置环境变量 添加环境变量:…...
并发-Java中的锁(二)--- 重入锁ReentrantLock,公平锁,非公平锁笔记
重入锁ReentrantLock 支持重进入的锁,表示该锁能够支持一个线程对资源的重复加锁该锁支持获取锁时的公平和非公平的选择 如果在绝对时间上,先对锁进行获取的请求一定先被满足,那么锁是公平的,获取锁是顺序的。 实现重进入 线程再…...
LeetCode每日一题:1921. 消灭怪物的最大数量(2023.9.3 C++)
目录 1921. 消灭怪物的最大数量 题目描述: 实现代码与解析: 贪心 原理思路: 1921. 消灭怪物的最大数量 题目描述: 你正在玩一款电子游戏,在游戏中你需要保护城市免受怪物侵袭。给你一个 下标从 0 开始 且长度为 …...
SpringBoot连接MySQL数据库,使用Mybatis框架(入门)
1. 说明 SpringBoot项目,连接MySQL数据库,使用Mybatis框架。 本篇文章作为 SpringBoot 使用 Mybatis 的入门。 2. 依赖 2.1. MySQL驱动依赖 MySQL驱动,使用SpringBoot版本对应的默认版本,不需要手动指定版本。 比如…...
滑动窗口实例6(找到字符串中所有字母异位词)
题目: 给定两个字符串 s 和 p,找到 s 中所有 p 的 异位词 的子串,返回这些子串的起始索引。不考虑答案输出的顺序。 异位词 指由相同字母重排列形成的字符串(包括相同的字符串)。 示例 1: 输入: s "cbaebabac…...
武林新秀(一)`git init` 初始化一个新的Git仓库
文章目录 命令的概述和用途命令的用法命令行选项和参数的详细说明命令的示例命令的注意事项或提示 命令的概述和用途 git init 是 Git 版本控制系统中用于初始化一个新的 Git 仓库或重新初始化一个现有的仓库的命令。“init” 是 “initialize”(初始化)…...
gRPC之Interceptor
1、gRPC Interceptor 在应用开发过程中会有这样的需求,就是在请求执行前后做一些通用的处理逻辑,比如记录日志、tracing、身份 认证等,在web框架中一般是使用middleware来实现的,gRPC 在客户端和服务端都支持了拦截器功能&#…...
计算机竞赛 基于机器视觉的二维码识别检测 - opencv 二维码 识别检测 机器视觉
文章目录 0 简介1 二维码检测2 算法实现流程3 特征提取4 特征分类5 后处理6 代码实现5 最后 0 简介 🔥 优质竞赛项目系列,今天要分享的是 基于机器学习的二维码识别检测 - opencv 二维码 识别检测 机器视觉 该项目较为新颖,适合作为竞赛课…...
ELK安装、部署、调试 (七)kibana的安装与配置
1.介绍 Kibana 是一个基于浏览器的开源可视化工具,主要用于分析大量日志,以折线图、条形图、饼图、热图、区域图、坐标图、仪表、目标、时间等形式。预测或查看输入源的错误或其他重大事件趋势的变化。Kibana 与 Elasticsearch 和 Logstash 同步工作&am…...
【Npm】的安装和使用教程
前端工具及插件库 专栏收录该内容 24 篇文章1 订阅 订阅专栏 npm 一、安装配置 二、初始化配置文件 package.json package.lock.json 二、下载模块 2.1、下载指令 2.2、清理缓存 2.3、模块信息 2.4、npm i 与 npm ci 区别 三、其他指令 第三方模块是别人写好的一些文件…...
22.3D等距社交媒体菜单的悬停特效
效果 源码 <!doctype html> <html><head><meta charset="utf-8"><title>CSS Isometric Social Media Menu</title><link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.…...
音视频开发常用工具
文章目录 前言一、VLC 播放器1、简介2、下载3、VLC media player4、VLC 打开网络串流5、VLC 作为流媒体服务器①、搭建 RTSP 流媒体服务器②、新建播放器 二、MediaInfo1、简介2、下载3、MediaInfo①、主界面②、主要功能特点③、使用方法④、Mediainfo 相关参数和含义简介 三、…...
【leetcode 力扣刷题】字符串匹配之经典的KMP!!!
字符串子串匹配相关 28. 找出字符串中第一个匹配项的下标暴力求解KMP 459. 重复的子字符串暴力求解在SS中找S 以下是能用KMP求解的算法题,KMP是用于字符串匹配的经典算法【至今没学懂………啊啊啊】 28. 找出字符串中第一个匹配项的下标 题目链接:28. 找…...
C#的反射机制
介绍 当谈到C#的反射机制时,它提供了一种动态地在运行时获取和操作类型信息的能力。通过反射,可以在编译时未知的情况下,使用类型信息来创建对象、调用方法、访问属性和字段等。下面是一些反射机制的重要概念和用法: Type 类型&a…...
Python爬虫实战:研究MechanicalSoup库相关技术
一、MechanicalSoup 库概述 1.1 库简介 MechanicalSoup 是一个 Python 库,专为自动化交互网站而设计。它结合了 requests 的 HTTP 请求能力和 BeautifulSoup 的 HTML 解析能力,提供了直观的 API,让我们可以像人类用户一样浏览网页、填写表单和提交请求。 1.2 主要功能特点…...
模型参数、模型存储精度、参数与显存
模型参数量衡量单位 M:百万(Million) B:十亿(Billion) 1 B 1000 M 1B 1000M 1B1000M 参数存储精度 模型参数是固定的,但是一个参数所表示多少字节不一定,需要看这个参数以什么…...
Qt Widget类解析与代码注释
#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this); }Widget::~Widget() {delete ui; }//解释这串代码,写上注释 当然可以!这段代码是 Qt …...
线程与协程
1. 线程与协程 1.1. “函数调用级别”的切换、上下文切换 1. 函数调用级别的切换 “函数调用级别的切换”是指:像函数调用/返回一样轻量地完成任务切换。 举例说明: 当你在程序中写一个函数调用: funcA() 然后 funcA 执行完后返回&…...
LeetCode - 394. 字符串解码
题目 394. 字符串解码 - 力扣(LeetCode) 思路 使用两个栈:一个存储重复次数,一个存储字符串 遍历输入字符串: 数字处理:遇到数字时,累积计算重复次数左括号处理:保存当前状态&a…...
HBuilderX安装(uni-app和小程序开发)
下载HBuilderX 访问官方网站:https://www.dcloud.io/hbuilderx.html 根据您的操作系统选择合适版本: Windows版(推荐下载标准版) Windows系统安装步骤 运行安装程序: 双击下载的.exe安装文件 如果出现安全提示&…...
tree 树组件大数据卡顿问题优化
问题背景 项目中有用到树组件用来做文件目录,但是由于这个树组件的节点越来越多,导致页面在滚动这个树组件的时候浏览器就很容易卡死。这种问题基本上都是因为dom节点太多,导致的浏览器卡顿,这里很明显就需要用到虚拟列表的技术&…...
【碎碎念】宝可梦 Mesh GO : 基于MESH网络的口袋妖怪 宝可梦GO游戏自组网系统
目录 游戏说明《宝可梦 Mesh GO》 —— 局域宝可梦探索Pokmon GO 类游戏核心理念应用场景Mesh 特性 宝可梦玩法融合设计游戏构想要素1. 地图探索(基于物理空间 广播范围)2. 野生宝可梦生成与广播3. 对战系统4. 道具与通信5. 延伸玩法 安全性设计 技术选…...
Java多线程实现之Thread类深度解析
Java多线程实现之Thread类深度解析 一、多线程基础概念1.1 什么是线程1.2 多线程的优势1.3 Java多线程模型 二、Thread类的基本结构与构造函数2.1 Thread类的继承关系2.2 构造函数 三、创建和启动线程3.1 继承Thread类创建线程3.2 实现Runnable接口创建线程 四、Thread类的核心…...
QT开发技术【ffmpeg + QAudioOutput】音乐播放器
一、 介绍 使用ffmpeg 4.2.2 在数字化浪潮席卷全球的当下,音视频内容犹如璀璨繁星,点亮了人们的生活与工作。从短视频平台上令人捧腹的搞笑视频,到在线课堂中知识渊博的专家授课,再到影视平台上扣人心弦的高清大片,音…...
