conditional beans using spring

2020-08-10 19:15发布

问题:

I am trying to write a ValidatorFactory which will give me a validator based on its type

public Validator getNewValidator(ValidatorType type){

    switch:
         case a : new Validator1();
         break;
          case b : new Validator2();
        break;

}

I want to write using spring xml beans definition

I can use method injection but it will let me create only one object and the method does

not take any arguments.

I don't want to use FactoryBean.. I am just looking whether we can do this using spring xml

bean definition.

回答1:

you can do conditional bean injection with plain xml. The "ref" attribute can be triggered by property values from a property file and thus create conditional beans depending on property values. This feature is not documented but it works perfect.

<bean id="validatorFactory" class="ValidatorFactory">
<property name="validator" ref="${validatorType}" />
</bean>

<bean id="validatorTypeOne" class="Validator1" lazy-init="true" />
<bean id="validatorTypeTwo" class="Validator2" lazy-init="true" />

And the content of the property file would be:

validatorType=validatorTypeOne

To use the property file in your xml just add this context to the top of your spring config

<context:property-placeholder location="classpath:app.properties" />


回答2:

For complex cases (more complex than the one exposed), Spring JavaConfig could be your friend.



回答3:

If you are using annotation (@Autowired, @Qualifier etc) instead of xml, you are not able to make conditional beans work (at least at current version 3). This is due to @Qualifier does not support expression

@Qualifier(value="${validatorType}")

More information is at https://stackoverflow.com/a/7813228/418439



回答4:

I had an slightly different requirements. In my case I wanted to have encoded password in production but plain text in development. Also, I didn't have access to parent bean parentEncoder. This is how I managed to achieve that:

<bean id="plainTextPassword" class="org.springframework.security.authentication.encoding.PlaintextPasswordEncoder"/>
<bean id="shaPassword" class="org.springframework.security.authentication.encoding.ShaPasswordEncoder">
    <constructor-arg type="int" value="256"/>
</bean> 

<bean id="parentEncoder" class="org.springframework.aop.framework.ProxyFactoryBean"> 
  <property name="targetSource"> 
    <bean class="org.springframework.aop.target.HotSwappableTargetSource"> 
      <constructor-arg ref="${password.encoding}Password"/> 
    </bean> 
  </property> 
</bean>

Of course, I defined password.encoding in a property file with possible values as sha or plainText.



回答5:

You should be able to do this:

<bean id="myValidator" factory-bean="validatorFactory" factory-method="getNewValidator" scope="prototype">
    <constructor-arg><ref bean="validatorType"/></constructor-arg>
</bean>

<bean id="validatorType" ... />

Of course, it uses an automatically configured FactoryBean underneath but you avoid any Spring dependency in your code.