How to do conditional auto-wiring in Spring?

ou can implement simple factory bean to do the conditional wiring. Such factory bean can contain complex conditioning logic:

<span class="kwd">public<span class="pln"> <span class="typ">MyBeanFactoryBean<span class="pln"> <span class="kwd">implements<span class="pln"> <span class="typ">FactoryBean<span class="pun"><<span class="typ">MyBean<span class="pun">><span class="pln"> <span class="pun">{<span class="pln">

    <span class="com">// Using app context instead of bean references so that the unused <span class="pln">
    <span class="com">// dependency can be left uninitialized if it is lazily initialized<span class="pln">
    <span class="lit">@Autowired<span class="pln">
    <span class="kwd">private<span class="pln"> <span class="typ">ApplicationContext<span class="pln"> applicationContext<span class="pun">;<span class="pln">

    <span class="kwd">public<span class="pln"> <span class="typ">MyBean<span class="pln"> getObject<span class="pun">()<span class="pln"> <span class="pun">{<span class="pln">
        <span class="typ">MyBean<span class="pln"> myBean <span class="pun">=<span class="pln"> <span class="kwd">new<span class="pln"> <span class="typ">MyBean<span class="pun">();<span class="pln">
        <span class="kwd">if<span class="pln"> <span class="pun">(<span class="kwd">true<span class="pln"> <span class="com">/* some condition */<span class="pun">)<span class="pln"> <span class="pun">{<span class="pln">
            myBean<span class="pun">.<span class="pln">setDependency<span class="pun">(<span class="pln">applicationContext<span class="pun">.<span class="pln">getBean<span class="pun">(<span class="typ">DependencyX<span class="pun">.<span class="kwd">class<span class="pun">));<span class="pln">
        <span class="pun">}<span class="pln"> <span class="kwd">else<span class="pln"> <span class="pun">{<span class="pln">
            myBean<span class="pun">.<span class="pln">setDependency<span class="pun">(<span class="pln">applicationContext<span class="pun">.<span class="pln">getBean<span class="pun">(<span class="typ">DependencyY<span class="pun">.<span class="kwd">class<span class="pun">));<span class="pln">
        <span class="pun">}<span class="pln">
        <span class="kwd">return<span class="pln"> myBean<span class="pun">;<span class="pln">
    <span class="pun">}<span class="pln">

    <span class="com">// Implementation of isSingleton => false and getObjectType<span class="pln">

<span class="pun">}</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>

Maybe a bit better approach is if you use factory bean to create the dependency bean in case you want to have only one such bean in your application context:

<span class="kwd">public<span class="pln"> <span class="typ">MyDependencyFactoryBean<span class="pln"> <span class="kwd">implements<span class="pln"> <span class="typ">FactoryBean<span class="pun"><<span class="typ">MyDependency<span class="pun">><span class="pln"> <span class="pun">{<span class="pln">

    <span class="kwd">public<span class="pln"> <span class="typ">MyDependency<span class="pln"> getObject<span class="pun">()<span class="pln"> <span class="pun">{<span class="pln">
        <span class="kwd">if<span class="pln"> <span class="pun">(<span class="kwd">true<span class="pln"> <span class="com">/* some condition */<span class="pun">)<span class="pln"> <span class="pun">{<span class="pln">
            <span class="kwd">return<span class="pln"> <span class="kwd">new<span class="pln"> <span class="typ">MyDependencyX<span class="pun">();<span class="pln">
        <span class="pun">}<span class="pln"> <span class="kwd">else<span class="pln"> <span class="pun">{<span class="pln">
            <span class="kwd">return<span class="pln"> <span class="kwd">new<span class="pln"> <span class="typ">MyDependencyY<span class="pun">();<span class="pln">
        <span class="pun">}<span class="pln">
    <span class="pun">}<span class="pln">

    <span class="com">// Implementation of isSingleton => false and getObjectType<span class="pln">

<span class="pun">}</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>

With SpEL there are many possibilities. Most common are system property based conditions:

<span class="tag"><bean<span class="pln"> <span class="atn">class<span class="pun">=<span class="atv">"com.example.MyBean"<span class="tag">><span class="pln">
    <span class="tag"><property<span class="pln"> <span class="atn">name<span class="pun">=<span class="atv">"dependency"<span class="pln"> <span class="atn">value<span class="pun">=<span class="atv">"#{systemProperties['foo'] == 'bar' ? dependencyX : dependencyY}"<span class="pln"> <span class="tag">/></span></span></span></span></span></span></span></span></span></property<span></span></span></span></span></span></span></bean<span></span>

You can have property placeholder resolve your bean reference. The dependency name can be part of the application configuration.

<span class="tag"><bean<span class="pln"> <span class="atn">class<span class="pun">=<span class="atv">"com.example.MyBean"<span class="tag">><span class="pln">
    <span class="tag"><property<span class="pln"> <span class="atn">name<span class="pun">=<span class="atv">"dependency"<span class="pln"> <span class="atn">ref<span class="pun">=<span class="atv">"${dependencyName}"<span class="pln"> <span class="tag">/></span></span></span></span></span></span></span></span></span></property<span></span></span></span></span></span></span></bean<span></span>

Usually the condition you want to evaluate means that a whole set of beans should or should not be registered. Spring profiles can be used for this:

<span class="com"><!-- Default dependency which is referred by myBean --><span class="pln">
<span class="tag"><bean<span class="pln"> <span class="atn">id<span class="pun">=<span class="atv">"dependency"<span class="pln"> <span class="atn">class<span class="pun">=<span class="atv">"com.example.DependencyX"<span class="pln"> <span class="tag">/><span class="pln">

<span class="tag"><beans<span class="pln"> <span class="atn">profile<span class="pun">=<span class="atv">"myProfile"<span class="tag">><span class="pln">
    <span class="com"><!-- Override dependency definition if myProfile is active --><span class="pln">
    <span class="tag"><bean<span class="pln"> <span class="atn">id<span class="pun">=<span class="atv">"dependency"<span class="pln"> <span class="atn">class<span class="pun">=<span class="atv">"com.example.DependencyY"<span class="pln"> <span class="tag">/></span></span></span></span></span></span></span></span></span></bean<span></span></span></span></span></span></span></span></span></beans<span></span></span></span></span></span></span></span></span></span></span></span></bean<span></span></span></span>

Other methods can mark the bean definition as lazy-init="true", but the definition will be still registered inside application context (and making your life harder when using unqualified autowiring). You can also use profiles with @Component based beans via @Profile annotation.

This is why Java based config is being so popular as you can do:

<span class="lit">@Bean<span class="pln">
<span class="kwd">public<span class="pln"> <span class="typ">MyBean<span class="pln"> myBean<span class="pun">()<span class="pln"> <span class="pun">{<span class="pln">
    <span class="typ">MyBean<span class="pln"> myBean <span class="pun">=<span class="pln"> <span class="kwd">new<span class="pln"> <span class="typ">MyBean<span class="pun">();<span class="pln">
    <span class="kwd">if<span class="pln"> <span class="pun">(<span class="kwd">true<span class="pln"> <span class="com">/* some condition */<span class="pun">)<span class="pln"> <span class="pun">{<span class="pln">
        myBean<span class="pun">.<span class="pln">setDependency<span class="pun">(<span class="pln">dependencyX<span class="pun">());<span class="pln">
    <span class="pun">}<span class="pln"> <span class="kwd">else<span class="pln"> <span class="pun">{<span class="pln">
        myBean<span class="pun">.<span class="pln">setDependency<span class="pun">(<span class="pln">dependencyY<span class="pun">());<span class="pln">
    <span class="pun">}<span class="pln">
    <span class="kwd">return<span class="pln"> myBean<span class="pun">;<span class="pln">
<span class="pun">}</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>

Of course you can use more or less all configuration methods in the java based config as well (via @Profile, @Value or @Qualifier + @Autowired).

Spring offers numerous hook points and SPIs, where you can participate in the application context life-cycle. This section requires a bit more knowledge of Spring’s inner workings.

BeanFactoryPostProcessors can read and alter bean definitions (e.g. property placeholder ${}resolution is implemented this way).

BeanPostProcessors can process bean instances. It is possible to check freshly created bean and play with it (e.g. @Scheduled annotation processing is implemented this way).

MergedBeanDefinitionPostProcessor is extension of bean post processor and can alter the bean definition just before it is being instantiated (@Autowired annotation processing is implemented this way).

UPDATE Oct 2015

  • Spring 4 has added a new method how to do conditional bean registration via @Conditionalannotation. That is worth checking as well.

  • Of course there are numerous other ways with Spring Boot alone via its @ConditionalOn*.

  • Also note that both @Import and @ComponentScan (and their XML counterparts) undergo property resolution (i.e. you can use ${}).

Original: https://www.cnblogs.com/goody9807/p/7659993.html
Author: PointNet
Title: How to do conditional auto-wiring in Spring?

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/540020/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球