2016-05-24 47 views
1

我想轉換類,使Spring可以看到轉換後的註釋。這將允許我動態注入@Entity註釋,以便Spring Boot將其註冊爲數據使用的託管類型。ByteBuddy @Entity註解對Spring引導不可見ClassPathBeanDefinitionScanner basePackages掃描

註釋轉換工作正常,但Spring Boot似乎在缺少轉換版本的文件jar級別執行包掃描。這意味着Spring沒有看到註釋,因爲它正在分析JAR本身內的類文件的輸入流。

初始彈簧候選組件掃描如下:

 public Set<BeanDefinition> findCandidateComponents(String basePackage) { 
     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

     Resource[] resources = this.resourcePatternResolver.getResources(packageSearchPath); 

     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

     MetadataReader metadataReader = this.metadataReaderFactory.getMetadataReader(resource); 

     if (isCandidateComponent(metadataReader)) { 

     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

的getResources調用最終在PathMatchingResourcePatternResolver結束 - 在這種情況下doFindAllClassPathResources

是彈簧加載器ByteBuddy的範圍之外?

ClassLoader cl = getClassLoader(); 
    Enumeration<URL> resourceUrls = (cl != null ? cl.getResources(path) : ClassLoader.getSystemResources(path)); 

加載資源後,春加載類的元數據(一個缺少註釋)

MetadataReader metadataReader = this.metadataReaderFactory.getMetadataReader(resource); 

以上getMetadataReader方法調用最終在

final class SimpleMetadataReader implements MetadataReader 

結束了它使用ASM ClassReader訪問類和註釋元數據。這顯然沒有找到Bytebuddy發佈的@Entity註釋。

我不確定是否應該以某種方式將Classloader鏈接到ByteBuddy或重寫Springs SimpleMetadataReader以使我自己的實現由ByteBuddy支持。

有什麼建議嗎?我正在使用AgentBuilder轉換註釋,並在彈簧引導啓動之前運行它。

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組件註釋來設置類。

回答

1

「問題」是Spring查看原始類而不是加載的類。 Byte Buddy註冊了一個Java代理程序,它在加載時轉換類,但保留了Spring Boot無法識別的原始類文件。

另一個問題是,Spring在啓動時和加載類之前調查jar文件。這意味着,當Spring收集實體時,Byte Buddy代理甚至不活躍。

相反,春季應調查加載類的類加載器可能甚至不提供的類文件,但我想他們盡力挽留類的加載順序是什麼原因導致這樣的結果。

,唯一的選擇是要求字節好友重寫任何相關的jar文件在啓動時。您需要解析類路徑上的任何資源,並重新定義包含該文件的jar。關閉時,您應該通過複製原始jar狀態來重置狀態。

理想情況下,Spring會通過查看加載的類而不是解析類文件來添加掃描選項,因爲這兩種方法都有優缺點。根據我的經驗,查看加載的類無論如何都是更高性能的,因爲它避免了IO重複,所以該選項可以使代理識別以外的用例受益。

+0

這就是我想的。我可能會實現我自己的Spring ResourceLoader來做到這一點,或者實現我自己的MetadataReader來重新掃描類路徑上的資源,以獲取正確的引用。 與我上面的Bytebuddy代理有一個簡單的方法來確定它的掃描範圍嗎?它正在掃描所有內容,我想將它的掃描範圍限制在僅檢查basePackage中的類「com.system。*」,這可能會使其更快。當我想要完全忽略這些軟件包時,我看到成千上萬的IGNORES。 – John

+0

您可以爲這些包空間設置忽略匹配器。 Java工具API沒有辦法壓縮包,但Byte Buddy真的很便宜。一切都懶散地解決了。 –