diff --git a/sofa-serverless-runtime/pom.xml b/sofa-serverless-runtime/pom.xml
index 3e74d416d..f608cfe7d 100644
--- a/sofa-serverless-runtime/pom.xml
+++ b/sofa-serverless-runtime/pom.xml
@@ -82,7 +82,8 @@
arklet-corearklet-springboot-startersofa-serverless-adapter-ext
-
+ sofa-serverless-base-loader
+
diff --git a/sofa-serverless-runtime/sofa-serverless-base-loader/pom.xml b/sofa-serverless-runtime/sofa-serverless-base-loader/pom.xml
new file mode 100644
index 000000000..ace06cd58
--- /dev/null
+++ b/sofa-serverless-runtime/sofa-serverless-base-loader/pom.xml
@@ -0,0 +1,25 @@
+
+
+
+ sofa-serverless-runtime
+ com.alipay.sofa.serverless
+ ${revision}
+ ../pom.xml
+
+ 4.0.0
+ ${revision}
+ pom
+ sofa-serverless-base-loader
+
+ sofa-serverless-spring-loader
+ sofa-serverless-spring-loader-tool
+
+
+
+ 8
+ 8
+
+
+
\ No newline at end of file
diff --git a/sofa-serverless-runtime/sofa-serverless-base-loader/sofa-serverless-spring-loader-tool/README.md b/sofa-serverless-runtime/sofa-serverless-base-loader/sofa-serverless-spring-loader-tool/README.md
new file mode 100644
index 000000000..50710c0e0
--- /dev/null
+++ b/sofa-serverless-runtime/sofa-serverless-base-loader/sofa-serverless-spring-loader-tool/README.md
@@ -0,0 +1,43 @@
+# 使用说明
+
+1. 引入打包依赖
+```xml
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+ 2.7.15
+
+ ../../target/boot
+ executable
+
+
+
+ package
+
+ repackage
+
+
+
+
+
+ com.alipay.sofa.serverless
+ sofa-serverless-spring-loader-tool
+
+ 0.5.6
+
+
+
+```
+2. fat jar启动方式不变,会默认使用sofa-serverless-spring-loader的JarLauncher启动
+```shell
+java -jar xxx-executable.jar
+```
+3. 解压启动方式,Launcher需要改成com.alipay.sofa.serverless.spring.loader.JarLauncher
+```shell
+java -classpath xxx-executable-unpack com.alipay.sofa.serverless.spring.loader.JarLauncher
+```
+
+# 维护说明
+
+如果改了ofa-serverless-spring-loader代码,需要先手动mvn打包,然后将sofa-serverless-spring-loader/target/sofa-serverless-spring-loader-xxx.jar复制到sofa-serverless-spring-loader-tool/src/main/resources/META-INF/loader
+
diff --git a/sofa-serverless-runtime/sofa-serverless-base-loader/sofa-serverless-spring-loader-tool/pom.xml b/sofa-serverless-runtime/sofa-serverless-base-loader/sofa-serverless-spring-loader-tool/pom.xml
new file mode 100644
index 000000000..c9cd8935f
--- /dev/null
+++ b/sofa-serverless-runtime/sofa-serverless-base-loader/sofa-serverless-spring-loader-tool/pom.xml
@@ -0,0 +1,49 @@
+
+
+
+ com.alipay.sofa.serverless
+ sofa-serverless-base-loader
+ ${revision}
+ ../pom.xml
+
+ 4.0.0
+
+ sofa-serverless-spring-loader-tool
+ ${revision}
+
+
+ 8
+ 8
+
+
+
+ org.springframework.boot
+ spring-boot-loader
+
+
+ org.springframework.boot
+ spring-boot-loader-tools
+ ${spring.boot.version}
+
+
+ junit
+ junit
+ test
+
+
+
+ org.mockito
+ mockito-core
+ test
+
+
+
+ org.mockito
+ mockito-inline
+ test
+
+
+
+
\ No newline at end of file
diff --git a/sofa-serverless-runtime/sofa-serverless-base-loader/sofa-serverless-spring-loader-tool/src/main/java/com/alipay/sofa/serverless/spring/loader/tools/CustomLayoutFactory.java b/sofa-serverless-runtime/sofa-serverless-base-loader/sofa-serverless-spring-loader-tool/src/main/java/com/alipay/sofa/serverless/spring/loader/tools/CustomLayoutFactory.java
new file mode 100644
index 000000000..d64b3132b
--- /dev/null
+++ b/sofa-serverless-runtime/sofa-serverless-base-loader/sofa-serverless-spring-loader-tool/src/main/java/com/alipay/sofa/serverless/spring/loader/tools/CustomLayoutFactory.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alipay.sofa.serverless.spring.loader.tools;
+
+import java.io.File;
+
+import org.springframework.boot.loader.tools.Layout;
+import org.springframework.boot.loader.tools.LayoutFactory;
+
+/**
+ * CustomLayoutFactory
+ * @author zjulbj
+ * @daye 2023/12/26
+ * @version CustomLayoutFactory.java, v 0.1 2023年12月26日 14:45 syd
+ */
+public class CustomLayoutFactory implements LayoutFactory {
+ @Override
+ public Layout getLayout(File source) {
+ return Layouts.forFile(source);
+ }
+}
\ No newline at end of file
diff --git a/sofa-serverless-runtime/sofa-serverless-base-loader/sofa-serverless-spring-loader-tool/src/main/java/com/alipay/sofa/serverless/spring/loader/tools/Layouts.java b/sofa-serverless-runtime/sofa-serverless-base-loader/sofa-serverless-spring-loader-tool/src/main/java/com/alipay/sofa/serverless/spring/loader/tools/Layouts.java
new file mode 100644
index 000000000..cf650eb01
--- /dev/null
+++ b/sofa-serverless-runtime/sofa-serverless-base-loader/sofa-serverless-spring-loader-tool/src/main/java/com/alipay/sofa/serverless/spring/loader/tools/Layouts.java
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alipay.sofa.serverless.spring.loader.tools;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
+import org.springframework.boot.loader.tools.CustomLoaderLayout;
+import org.springframework.boot.loader.tools.Layout;
+import org.springframework.boot.loader.tools.LibraryScope;
+import org.springframework.boot.loader.tools.LoaderClassesWriter;
+
+/**
+ * Custom Layouts
+ * @author zjulbj
+ * @daye 2023/12/26
+ * @version Layouts.java, v 0.1 2023年12月26日 14:45 syd
+ */
+public class Layouts {
+ private Layouts() {
+ }
+
+ /**
+ * Return a layout for the given source file.
+ *
+ * @param file the source file
+ * @return a {@link Layout}
+ */
+ public static Layout forFile(File file) {
+ if (file == null) {
+ throw new IllegalArgumentException("File must not be null");
+ }
+ String lowerCaseFileName = file.getName().toLowerCase(Locale.ENGLISH);
+ if (lowerCaseFileName.endsWith(".jar")) {
+ return new Jar();
+ }
+ return org.springframework.boot.loader.tools.Layouts.forFile(file);
+ }
+
+ /**
+ * Executable JAR layout.
+ */
+ public static class Jar extends org.springframework.boot.loader.tools.Layouts.Jar implements
+ CustomLoaderLayout {
+ @Override
+ public String getLauncherClassName() {
+ return "com.alipay.sofa.serverless.spring.loader.JarLauncher";
+ }
+
+ @Override
+ public void writeLoadedClasses(LoaderClassesWriter writer) throws IOException {
+ writer.writeLoaderClasses("META-INF/loader/spring-boot-loader.jar");
+ writer.writeLoaderClasses("META-INF/loader/sofa-serverless-spring-loader.jar");
+ }
+ }
+}
\ No newline at end of file
diff --git a/sofa-serverless-runtime/sofa-serverless-base-loader/sofa-serverless-spring-loader-tool/src/main/resources/META-INF/loader/sofa-serverless-spring-loader.jar b/sofa-serverless-runtime/sofa-serverless-base-loader/sofa-serverless-spring-loader-tool/src/main/resources/META-INF/loader/sofa-serverless-spring-loader.jar
new file mode 100644
index 000000000..239e58df0
Binary files /dev/null and b/sofa-serverless-runtime/sofa-serverless-base-loader/sofa-serverless-spring-loader-tool/src/main/resources/META-INF/loader/sofa-serverless-spring-loader.jar differ
diff --git a/sofa-serverless-runtime/sofa-serverless-base-loader/sofa-serverless-spring-loader-tool/src/main/resources/META-INF/spring.factories b/sofa-serverless-runtime/sofa-serverless-base-loader/sofa-serverless-spring-loader-tool/src/main/resources/META-INF/spring.factories
new file mode 100644
index 000000000..fb31a99b9
--- /dev/null
+++ b/sofa-serverless-runtime/sofa-serverless-base-loader/sofa-serverless-spring-loader-tool/src/main/resources/META-INF/spring.factories
@@ -0,0 +1 @@
+org.springframework.boot.loader.tools.LayoutFactory=com.alipay.sofa.serverless.spring.loader.tools.CustomLayoutFactory
diff --git a/sofa-serverless-runtime/sofa-serverless-base-loader/sofa-serverless-spring-loader-tool/src/test/java/com/alipay/sofa/serverless/spring/loader/tools/LayoutsTest.java b/sofa-serverless-runtime/sofa-serverless-base-loader/sofa-serverless-spring-loader-tool/src/test/java/com/alipay/sofa/serverless/spring/loader/tools/LayoutsTest.java
new file mode 100644
index 000000000..e747dfc0c
--- /dev/null
+++ b/sofa-serverless-runtime/sofa-serverless-base-loader/sofa-serverless-spring-loader-tool/src/test/java/com/alipay/sofa/serverless/spring/loader/tools/LayoutsTest.java
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alipay.sofa.serverless.spring.loader.tools;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.jar.JarFile;
+
+import com.alipay.sofa.serverless.spring.loader.tools.Layouts.Jar;
+import junit.framework.TestCase;
+import org.junit.Assert;
+
+import org.springframework.boot.loader.tools.JarWriter;
+import org.springframework.boot.loader.tools.Layout;
+
+public class LayoutsTest extends TestCase {
+
+ public void testForNullFile() throws IOException {
+ IllegalArgumentException exception = null;
+ try {
+ Layouts.forFile(null);
+ } catch (IllegalArgumentException e) {
+ exception = e;
+ }
+ assertNotNull(exception);
+ }
+
+ public void testForFile() throws IOException {
+ CustomLayoutFactory customLayoutFactory = new CustomLayoutFactory();
+
+ File appJar = new File(getClass().getClassLoader().getResource("demo-executable.jar")
+ .getFile());
+ Layout layout = customLayoutFactory.getLayout(appJar);
+ assertTrue(layout instanceof Jar);
+ Jar jar = (Jar) layout;
+ assertEquals("com.alipay.sofa.serverless.spring.loader.JarLauncher",
+ jar.getLauncherClassName());
+ File rewrite = new File(appJar.getParent() + "/demo-executable-rewrite.jar");
+ JarWriter writer = new JarWriter(rewrite);
+ jar.writeLoadedClasses(writer);
+ writer.close();
+ URLClassLoader urlClassLoader = new URLClassLoader(new URL[] { rewrite.toURI().toURL() },
+ null);
+ try {
+ urlClassLoader.loadClass(jar.getLauncherClassName());
+ } catch (ClassNotFoundException e) {
+ Assert.fail(e.getMessage());
+ }
+ }
+}
\ No newline at end of file
diff --git a/sofa-serverless-runtime/sofa-serverless-base-loader/sofa-serverless-spring-loader-tool/src/test/resources/demo-executable.jar b/sofa-serverless-runtime/sofa-serverless-base-loader/sofa-serverless-spring-loader-tool/src/test/resources/demo-executable.jar
new file mode 100644
index 000000000..93dc8f4b4
Binary files /dev/null and b/sofa-serverless-runtime/sofa-serverless-base-loader/sofa-serverless-spring-loader-tool/src/test/resources/demo-executable.jar differ
diff --git a/sofa-serverless-runtime/sofa-serverless-base-loader/sofa-serverless-spring-loader/pom.xml b/sofa-serverless-runtime/sofa-serverless-base-loader/sofa-serverless-spring-loader/pom.xml
new file mode 100644
index 000000000..6976efe48
--- /dev/null
+++ b/sofa-serverless-runtime/sofa-serverless-base-loader/sofa-serverless-spring-loader/pom.xml
@@ -0,0 +1,62 @@
+
+
+
+ com.alipay.sofa.serverless
+ sofa-serverless-base-loader
+ ${revision}
+ ../pom.xml
+
+ 4.0.0
+ sofa-serverless-spring-loader
+ ${revision}
+
+
+ 8
+ 8
+
+
+
+ org.springframework.boot
+ spring-boot-loader
+
+
+ org.springframework.boot
+ spring-boot-loader-tools
+ ${spring.boot.version}
+
+
+ junit
+ junit
+ test
+
+
+
+ org.mockito
+ mockito-core
+ test
+
+
+
+ org.mockito
+ mockito-inline
+ test
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+ ${java.version}
+ ${java.version}
+ UTF-8
+ true
+
+
+
+
+
+
\ No newline at end of file
diff --git a/sofa-serverless-runtime/sofa-serverless-base-loader/sofa-serverless-spring-loader/src/main/java/com/alipay/sofa/serverless/spring/loader/CachedLaunchedURLClassLoader.java b/sofa-serverless-runtime/sofa-serverless-base-loader/sofa-serverless-spring-loader/src/main/java/com/alipay/sofa/serverless/spring/loader/CachedLaunchedURLClassLoader.java
new file mode 100644
index 000000000..40b422b60
--- /dev/null
+++ b/sofa-serverless-runtime/sofa-serverless-base-loader/sofa-serverless-spring-loader/src/main/java/com/alipay/sofa/serverless/spring/loader/CachedLaunchedURLClassLoader.java
@@ -0,0 +1,141 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alipay.sofa.serverless.spring.loader;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Optional;
+
+import org.springframework.boot.loader.LaunchedURLClassLoader;
+import org.springframework.boot.loader.archive.Archive;
+
+/**
+ * A cached LaunchedURLClassLoader to accelerate load classes and resources
+ * @author zjulbj
+ * @daye 2023/12/26
+ * @version CachedLaunchedURLClassLoader.java, v 0.1 2023年12月26日 14:45 syd
+ */
+public class CachedLaunchedURLClassLoader extends LaunchedURLClassLoader {
+ private static final int ENTRY_CACHE_SIZE = Integer.getInteger(
+ "serverless.class.cache.size",
+ 6000);
+ private static final Object NOT_FOUND = new Object();
+ protected final Map classCache = Collections
+ .synchronizedMap(new LinkedHashMap(
+ ENTRY_CACHE_SIZE, 0.75f,
+ true) {
+ @Override
+ protected boolean removeEldestEntry(Map.Entry eldest) {
+ return size() >= ENTRY_CACHE_SIZE;
+ }
+ });
+ protected final Map> resourceUrlCache = Collections
+ .synchronizedMap(new LinkedHashMap>(
+ ENTRY_CACHE_SIZE, 0.75f,
+ true) {
+ @Override
+ protected boolean removeEldestEntry(Map.Entry> eldest) {
+ return size() >= ENTRY_CACHE_SIZE;
+ }
+ });
+ protected final Map resourcesUrlCache = Collections
+ .synchronizedMap(new LinkedHashMap(
+ ENTRY_CACHE_SIZE, 0.75f,
+ true) {
+ @Override
+ protected boolean removeEldestEntry(Map.Entry eldest) {
+ return size() >= ENTRY_CACHE_SIZE;
+ }
+ });
+
+ static {
+ ClassLoader.registerAsParallelCapable();
+ }
+
+ public CachedLaunchedURLClassLoader(boolean exploded, Archive rootArchive, URL[] urls,
+ ClassLoader parent) {
+ super(exploded, rootArchive, urls, parent);
+ }
+
+ @Override
+ protected Class> loadClass(String name, boolean resolve) throws ClassNotFoundException {
+ return loadClassWithCache(name, resolve);
+ }
+
+ @Override
+ public URL findResource(String name) {
+ Optional urlOptional = resourceUrlCache.get(name);
+ if (urlOptional != null) {
+ return urlOptional.orElse(null);
+ }
+ URL url = super.findResource(name);
+ resourceUrlCache.put(name, url != null ? Optional.of(url) : Optional.empty());
+ return url;
+ }
+
+ @Override
+ public Enumeration findResources(String name) throws IOException {
+ Optional> urlOptional = resourcesUrlCache.get(name);
+ if (urlOptional != null) {
+ return urlOptional.orElse(null);
+ }
+ Enumeration enumeration = super.findResources(name);
+ if (enumeration == null || !enumeration.hasMoreElements()) {
+ resourcesUrlCache.put(name, Optional.empty());
+ }
+ return enumeration;
+ }
+
+ /**
+ * NOTE: Only cache ClassNotFoundException when class not found.
+ * If class found, do not cache, and just use parent class loader cache.
+ *
+ * @param name
+ * @param resolve
+ * @return
+ * @throws ClassNotFoundException
+ */
+ protected Class> loadClassWithCache(String name, boolean resolve)
+ throws ClassNotFoundException {
+ Object resultInCache = classCache.get(name);
+ if (resultInCache == NOT_FOUND) {
+ throw new ClassNotFoundException(name);
+ }
+ try {
+ Class> clazz = super.findLoadedClass(name);
+ if (clazz == null) {
+ clazz = super.loadClass(name, resolve);
+ }
+ return clazz;
+ } catch (ClassNotFoundException exception) {
+ classCache.put(name, NOT_FOUND);
+ throw exception;
+ }
+ }
+
+ @Override
+ public void clearCache() {
+ super.clearCache();
+ classCache.clear();
+ resourceUrlCache.clear();
+ resourcesUrlCache.clear();
+ }
+}
\ No newline at end of file
diff --git a/sofa-serverless-runtime/sofa-serverless-base-loader/sofa-serverless-spring-loader/src/main/java/com/alipay/sofa/serverless/spring/loader/JarLauncher.java b/sofa-serverless-runtime/sofa-serverless-base-loader/sofa-serverless-spring-loader/src/main/java/com/alipay/sofa/serverless/spring/loader/JarLauncher.java
new file mode 100644
index 000000000..2c539e82e
--- /dev/null
+++ b/sofa-serverless-runtime/sofa-serverless-base-loader/sofa-serverless-spring-loader/src/main/java/com/alipay/sofa/serverless/spring/loader/JarLauncher.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alipay.sofa.serverless.spring.loader;
+
+/**
+ *
+ * @author syd
+ * @version JarLauncher.java, v 0.1 2023年12月26日 14:54 syd
+ */
+import java.net.URL;
+
+/**
+ * A JarLauncher to load classes with CachedLaunchedURLClassLoader
+ *
+ * @author zjulbj
+ * @daye 2023/12/26
+ * @author bingjie.lbj
+ */
+public class JarLauncher extends org.springframework.boot.loader.JarLauncher {
+ public static void main(String[] args) throws Exception {
+ new JarLauncher().launch(args);
+ }
+
+ @Override
+ protected ClassLoader createClassLoader(URL[] urls) throws Exception {
+ return new CachedLaunchedURLClassLoader(isExploded(), getArchive(), urls, getClass()
+ .getClassLoader());
+ }
+}
diff --git a/sofa-serverless-runtime/sofa-serverless-base-loader/sofa-serverless-spring-loader/src/test/java/com/alipay/sofa/serverless/spring/loader/CachedLaunchedURLClassLoaderTest.java b/sofa-serverless-runtime/sofa-serverless-base-loader/sofa-serverless-spring-loader/src/test/java/com/alipay/sofa/serverless/spring/loader/CachedLaunchedURLClassLoaderTest.java
new file mode 100644
index 000000000..db2a2a8dc
--- /dev/null
+++ b/sofa-serverless-runtime/sofa-serverless-base-loader/sofa-serverless-spring-loader/src/test/java/com/alipay/sofa/serverless/spring/loader/CachedLaunchedURLClassLoaderTest.java
@@ -0,0 +1,100 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alipay.sofa.serverless.spring.loader;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+
+import junit.framework.TestCase;
+import org.junit.Assert;
+
+public class CachedLaunchedURLClassLoaderTest extends TestCase {
+
+ public void testLoadClass() throws IOException, ClassNotFoundException, InterruptedException {
+
+ URL appJar = getClass().getClassLoader().getResource("jars/demo.jar");
+
+ System.setProperty("serverless.class.cache.size", "100");
+ CachedLaunchedURLClassLoader loader = new CachedLaunchedURLClassLoader(false, null,
+ new URL[] { appJar }, null);
+ URL url = loader.getResource("com/example/demo/DemoApplication.class");
+ assertNotNull(url);
+ assertEquals(loader.getResource("com/example/demo/DemoApplication.class"), url);
+ assertEquals(loader.loadClass("com.example.demo.DemoApplication"),
+ loader.loadClass("com.example.demo.DemoApplication"));
+ assertNull(loader.getResource("demo/ApplicationNotExist.class"));
+ assertTrue(!loader.getResources("demo/ApplicationNotExist.class").hasMoreElements());
+ assertTrue(!loader.getResources("demo/ApplicationNotExist.class").hasMoreElements());
+
+ ClassNotFoundException ex = null;
+ ClassNotFoundException ex1 = null;
+ ClassNotFoundException ex2 = null;
+ ClassNotFoundException ex3 = null;
+ try {
+ loader.loadClass("demo.ApplicationNotExist");
+ } catch (ClassNotFoundException exception) {
+ ex = exception;
+ }
+ try {
+ loader.loadClass("demo.ApplicationNotExist");
+ } catch (ClassNotFoundException exception) {
+ ex1 = exception;
+ }
+ try {
+ loader.loadClass("demo.ApplicationNotExist");
+ } catch (ClassNotFoundException exception) {
+ ex2 = exception;
+ }
+ try {
+ loader.clearCache();
+ loader.loadClass("demo.ApplicationNotExist");
+ } catch (ClassNotFoundException exception) {
+ ex3 = exception;
+ }
+ assertNotNull(ex);
+ assertNotNull(ex1);
+ assertNotNull(ex2);
+ assertNotNull(ex3);
+
+ assertEquals(ex.getMessage(), ex1.getMessage());
+ assertNotSame(ex, ex2);
+ assertNotSame(ex1, ex2);
+ assertNotSame(ex, ex3);
+ assertNotSame(ex1, ex3);
+ assertNotSame(ex2, ex3);
+ ExecutorService executor = new ThreadPoolExecutor(5, 10, 60L, TimeUnit.SECONDS,
+ new LinkedBlockingQueue(100));
+ CountDownLatch countDownLatch = new CountDownLatch(100);
+ for (int i = 0; i < 100; i++) {
+ final String className = "notExits" + i;
+ executor.submit(() -> {
+ try {
+ loader.loadClass(className);
+ } catch (ClassNotFoundException e) {
+ }
+ countDownLatch.countDown();
+ });
+ }
+ countDownLatch.await();
+ Assert.assertEquals(99, loader.classCache.size());
+ }
+}
\ No newline at end of file
diff --git a/sofa-serverless-runtime/sofa-serverless-base-loader/sofa-serverless-spring-loader/src/test/java/com/alipay/sofa/serverless/spring/loader/JarLauncherTest.java b/sofa-serverless-runtime/sofa-serverless-base-loader/sofa-serverless-spring-loader/src/test/java/com/alipay/sofa/serverless/spring/loader/JarLauncherTest.java
new file mode 100644
index 000000000..84c3b4d49
--- /dev/null
+++ b/sofa-serverless-runtime/sofa-serverless-base-loader/sofa-serverless-spring-loader/src/test/java/com/alipay/sofa/serverless/spring/loader/JarLauncherTest.java
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alipay.sofa.serverless.spring.loader;
+
+import junit.framework.TestCase;
+
+public class JarLauncherTest extends TestCase {
+
+ public void test() throws Exception {
+ try {
+ JarLauncher.main(new String[] { "" });
+ } catch (Exception e) {
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/sofa-serverless-runtime/sofa-serverless-base-loader/sofa-serverless-spring-loader/src/test/resources/jars/demo-executable.jar b/sofa-serverless-runtime/sofa-serverless-base-loader/sofa-serverless-spring-loader/src/test/resources/jars/demo-executable.jar
new file mode 100644
index 000000000..93dc8f4b4
Binary files /dev/null and b/sofa-serverless-runtime/sofa-serverless-base-loader/sofa-serverless-spring-loader/src/test/resources/jars/demo-executable.jar differ
diff --git a/sofa-serverless-runtime/sofa-serverless-base-loader/sofa-serverless-spring-loader/src/test/resources/jars/demo.jar b/sofa-serverless-runtime/sofa-serverless-base-loader/sofa-serverless-spring-loader/src/test/resources/jars/demo.jar
new file mode 100644
index 000000000..fcb018d45
Binary files /dev/null and b/sofa-serverless-runtime/sofa-serverless-base-loader/sofa-serverless-spring-loader/src/test/resources/jars/demo.jar differ