web-dev-qa-db-ja.com

Springを使用した自己注入

BeanNotFoundExceptionで失敗したSpring 3.xで次のコードを試してみましたが、前に尋ねた質問の答えに従っているはずです- Springを使用して同じクラスを注入できますか?

@Service
public class UserService implements Service{
    @Autowired
    private Service self;
}

Java 6でこれを試していたので、次のコードがうまくいくことがわかりました。

@Service(value = "someService")
public class UserService implements Service{
    @Resource(name = "someService")
    private Service self;
}

しかし、循環依存関係をどのように解決するのか理解できません。

編集:
エラーメッセージを次に示します。 OPは、回答の1つに関するコメントでそれについて言及しました。

原因:org.springframework.beans.factory.NoSuchBeanDefinitionException:依存関係のタイプ[com.spring.service.Service]の一致するBeanが見つかりません。この依存関係の自動配線候補として適格な少なくとも1つのBeanが必要です。依存関係の注釈:{@ org.springframework.beans.factory.annotation.Autowired(required = true)}

57
Premraj

更新:2016年2月

自己の自動配線は、Spring Framework 4.3で正式にサポートされます。実装はこの GitHub commit で見ることができます。


自分で自動配線できない決定的な理由は、SpringのDefaultListableBeanFactory.findAutowireCandidates(String, Class, DependencyDescriptor)メソッドの実装が可能性を明示的に除外しているからです。これは、このメソッドからの次のコードの抜粋で確認できます。

for (String candidateName : candidateNames) {
    if (!candidateName.equals(beanName) && isAutowireCandidate(candidateName, descriptor)) {
        result.put(candidateName, getBean(candidateName));
    }
}

参考:Beanの名前(つまり、自身を自動接続しようとしているBean)はbeanNameです。そのBeanは実際には自動配線の候補ですが、上記のif条件はfalseを返します(実際にcandidateNamebeanNameと等しいため)。したがって、Beanとそれ自体を単に自動接続することはできません(少なくともSpring 3.1 M1の時点ではそうではありません)。

ここで、これが意味論的に言えば振る舞いを意図したものであるかどうかについては、別の質問です。 ;)

ユルゲンに聞いて、彼が何を言っているのか見てみましょう。

よろしく、

サム(Core Spring Committer)

追伸@Autowiredを使用したタイプによる自動自動配線のサポートを検討するために、Spring JIRAの問題を公開しました。この問題を自由に見たり、投票してください: https://jira.springsource.org/browse/SPR-845

44
Sam Brannen

ところで、自己呼び出しの問題に対するよりエレガントなソリューションは、トランザクションプロキシ(または使用しているAOPで導入されたプロキシ)にAspectJ Load-Time Weavingを使用することです。

たとえば、アノテーション駆動型のトランザクション管理では、次のように「aspectj」モードを使用できます。

<tx:annotation-driven mode="aspectj" />

デフォルトモードは「プロキシ」(つまり、JDK動的プロキシ)であることに注意してください。

よろしく、

サム

1
Sam Brannen

オブジェクト自体からAOPプロキシを取得する 質問は、特殊なケースに適している可能性のあるAopContext.currentProxy()を使用した別のハッキング手法を提案します。

1
Vadzim

上記のコードを考えると、循環依存関係は見当たりません。 ServiceのインスタンスをUserServiceに注入します。挿入されたサービスの実装は、必ずしも別のUserServiceである必要はないため、循環依存関係はありません。

UserServiceをUserServiceに注入する理由はわかりませんが、これが理論的な試用などであることを願っています。

1
Stijn Geukens

Springはオブジェクトを作成および構成し、Beanルックアップコンテキストに配置するようです。しかし、Javaの場合は、オブジェクトを作成し、名前と、コンテキストで見つかった名前でオブジェクトを検索する際の設定中にそれを結び付けると思います。

0
Krishna

ちょうど別のアプローチ:

@EnableAsync
@SpringBootApplication
public class Application {

    @Autowired
    private AccountStatusService accountStatusService;

    @PostConstruct
    private void init() {
        accountStatusService.setSelf(accountStatusService);
    }
}

@Service
public class AccountStatusService {
    private AccountStatusService self;

    public void setSelf(AccountStatusService self) {
        this.self = self;
    }
}

これにより、サービスはプロキシになります。これは、内部で非同期メソッドを操作するために行いました。

私は@sinuhepopソリューションを試しました:

@PostConstruct
private void init() {
    self = applicationContext.getBean(UserService.class);
}

インジェクションを行いましたが、サービスはプロキシ内になく、メソッドは新しいスレッドで実行されていませんでした。そのアプローチで、それは私が望むように動作します。

0
Gilson