-
Notifications
You must be signed in to change notification settings - Fork 41.2k
Including spring-boot-devtools causes package-private getter on proxied class to return null #25367
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
When the target class is loaded by one class loader and the proxy class is loaded by another, the proxy can't access anything on the target that's package-private. This happens because package-private access requires code to be located in the same package and to have been loaded by the same class loader. To fix this automatically, I wonder if proxy creation needs to be a bit smarter about the ClassLoader that is uses when DevTools is in the picture. It's static class BeanClassClassLoaderAnnotationAwareAspectJAutoProxyCreator extends AnnotationAwareAspectJAutoProxyCreator {
@Override
protected Object createProxy(Class<?> beanClass, String beanName, Object[] specificInterceptors,
TargetSource targetSource) {
if (getBeanFactory() instanceof ConfigurableListableBeanFactory) {
// Package-private so can't call this
// AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) getBeanFactory(), beanName, beanClass);
}
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this);
if (!proxyFactory.isProxyTargetClass()) {
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
}
else {
evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
proxyFactory.addAdvisors(advisors);
proxyFactory.setTargetSource(targetSource);
customizeProxyFactory(proxyFactory);
proxyFactory.setFrozen(isFrozen());
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}
ClassLoader classLoader = beanClass.getClassLoader();
System.out.println("Proxying " + beanClass + " using ClassLoader " + classLoader);
return proxyFactory.getProxy(classLoader);
}
}; It can then be hacked into place using a BFPP: @Bean
static BeanFactoryPostProcessor hack() {
return (beanFactory) -> {
BeanDefinition definition = beanFactory.getBeanDefinition(AopConfigUtils.AUTO_PROXY_CREATOR_BEAN_NAME);
if (AnnotationAwareAspectJAutoProxyCreator.class.getName().equals(definition.getBeanClassName())) {
definition.setBeanClassName(BeanClassClassLoaderAnnotationAwareAspectJAutoProxyCreator.class.getName());
}
};
} With these changes in place, the sample works with
|
The problem can also be avoided by pulling spring-cloud-circuitbreaker-resilience4j up into the restart class loader using a
Ideally, users shouldn't have to know about this and it's only necessary when Sleuth is in the picture as it triggers the proxying of |
This issue was originally created in Sleuth: spring-cloud/spring-cloud-sleuth#1630
I investigated it a little bit, you can see my findings here: spring-cloud/spring-cloud-sleuth#1630 (comment)
Description:
It seems if the system class loader is wrapped (e.g.: spring-boot-devtools restarts the app using a
RestartClassLoader
), cglib produces incorrectClassLoaderData
causing proxied package-private methods returning null (public/protected is fine); please see the original issue and investigation details.Here's a sample project (uses
2.3.6.RELEASE
) that reproduces the issue: https://github.com/jonatan-ivanov/sleuth-gh-1630-minimal Please check the readme, the issue is hiding.The text was updated successfully, but these errors were encountered: