1

Spring が変換された注釈を認識できるように、クラスを変換しようとしています。これにより、@Entity アノテーションを動的に注入して、Spring Boot がそれをデータ使用のためのマネージド型として登録できるようになります。

アノテーション変換は機能しますが、Spring Boot は変換されたバージョンが見つからないファイル jar レベルでパッケージ スキャンを実行しているようです。これは、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 とスプリングをきれいに統合したいと考えています。

4

1 に答える 1

1

「問題」は、Spring がロードされたクラスではなく、元のクラスを参照することです。Byte Buddy は、ロード時にクラスを変換する Java エージェントを登録しますが、Spring Boot が認識しない元のクラス ファイルを保持します。

もう 1 つの問題は、Spring が起動時およびクラスがロードされる前に jar ファイルを調査することです。これは、Spring がエンティティーを収集した時点で、Byte Buddy エージェントがまだアクティブでさえなかったことを意味します。

代わりに、クラスローダーはクラスファイルを提供しない可能性があるため、Spring はロードされたクラスを調査する必要がありますが、この結果の原因となるクラスのロード順序を保持しようとしていると思います。

唯一の代替手段は、Byte Buddy が起動時に関連する jar ファイルを書き換えるよう要求することです。クラスパス上のリソースを解析し、ファイルを含む jar を再定義する必要があります。シャットダウン時に、元の jar 状態をコピーして状態をリセットする必要があります。

どちらのアプローチにも長所と短所があるため、理想的には、Spring は、クラス ファイルを解析する代わりに、ロードされたクラスを見てスキャンするオプションを追加します。私の経験から、ロードされたクラスを見ることは、IO の重複を回避するため、とにかくパフォーマンスが向上するため、オプションはエージェントの認識を超えたユースケースに利益をもたらす可能性があります。

于 2016-05-24T12:20:03.083 に答える