Don't use RestartClassLoader when proxying classes it did not load
Fixes gh-19010 Fixes gh-25367
This commit is contained in:
parent
3cc36d518d
commit
952ac7b8d2
|
@ -70,6 +70,7 @@ dependencies {
|
||||||
testImplementation("org.thymeleaf:thymeleaf-spring5")
|
testImplementation("org.thymeleaf:thymeleaf-spring5")
|
||||||
testImplementation("nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect")
|
testImplementation("nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect")
|
||||||
|
|
||||||
|
testRuntimeOnly("org.aspectj:aspectjweaver")
|
||||||
testRuntimeOnly("org.yaml:snakeyaml")
|
testRuntimeOnly("org.yaml:snakeyaml")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -173,6 +173,11 @@ public class RestartClassLoader extends URLClassLoader implements SmartClassLoad
|
||||||
return defineClass(name, b, 0, b.length, protectionDomain);
|
return defineClass(name, b, 0, b.length, protectionDomain);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ClassLoader getOriginalClassLoader() {
|
||||||
|
return getParent();
|
||||||
|
}
|
||||||
|
|
||||||
private URL createFileUrl(String name, ClassLoaderFile file) {
|
private URL createFileUrl(String name, ClassLoaderFile file) {
|
||||||
try {
|
try {
|
||||||
return new URL("reloaded", null, -1, "/" + name, new ClassLoaderFileURLStreamHandler(file));
|
return new URL("reloaded", null, -1, "/" + name, new ClassLoaderFileURLStreamHandler(file));
|
||||||
|
|
|
@ -20,6 +20,7 @@ import java.io.File;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.net.MalformedURLException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.net.URLClassLoader;
|
import java.net.URLClassLoader;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
@ -36,7 +37,14 @@ import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.io.TempDir;
|
import org.junit.jupiter.api.io.TempDir;
|
||||||
|
|
||||||
import org.springframework.aop.framework.ProxyFactory;
|
import org.springframework.aop.framework.ProxyFactory;
|
||||||
|
import org.springframework.aop.support.AopUtils;
|
||||||
import org.springframework.boot.devtools.restart.classloader.ClassLoaderFile.Kind;
|
import org.springframework.boot.devtools.restart.classloader.ClassLoaderFile.Kind;
|
||||||
|
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.EnableAspectJAutoProxy;
|
||||||
|
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import org.springframework.util.FileCopyUtils;
|
import org.springframework.util.FileCopyUtils;
|
||||||
import org.springframework.util.StreamUtils;
|
import org.springframework.util.StreamUtils;
|
||||||
|
|
||||||
|
@ -210,6 +218,20 @@ class RestartClassLoaderTests {
|
||||||
// Warning would happen outside the boundary of the test
|
// Warning would happen outside the boundary of the test
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void packagePrivateClassLoadedByParentClassLoaderCanBeProxied() throws MalformedURLException {
|
||||||
|
new ApplicationContextRunner()
|
||||||
|
.withClassLoader(new RestartClassLoader(ExampleTransactional.class.getClassLoader(),
|
||||||
|
new URL[] { this.sampleJarFile.toURI().toURL() }, this.updatedFiles))
|
||||||
|
.withUserConfiguration(ProxyConfiguration.class).run((context) -> {
|
||||||
|
assertThat(context).hasNotFailed();
|
||||||
|
ExampleTransactional transactional = context.getBean(ExampleTransactional.class);
|
||||||
|
assertThat(AopUtils.isCglibProxy(transactional)).isTrue();
|
||||||
|
assertThat(transactional.getClass().getClassLoader())
|
||||||
|
.isEqualTo(ExampleTransactional.class.getClassLoader());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private String readString(InputStream in) throws IOException {
|
private String readString(InputStream in) throws IOException {
|
||||||
return new String(FileCopyUtils.copyToByteArray(in));
|
return new String(FileCopyUtils.copyToByteArray(in));
|
||||||
}
|
}
|
||||||
|
@ -218,4 +240,32 @@ class RestartClassLoaderTests {
|
||||||
return (enumeration != null) ? Collections.list(enumeration) : Collections.emptyList();
|
return (enumeration != null) ? Collections.list(enumeration) : Collections.emptyList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Configuration(proxyBeanMethods = false)
|
||||||
|
@EnableAspectJAutoProxy(proxyTargetClass = true)
|
||||||
|
@EnableTransactionManagement
|
||||||
|
static class ProxyConfiguration {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
ExampleTransactional exampleTransactional() {
|
||||||
|
return new ExampleTransactional();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static class ExampleTransactional implements ExampleInterface {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
public String doIt() {
|
||||||
|
return "hello";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ExampleInterface {
|
||||||
|
|
||||||
|
String doIt();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue