简体   繁体   中英

Is it possible to avoid compile-time dependency using spring Java @Configuration?

Is there a way to declare beans using spring Java based configuration without compile-time checking, so that I can provide interface implementation at runtime?

For example, when I write a JAX-RS client, I use the JAX-RS API without referring to a specific API implementation. In my spring XML configuration, I then declare the actual implementation of the JAX-RS API that I want to use, eg Jersey, when setting up the client bean. Because XML based configuration is used (and verified) during runtime, I do not need compile time dependency to Jersey. This allows me to have a <scope>runtime</scope> Maven dependency to Jersey, while I must have a <scope>compile</scope> dependency to the JAX-RS API. The benefit of this approach is that if I accidentally use the implementation, my application won't compile with Maven.

On the other hand, if I use the Java based spring configuration (using @Configuration ) to declare my beans, I must have a compile time dependency to the implementation of the API because the configuration itself is compiled.

If this is not possible to achieve with Java based configuration, are there any alternatives (besides using a combination of XML and Java based configuration which I know is possible)?

Short answer :

Yes it's possible :)

Long answer :

Besides the described ways, Spring Boot provides this out of the box.

It's the way Spring Boot does it's autoconfiguration magic. A lot of options are only provided in the core Spring Boot Starter library only during compile time. But became active with the actual implementation when the necessary libraries (or to be precise classes) are available on the class path during runtime.

Spring Boot provides for this purpose specialized annotation: @ConditionalOnClass . I would recommend to read this section of Spring Boots documentation to get familiar with the topic.

For your java configuration to compile, all the classes included in it have to be accessible at compile time.

You could move that @Configuration root class to another maven module, compile your main module and that specific module separately and don't have the dependencies you don't want to have in your main module; then reference that specific @Configuration root class loading your Spring context (for example, via contextConfigLocation context parameter).

Or you could use dirty Class.forName() + newInstance() techniques in your @Configuration.

Of course, the option you mention (a mix of @Configuration + XML-based configs) is also possible.

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