in Coding

Why using Spring’s @Value annotation is bad


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 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.

Or even better

If you are using Spring Boot (not only Spring), you don’t need to re-invent the wheel. Spring Boot provides an elegant way to separate configuration and from the rest of your application: @ConfigurationProperties. By using Spring Boot’s @ConfigurationProperties you can easily encapsulate your configuration in a separate class and avoid scattering direct dependencies to your configuration files all over your code. Reade more here.

Best regards,

Write a Comment



  1. 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.

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

  3. 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.

  4. 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.

  5. Uh this article reminds me of the people on ifomercials that need help doing the most mundane things, like opening a cabinet door and having eveyrthing fall out of it. There are two things that can be done to manage properties so that @Value properties do not become unmanageable. 1) Keep your applications small, utilize the microservices architecture. 2) Name space your property names so that they are easy to tell where they belong.

    • “Uh this article reminds me of the people on ifomercials that need help doing the most mundane things, like opening a cabinet door and having everything fall out of it.”

      HAHaha, thank you for my morning laugh! I was thinking the same thing. Just keep your apps small. I like how @Value keeps things clean in the code.

      “You will end-up with doing a full text search on your project to find out where a single key is used”

      So? I do that anyway for many things, it’s quick and simple.

  6. This is called the Service Locator Pattern. If you put all your configuration in a Service class, then all of your classes will depend on the configuration class. Breaks modularization.

  7. I get what you are saying here. However, a class or method should only have access to values it absolutely needs in order to perform what it is supposed to do. If you inject a comprehensive Configuration object, then you also provide the method with means to access values it should not in reality be using. This complicates testing, because it is less clear what configuration values are required to run a specific test.

    I like @Value because it makes a method more concise as far as identifying what it needs in order to run. It makes refactoring more difficult because you have to do some full text searching on your source code, but this is less important in my oppinion. You often need to do this anyway, with class references in xml files for example.

    Others may disagree, just sharing my view on this 🙂

  8. Hi,
    Thanks for the article, however i’m -1 on this. it’s tempting at first, but imagine if someone did

    int myConfig = configService.getMyConfig();

    then you’d like to use @RefreshScope and get a new value for this property.
    You’ve to ensure that these properties are never saved and always get from the serviceConfig. that’s much harder task imho


  9. Good point. It is always a good design to have all the properties in one class and it to get the value.

  10. This is over-engineering at its best. Your argument against find and replace is silly. Changing property names across multiple files is simple using any IDE or text editor.

  11. The problem is that @ConfigurationProperties doesn’t support default values, and sometimes your only recourse is to use @Value (ie. @Value (“${}:42}

    I still keep these all in a single Config class and agree about encapsulating configuration.

    • You can just initialise a variable to a default value: