1. 駆動力

Springアプリケーションでは、あるBeanを別のBeanに注入するのが非常に一般的です。 ただし、通常のオブジェクトにBeanを注入することが望ましい場合があります。たとえば、エンティティオブジェクト内からサービスへの参照を取得したい場合があります。

幸いなことに、それを達成することは見た目ほど難しくはありません。 次のセクションでは、@ConfigurableアノテーションとAspectJウィーバーを使用してを実行する方法を示します。

2. @Configurableアノテーション

このアノテーションにより、装飾されたクラスのインスタンスがSpringBeanへの参照を保持できるようになります。

2.1. SpringBeanの定義と登録

@Configurable アノテーションについて説明する前に、SpringBeanの定義を設定しましょう。

@Service
public class IdService {
    private static int count;

    int generateId() {
        return ++count;
    }
}

このクラスは@Serviceアノテーションで装飾されています。 したがって、コンポーネントスキャンを介してSpringコンテキストに登録できます。

そのメカニズムを有効にする簡単な構成クラスは次のとおりです。

@ComponentScan
public class AspectJConfig {
}

2.2. @Configurableを使用する

最も単純な形式では、要素なしで@Configurableを使用できます:

@Configurable
public class PersonObject {
    private int id;
    private String name;

    public PersonObject(String name) {
        this.name = name;
    }

    // getters and other code shown in the next subsection
}

@Configurable アノテーション、この場合、は、PersonObjectクラスをSpring駆動型構成に適格であることを示します。

2.3. アンマネージドオブジェクトへのSpringBeanの注入

他のSpringBeanの場合と同じように、IdServicePersonObjectに挿入できます。

@Configurable
public class PersonObject {
    @Autowired
    private IdService idService;

    // fields, constructor and getters - shown in the previous subsection

    void generateId() {
        this.id = idService.generateId();
    }
}

ただし、注釈は、ハンドラーによって認識および処理される場合にのみ役立ちます。 ここでAspectJウィーバーが活躍します。 具体的には、 AnnotationBeanConfigurerAspectは、@ Configurableの存在に基づいて動作し、必要な処理を実行します。

3. AspectJウィービングの有効化

3.1. プラグイン宣言

AspectJウィービングを有効にするには、最初にAspectJMavenプラグインが必要です。

<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>aspectj-maven-plugin</artifactId>
    <version>1.11</version>
    <!-- configuration and executions -->
</plugin>

また、追加の構成が必要です。

<configuration>
    <complianceLevel>1.8</complianceLevel>
    <Xlint>ignore</Xlint>
    <aspectLibraries>
        <aspectLibrary>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
        </aspectLibrary>
    </aspectLibraries>
</configuration>

最初に必要な要素はcomplianceLevelです。 1.8 の値は、ソースとターゲットの両方のJDKバージョンを1.8に設定します。 明示的に設定しない場合、ソースバージョンは1.3になり、ターゲットは1.1になります。 これらの値は明らかに時代遅れであり、最新のJavaアプリケーションには十分ではありません。

管理されていないオブジェクトにBeanを注入するには、spring-aspects.jarで提供されるAnnotationBeanConfigurerAspectクラスに依存する必要があります。 これはプリコンパイルされた側面であるため、プラグイン構成に含まれているアーティファクトを追加する必要があります。

このような参照されたアーティファクトは、プロジェクトの依存関係として存在する必要があることに注意してください。

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aspects</artifactId>
    <version>5.2.7.RELEASE</version>
</dependency>

spring-aspects の最新バージョンは、 MavenCentralにあります。

3.2. プラグインの実行

関連するすべてのクラスを織り込むようにプラグインに指示するには、次のexecutions構成が必要です。

<executions>
    <execution>
        <goals>
            <goal>compile</goal>
        </goals>
    </execution>
</executions>

プラグインのコンパイル目標は、デフォルトでコンパイルライフサイクルフェーズにバインドされていることに注意してください。

3.2. Bean構成

AspectJウィービングを有効にする最後のステップは、 @EnableSpringConfiguredを構成クラスに追加することです:

@ComponentScan
@EnableSpringConfigured
public class AspectJConfig {
}

追加のアノテーションはAnnotationBeanConfigurerAspectを構成し、PersonObjectインスタンスをSpringIoCコンテナーに登録します。

4. テスト

ここで、IdServiceBeanがPersonObjectに正常に注入されたことを確認しましょう。

@RunWith(SpringRunner.class)
@ContextConfiguration(classes = AspectJConfig.class)
public class PersonUnitTest {
    @Test
    public void givenUnmanagedObjects_whenInjectingIdService_thenIdValueIsCorrectlySet() {
        PersonObject personObject = new PersonObject("Baeldung");
        personObject.generateId();
        assertEquals(1, personObject.getId());
        assertEquals("Baeldung", personObject.getName());
    }
}

5. JPAエンティティへのBeanの注入

Springコンテナの観点からは、エンティティは通常のオブジェクトに他なりません。したがって、JPAエンティティにSpringBeanを注入することについて特別なことは何もありません。

ただし、JPAエンティティへの注入は一般的なユースケースであるため、さらに詳しく説明します。

5.1. エンティティクラス

エンティティクラスのスケルトンから始めましょう。

@Entity
@Configurable(preConstruction = true)
public class PersonEntity {
    @Id
    private int id;
    private String name;

    public PersonEntity() {
    }

    // other code - shown in the next subsection
}

@ConfigurableアノテーションのpreConstruction要素に注意してください。完全に構築される前に、オブジェクトに依存関係を挿入できます。

5.2. サービスインジェクション

これで、 PersonObject で行ったのと同様に、IdServicePersonEntityに挿入できます。

// annotations
public class PersonEntity {
    @Autowired
    @Transient
    private IdService idService;

    // fields and no-arg constructor

    public PersonEntity(String name) {
        id = idService.generateId();
        this.name = name;
    }

    // getters
}

@Transient アノテーションは、idServiceが永続化されないフィールドであることをJPAに通知するために使用されます。

5.3. 試験方法の更新

最後に、テストメソッドを更新して、サービスをエンティティに注入できることを示すことができます。

@Test
public void givenUnmanagedObjects_whenInjectingIdService_thenIdValueIsCorrectlySet() {
    // existing statements

    PersonEntity personEntity = new PersonEntity("Baeldung");
    assertEquals(2, personEntity.getId());
    assertEquals("Baeldung", personEntity.getName());
}

6. 警告

管理されていないオブジェクトからSpringコンポーネントにアクセスするのは便利ですが、多くの場合、そうすることはお勧めできません。

問題は、エンティティを含むアンマネージドオブジェクトが通常ドメインモデルの一部であるということです。 これらのオブジェクトは、さまざまなサービス間で再利用できるようにするためにのみデータを伝送する必要があります。

このようなオブジェクトにBeanを注入すると、コンポーネントとオブジェクトが結び付けられ、アプリケーションの保守と拡張が困難になる可能性があります。

7. 結論

このチュートリアルでは、SpringBeanをアンマネージドオブジェクトに注入するプロセスについて説明しました。 また、オブジェクトへの依存性注入に関連する設計上の問題についても言及しました。

実装コードは、GitHubにあります。