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-core arklet-springboot-starter sofa-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