我正在尝试转换类,以便 Spring 可以看到转换后的注释。这将允许我动态注入 @Entity 注释,以便 Spring Boot 将其注册为托管类型以供数据使用。
注释转换有效,但 Spring Boot 似乎在文件 jar 级别执行包扫描,缺少转换后的版本。这意味着 Spring 看不到注释,因为它正在分析 JAR 本身内的类文件的输入流。
初始spring候选组件扫描如下:
public Set<BeanDefinition> findCandidateComponents(String basePackage) {
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Resource[] resources = this.resourcePatternResolver.getResources(packageSearchPath);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
MetadataReader metadataReader = this.metadataReaderFactory.getMetadataReader(resource);
if (isCandidateComponent(metadataReader)) {
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
getResources 调用最终以 PathMatchingResourcePatternResolver 结束 - doFindAllClassPathResources
在这种情况下,Springs 类加载器是否超出了 ByteBuddy 的范围?
ClassLoader cl = getClassLoader();
Enumeration<URL> resourceUrls = (cl != null ? cl.getResources(path) : ClassLoader.getSystemResources(path));
加载资源后,Spring 加载类元数据(缺少注释)
MetadataReader metadataReader = this.metadataReaderFactory.getMetadataReader(resource);
上面的 getMetadataReader 方法调用最终结束于
final class SimpleMetadataReader implements MetadataReader
它使用 ASM ClassReader 来访问类和注释元数据。这显然没有找到Bytebuddy放置的@Entity注解。
我不确定是否应该以某种方式将 Classloader 链接到 Bytebuddy 或覆盖 Springs SimpleMetadataReader 以让我自己的实现由 ByteBuddy 支持。
有什么建议么?我正在使用 AgentBuilder 来转换注释并在 spring boot 启动之前运行它。
public static void main(String[] args) {
EntityAgent.install(ByteBuddyAgent.install());
InversionContainer.startInversion(args);
}
为了完整性,我的 ByteBuddy Impl:
**
* Transform all Non-Abstract Classes which extend BaseEntity
* to have the annotation Entity
*/
public class EntityAgent {
/**
* Installs the agent builder to the instrumentation API.
*/
public static void install(Instrumentation inst) {
createAgentBuilder().installOn(inst);
}
/**
* Creates the AgentBuilder that will redefine any class extending BaseEntity
*/
private static AgentBuilder createAgentBuilder() {
return new AgentBuilder.Default()
.with(toSystemError())
.with(AgentBuilder.RedefinitionStrategy.REDEFINITION)
.with(AgentBuilder.InitializationStrategy.SelfInjection.EAGER)
.with(AgentBuilder.TypeStrategy.Default.REDEFINE)
.type(getClassMatcher())
.transform(getTransformer());
}
/**
* Set Entity annotation on Class
*/
private static AgentBuilder.Transformer getTransformer() {
return (builder, typeDescription, classloader) -> builder.annotateType(AnnotationDescription.Builder.ofType(Entity.class).build());
}
/**
* Find any non-abstract class that extends BaseEntity
*/
private static ElementMatcher.Junction<TypeDescription> get ClassMatcher() {
return ElementMatchers.isSubTypeOf(BaseEntity.class).and(ElementMatchers.not(ElementMatchers.isAbstract()));
}
}
我回顾了Unable to Instrument apache httpclient using javaagent for spring boot uber jar application
如果您需要更多实施细节,请告诉我。我想干净地将 bytebuddy 与 spring 集成,这样我就可以使用 spring 组件注释来检测类。