首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >使用Buddy注册Spring反应库

使用Buddy注册Spring反应库
EN

Stack Overflow用户
提问于 2022-10-05 14:16:48
回答 1查看 114关注 0票数 0

我希望在运行时使用 Buddy创建和注册三个实体(实体/表的类、存储库接口和控制器类)。

代码语言:javascript
运行
复制
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的注册。

代码语言:javascript
运行
复制
@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());
  }
}
代码语言:javascript
运行
复制
beanService.registerBeanDefinition(tableClass.getSimpleName(), tableClass);
beanService.registerRepositoryBeanDefinition(tableClass.getSimpleName(), repositoryClass);

当我试图通过ApplicationContext访问存储库bean时,我会得到一个错误:MyRepository referenced from a method is not visible from class loader

代码语言:javascript
运行
复制
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时不会出现任何问题。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-10-06 07:11:46

您可能需要将类注入到目标类加载器中,而不是创建一个新的类加载器(这是默认的)。因此,与其:

代码语言:javascript
运行
复制
load(getClass().getClassLoader())

你会用:

代码语言:javascript
运行
复制
load(getClass().getClassLoader(), ClassLoadingStrategy.Default.INJECT)

对于Java 9+,您更愿意使用ClassLoadingStrategy.UsingLookup。它有一个工厂,可以在任何一个JVM版本上工作。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/73961761

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档