简体   繁体   中英

Spring autowire using annotations and a type defined in a properties file?

My goal is a framework where concrete types of beans can be easily changed by a properties file. I also prefer annotations to XML. Ideally I'd to use a combination of @Resource and SpEL like this:

@Resource(type="#{myProperties['enabled.subtype']}")
SomeInterface foo;

where I've loaded myProperties with a PropertiesFactoryBean or <util:properties> from a file that includes:

enabled.type = com.mycompany.SomeClassA; // which implements SomeInterface

This doesn't work because the argument of type must be a literal, ie, no SpEL allowed. What's the best practice here?

Update: See my answer below.

I think it is not possible, the solution I tend to adopt is to use a factory that creates the different objects depending on a configuration property (enabled.type in your example).

A second alternative could be to use injection by name:

@Resource(name="beanName")

And last, if you use Spring 3.1+ you can try to use profiles, and have different bean sets in different profiles, if that solves your problem.

This is exactly the use case for Spring Java Configuration.

http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/beans.html#beans-java

Or you can alternatively make a Factory.

Using: org.springframework.beans.factory.FactoryBean<SomeInterface>

The name of the bean that implements FactoryBean will be seen as a "SomeInterface" even though its not.

Spring's Java Configuration and Bean Definition Profiles turn out to be exactly what I was looking for (thanks @Adam-Gent and @Guido-Garcia). The former seems necessary for the dynamic element, and the latter promotes a better practice.

Here's a solution with Java config and properties:

@Configuration
public class SomeClassConfig {
    @Value("#{myProperties['enabled.subtype']}")
    public Class enabledClass;

    @Bean SomeInterface someBean() 
              throws InstantiationException, IllegalAccessException {
       return (SomeInterface) enabledClass.newInstance();
    }   
}

Here's a slightly less dynamic solution with profiles.

@Configuration
@Profile("dev")
public class DevelopmentConfig {
    @Bean SomeInterface someBean() {
       return new DevSubtype();
    }   
}

@Configuration
@Profile("prod")
public class ProductionConfig {
    @Bean SomeInterface someBean() {
       return new ProdSubtype();
    }   
}

With profiles, the active profile(s) are declared using one of a variety of methods such as via system property, JVM property, web.xml, etc. For example, with a JVM property:

-Dspring.profiles.active="dev"

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