简体   繁体   中英

How can I qualify an autowired property with a variable from a config file using annotations?

My specific problem is that I have configured two beans that implement the same interface and I have a third bean that has a property of that interface's type. I inject the property using a config property. So, assuming RemoteDataSource and LocalDataSource implement IDataSource and dao1 has a property of type IDataSource, my XML config might look like this:

<bean id="datasource1" class="com.foo.RemoteDataSource">
  <property name="url">${url}</property>
</bean>
<bean id="datasource2" class="com.foo.LocalDataSource">
  <property name="path">${filepath}</property>
</bean>
<bean id="dao1" class="com.foo.MyDAO">
  <property name="dataSource">${datasource}</property>
</bean>

With url, filepath and datasource being defined in an included properties file. We are now making a push for annotation-driven configuration and I'm not sure how to annotate my dao to put the data source configured in the property file. I want to do something like this, but it is evidently not allowed:

@Autowired
@Qualifier("${datasource}")
public void setDataSource(IDataSource datasource) {...}

NB: this is spring 3

Do you have any xml configuration? I'd assume you do as you have a data source.

Hard code the Qualifier for the datasource and then create an alias in your xml configuratation which aliases based on the property.

Something like

@Autowired
@Qualifier("designatedDatasource")
public void setDataSource(IDataSource datasource) {...}

And then in xml:

<alias name="${dataSource}" alias="designatedDatasource"/>

I'm pretty sure the spring developers considered allowing you to do it the way you specified, but personally, I would prefer not to. Working out where it is getting that $dataSource value from could end up quite tricky. I also think that supporting configurable properties in annotations would complexify things too much and allow for too much potential confusion.

My solution was thus:

@Autowired
public void setDataProviders(Map<String,IDataProvider> dataProviders) {
    this.dataProviders = dataProviders;
}

@Autowired
@Value("${cms}")
public void setDataProviderName(String dataProviderName) {
    this.dataProviderName = dataProviderName;
}

public IDataProvider getDataProvider() {
    return dataProviders.get(dataProviderName);
}

NB: I changed that naming to DataProvider to disambiguate from the canonical DataSource which this isn't. It's actually just a homemade REST client.

I did some work around for the similar problem I had.

My problem was I had three implementation for the Service say ServiceImpl1,ServiceImpl2 and ServiceImpl3 and in the properties file for place holder my.serviceImpl I may have values like

my.serviceImpl = serviceImpl1

or

my.serviceImpl = serviceImpl2

or

my.serviceImpl = serviceImpl3

So in my controller I should be able to use @Qualifier(${my.my.serviceImpl}) but this didn't worked, I even tried @value for but it also failed.

So finally I defined bean in my ApplicationConf.java as

@Bean(name = "myServiceImpl")
public Service myService() {

    String beanName = environment.getProperty("my.serviceImpl");

        if (beanName.equals("serviceImpl1")) {
            return new serviceImpl1();
        }
        else if(beanName.equals("serviceImpl2")){
            return new serviceImpl2();
        }
        else if(beanName.equals("serviceImpl3")){
            return new serviceImpl3();
        }


}

And in my controller I used qualifier as

@Autowired
@Qualifier("myServiceImpl")
Service myService;

Not sure though if this is the best way to do it.

I don't think this is possible. Even in CDI, which is entirely annotation-driven, switching beans depending on configuration is done via xml.

For Spring 3.1 your problem is solved by Spring profiles :

<bean id="dao1" class="com.foo.MyDAO">
   <property name="dataSource">${datasource}</property>
</bean>

<beans profile="remote">
   <bean id="datasource1" class="com.foo.RemoteDataSource">
      <property name="url">${url}</property>
   </bean>
<beans>

<beans profile="local">
    <bean id="datasource2" class="com.foo.LocalDataSource">
      <property name="path">${filepath}</property>
    </bean>
<beans>

No @Qualifier needed, only one IDataSource in every profile.

@Autowired
public void setDataSource(IDataSource datasource) {...}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM