我希望在运行时使用 Buddy创建和注册三个实体(实体/表的类、存储库接口和控制器类)。
Class<?> tableClass =
new ByteBuddy()
.subclass(Object.class, ConstructorStrategy.Default.DEFAULT_CONSTRUCTOR)
.name(className)
.annotateType(getTableAnnotation(tableName))
.defineField("id", UUID.class, Visibility.PRIVATE)
.annotateField(getIdAnnotation())
.defineMethod("getId", UUID.class, Visibility.PUBLIC)
.intercept(FieldAccessor.ofBeanProperty())
.defineMethod("setId", void.class, Visibility.PUBLIC)
.withParameter(UUID.class)
.intercept(FieldAccessor.ofBeanProperty());
.defineField("name", String.class, Visibility.PRIVATE)
.defineMethod("getName", String.class, Visibility.PUBLIC)
.intercept(FieldAccessor.ofBeanProperty())
.defineMethod("setName", void.class, Visibility.PUBLIC)
.withParameter(String.class)
.intercept(FieldAccessor.ofBeanProperty())
.make()
.load(getClass().getClassLoader())
.getLoaded();
TypeDescription.Generic repositoryTypeDescription =
TypeDescription.Generic.Builder.parameterizedType(
R2dbcRepository.class, tableClass, UUID.class)
Class<? extends Object> repositoryClass =
new ByteBuddy()
.makeInterface(repositoryTypeDescription)
.name(tableClass.getCanonicalName() + "Repository")
.make()
.load(tableClass.getClassLoader())
.getLoaded();
我还有一个服务类,它完成所有bean的注册。
@Service
public class BeanRegisterService {
@Autowired private BeanFactory beanFactory;
@Autowired private R2dbcEntityTemplate entityTemplate;
public <T> void registerBean(String beanName, T bean) {
((ConfigurableBeanFactory) beanFactory).registerSingleton(beanName, bean);
}
public <T> void registerBeanDefinition(String beanName, Class<T> rootBeanClass) {
BeanDefinitionBuilder beanDefinitionBuilder =
BeanDefinitionBuilder.rootBeanDefinition(rootBeanClass);
((DefaultListableBeanFactory) beanFactory)
.registerBeanDefinition(beanName, beanDefinitionBuilder.getBeanDefinition());
}
public <T> void registerRepositoryBeanDefinition(
String entityBean, Class<T> repositoryInterface) {
BeanDefinitionBuilder beanDefinitionBuilder =
BeanDefinitionBuilder.rootBeanDefinition(R2dbcRepositoryFactoryBean.class)
.addConstructorArgValue(repositoryInterface)
.addPropertyValue("databaseClient", entityTemplate.getDatabaseClient())
.addPropertyValue("dataAccessStrategy", entityTemplate.getDataAccessStrategy());
((DefaultListableBeanFactory) beanFactory)
.registerBeanDefinition(
repositoryInterface.getSimpleName(), beanDefinitionBuilder.getBeanDefinition());
}
}
beanService.registerBeanDefinition(tableClass.getSimpleName(), tableClass);
beanService.registerRepositoryBeanDefinition(tableClass.getSimpleName(), repositoryClass);
当我试图通过ApplicationContext
访问存储库bean时,我会得到一个错误:MyRepository referenced from a method is not visible from class loader
。
Caused by: java.lang.IllegalArgumentException: com.example.MyRepository referenced from a method is not visible from class loader
at java.base/java.lang.reflect.Proxy$ProxyBuilder.ensureVisible(Proxy.java:858) ~[na:na]
at java.base/java.lang.reflect.Proxy$ProxyBuilder.validateProxyInterfaces(Proxy.java:681) ~[na:na]
at java.base/java.lang.reflect.Proxy$ProxyBuilder.<init>(Proxy.java:627) ~[na:na]
at java.base/java.lang.reflect.Proxy.lambda$getProxyConstructor$1(Proxy.java:426) ~[na:na]
at java.base/jdk.internal.loader.AbstractClassLoaderValue$Memoizer.get(AbstractClassLoaderValue.java:329) ~[na:na]
at java.base/jdk.internal.loader.AbstractClassLoaderValue.computeIfAbsent(AbstractClassLoaderValue.java:205) ~[na:na]
at java.base/java.lang.reflect.Proxy.getProxyConstructor(Proxy.java:424) ~[na:na]
at java.base/java.lang.reflect.Proxy.newProxyInstance(Proxy.java:1006) ~[na:na]
at org.springframework.aop.framework.JdkDynamicAopProxy.getProxy(JdkDynamicAopProxy.java:126) ~[spring-aop-5.3.22.jar:5.3.22]
at org.springframework.aop.framework.ProxyFactory.getProxy(ProxyFactory.java:110) ~[spring-aop-5.3.22.jar:5.3.22]
at org.springframework.data.repository.core.support.RepositoryFactorySupport.getRepository(RepositoryFactorySupport.java:371) ~[spring-data-commons-2.7.2.jar:2.7.2]
at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.lambda$afterPropertiesSet$5(RepositoryFactoryBeanSupport.java:323) ~[spring-data-commons-2.7.2.jar:2.7.2]
at org.springframework.data.util.Lazy.getNullable(Lazy.java:231) ~[spring-data-commons-2.7.2.jar:2.7.2]
at org.springframework.data.util.Lazy.get(Lazy.java:115) ~[spring-data-commons-2.7.2.jar:2.7.2]
at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.afterPropertiesSet(RepositoryFactoryBeanSupport.java:329) ~[spring-data-commons-2.7.2.jar:2.7.2]
at org.springframework.data.r2dbc.repository.support.R2dbcRepositoryFactoryBean.afterPropertiesSet(R2dbcRepositoryFactoryBean.java:179) ~[spring-data-r2dbc-1.5.2.jar:1.5.2]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1863) ~[spring-beans-5.3.22.jar:5.3.22]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1800) ~[spring-beans-5.3.22.jar:5.3.22]
... 15 common frames omitted
与上述示例相比,表类具有更多的动态定义,并且在构建时不知道;因此,所有类都必须根据需要在运行时生成。
我遗漏了什么?
我的代码是基于以下内容的答案:
Byte Buddy Runtime generation for spring boot JPA repository classes
How to register custom JPA interface using bytebuddy
编辑:
如果我用repositoryClass
加载this.getClass()
,它不会到达ProxyBuilder。它与ClassNotFound的崩溃要快得多。将ClassLoadingStrategy转换为persistent也没有帮助。另一方面,加载tableClass
bean时不会出现任何问题。
发布于 2022-10-06 07:11:46
您可能需要将类注入到目标类加载器中,而不是创建一个新的类加载器(这是默认的)。因此,与其:
load(getClass().getClassLoader())
你会用:
load(getClass().getClassLoader(), ClassLoadingStrategy.Default.INJECT)
对于Java 9+,您更愿意使用ClassLoadingStrategy.UsingLookup。它有一个工厂,可以在任何一个JVM版本上工作。
https://stackoverflow.com/questions/73961761
复制相似问题