简体   繁体   中英

Interface to concrete class conditional instantiation in Spring

I have a Spring based Java application where a lot of classes use the following autowired interface.. they work off this interface at all places.

@Autowired
private IOperatingSystemManager m_operatingSystemManager;

Right now, there is only one implementation of the interface as follows:

@Component
public class WindowsManager implements IOperatingSystemManager 
{
 // Windows based shenanigans
}

And the application works as expected. Spring is happy. Everybody is happy. Alright, not everybody...

So, I want to add another concrete implementation of IOperatingSystemManager ..

@Component
public class LinuxManager implements IOperatingSystemManager 
{
 // Linux based shenanigans
}

What we want is the auto wiring of IOperatingSystemManager conditionally based on a properties file setting. (say.. os=windows.. basically something that is an arbitrary string and cannot be derived from system properties etc. simply because this is a dummy example. the actual managers are not OS related.)

I don't want to change any of the classes who have autowired to the interface and are working off the interface. All I need is for Spring to look at some logic that will dictate the Autowiring of the variables and wire up the right concrete instance for:

@Autowired
IOperatingSystemManager m_operatingSystemManager 

at all the gazillion places.

The documentation & web search talk about profiles, condition, bean factory, qualifiers etc.. but we don't want to use Profiles; and Qualifiers seem to be needing changes to all the interface variable annotations.

Factory methods look promising, but being new to Spring, couldn't find a crisp answer.

What is a simple and recommended way to achieve this?

Instead of scanning the WindowsManager class, create one concrete instance that implements the IOperatingSystemManager interface or another one, depending on the your logical conditions.

First, remove the @Component annotation from the WindowsManager class.

Then, create and scan this @Configuration class, which will act as a factory for your beans:

@Configuration
public class OperatingSystemManagerFactory {

    @Bean
    public IOperatingSystemManager getOperatingSystemManager() {
        if ( /* some logic that evaluates to true if windows */ ) {
            return new WindowsManager();
        } else {
            // Linux default option ;)
            return new LinuxManager();
        }
    }
}

With this solution, you shouldn't need to update anyone of your classes that reference the IOperatingSystemManager interface.

I dont know which version of spring you are using but you have options for this

http://www.intertech.com/Blog/spring-4-conditional-bean-configuration/

Here, as you can see, you can create a bean based on a condition that you can decide. It actully gave your example, Windows and Linux :), so i believe thats what you are looking for.

Edit:

If you are using spring-boot, you have some other Conditional annotations

http://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-developing-auto-configuration.html#boot-features-condition-annotations

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