in Coding, Java, Spring

Why using Spring’s @Value annotation is bad

@Value

Configuration is an important topic of every application which has more than a couple of hundred lines of code. In case you are using Spring, you would typically use Spring’s @Value annotation to load values from a Java properties file. This could look like this:

If you do so, Spring would inject the value for the key my.config.property.key from your properties file right into your class and you are done. Easy! Maybe too easy…

What will happen…

What will happen when you use this technique through your application? Well, whenever you need some property, you will inject it. You will inject it in services, controllers and components and you will properly inject the same property in different classes. That’s easy and absolutely what the mechanism is about.

However, this means nothing else than scattering your configuration about your whole application. Every class can pick a couple of properties to use. You will have no idea or control which class is using which properties. You will end-up with doing a full text search on your project to find out where a single key is used. You will have a lot of fun if you want to rename one of those keys or when you need to set each and every property for each and every class in your unit tests.

Configuration is an service

Instead of this, configuration should be an encapsulated service of your application such as any other functionality, too. You encapsulate persistence in DAOs, you encapsulate REST services in controllers and you encapsulate security in authenticators. So why not encapsulating configuration?

If you do so, you will have a single point of responsibility to load and get your configuration from. As any other service, you can easily change the implementation. Maybe you don’t want to load your properties from a properties file, but from a database or web service! If you encapsulate your configuration in a service, that’s not a big deal. You just change the implementation. You can also write some unit tests for your configuration (Why not? Configuration can become complicated when properties are combined or a certain configuration is determined based on a couple of other properties!) or you can do sanity checks for properties in the configuration service. You can do logging, you can do security (Maybe the path to the password file shouldn’t be visible everywhere, right?), you can do caching, you can do… well, you get the point.

Best regards,
Thomas

  • Pingback: Binding External Configuration properties in spring boot application | TO THE NEW Blog()

  • Neelesh Desai

    Good idea!!

  • Fairuz WAN ISMAIL

    Nice Idea!

  • AlexCzar

    Good point, and you can actually make implementation even more elegant by using @ConfigurationProperties as shown here: http://blog.codeleak.pl/2014/09/using-configurationproperties-in-spring.html and more formally explained here: http://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html

    • juha

      If you’re using SpringBoot, then yes.

  • Fahed CHAABANE

    Hi,

    I’ve already been forced to deal with all the consequences you’re talking about (struggled configuration all over the app) and I must admit that you’re right ! I also recommend this good practice.

    I just wanna say that the title, is a little bit exagerated / provocative as it’s not the fact of using the @Value annotation which is bad but using it all over the web application (as it is used in the configuration service 😉 ).

    Nice tip ! Thanks.

  • Yo

    Using a constant is a good practice ? instead of fetching value from properties file by using @Value annotation ?

  • luis_espinal

    A lot of the logic-scattering problems mentioned in this article can be addressed by converting the ConfigurationService class from a @Service into a @Configuration object.

    Functionally, either a @Service or @Configuration option are superficially equivalent. But annotating it as a @Service has connotations that it will be providing a lot more than that.

    If you annotate it (and model it) as a @Configuration, then the purpose is clear with the least amount of magic-under-the-table plumbing.

  • juha

    Rule number one:
    – Have a single software artefact that can deployed to all environments without changes

    This means that never ever include environment specific config inside your deployable packages.

    So, it’s not about Spring & injected application properties. The root cause is for having these things inside your application binaries. Other bad practice is to inject the things directly to multiple components which very much hides the configurability of these classes and also might drive towards implementation which makes unit and integration testing more difficult. In short, use configuration classes with @Configuration to inject the configs inside classes. I do agree that all environment specific config needs to be printed to logs during startup.

    There are multiple valid use scenarios for using @Value
    – Your application surely has lots of configuration which is not environment specific.
    – Depending on your environment you can externalise the configuration in multiple ways. OS level environment variables is a valid choice in e.g. some container solutions and properties support this in a nice way.
    – Database is also a valid place for storing application configs, but from where do you get the database config then?

    So, correct tools for correct things.