Enterprise Java

Spring Environment is for initialization code only

Since version 3.1, the Spring framework offers an abstraction towards several different sources through which you can easily configure your application: the Environment.

In this post I describe a micro benchmark that I ran to prove that, while it’s a convenient API if you’re using Spring in your application, it might introduce a performance penalty for which you should not use it outside of your initialization code.

How it works

Before getting into the numbers, a quick digression on the internals of the Environment that are important to this post.

From the documentation:

Properties play an important role in almost all applications, and may originate from a variety of sources: properties files, JVM system properties, system environment variables, JNDI, servlet context parameters, ad-hoc Properties objects, Maps, and so on. The role of the environment object with relation to properties is to provide the user with a convenient service interface for configuring property sources and resolving properties from them.

So, you can use the Environment to have a common interface to properties provided with different strategies, using a simple getProperty call to access the required value. Look at the following Groovy code:

@Component
    public class Greeter {

        private Environment environment

        @Autowired
        public Greeter greeter(Environment environment){
            this.environment = environment
        }

        def nickName(user) {
            environment.getProperty("user") // here be magic
        }

        def greet(user) {
            def nick = nickName(user)
            if (name == null) println "Hi, ${user}!"
                         else println "Hi, ${nick}!"
        }

    }

Now, I can specify nicknames in a properties file so that I can greet know users with a more familiar nick name, still being able to salute also users which are not given a nickname. Neat, but how about performance?

The hidden Exception

I got into this exercise while debugging a couple of slow pages in the website I’m working on. While performance is generally satisfactory, two pages were constantly giving above second response times. Definitely too much.

In our code, we were translating some country names into queriable keys for an external services. We also needed to override an otherwise straightforward translation algorithm with very specific exceptions to the rule. The actual code was pretty much like the above Greeter.greet(user), and a Flight Recorder session eventually provided us with the performance bottleneck (click to open):

exceptions

For 12 page refreshes we were silently throwing 140k+ exceptions. And exceptions are sloooooow, even if you just create them.

Looking at the top thrown exception, it was actually pretty easy to understand what’s going on: the Environment checks whether the requested property is defined in the current JNDI context. But, if the name is not found, a NameNotFoundException is thrown. In our specific case we were using property lookup for exceptional cases, which means the vast majority of cases resulted in an exception being thrown.

Micro benchmark

I put together a micro benchmark to evaluate the potential performance gain of the original property lookup strategy versus a simpler one where relevant properties are loaded up at class construction time. I used the Java Microbenchmark Harness, which does an incredible job at making micro benchmarks easy on the JVM: JIT, warm up, class loading, all is taken care of for you and you can just go ahead and put your code under test. Here the results (higher numbers better):


[Property lookup per invocation]

Result: 28917.876 ?(99.9%) 183.630 ops/s [Average]
Statistics: (min, avg, max) = (25688.067, 28917.876, 30976.876), stdev = 777.500
Confidence interval (99.9%): [28734.246, 29101.505]

[Property loading at class construction]

Result: 159062.900 ?(99.9%) 1013.309 ops/s [Average]
Statistics: (min, avg, max) = (138707.926, 159062.900, 177183.549), stdev = 4290.413
Confidence interval (99.9%): [158049.591, 160076.209]

As expected, five times as fast.

Conclusions

I’m not a big fan of Spring, but if you’re using it the Environment class is a dead easy interface to your application configuration. But, unless you’re using JNDI as your main store of configuration properties, its performance characteristics make it a great tool only if you’re using it in your initialization code, and not during on-line processing of requests.

Reference: Spring Environment is for initialization code only from our JCG partner Carlo Sciolla at the Skuro blog.

Carlo Sciolla

An enterprise software engineer by day and Clojurian, meetup organizer, blogger and biker by night, Carlo is an Open Source enthusiast and passionate of every thing software. Currently working as Product Lead at Backbase, he is also the organizer of the Amsterdam Clojurians meetup and the yearly October Amsterdam Clojure conference.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

4 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Michael Russo
Michael Russo
9 years ago

Thanks for the post. I didn’t realize the performance cost of the environment abstraction, but as you said, it still works great for initialization code.

Care to elaborate on that last bit, though? Why don’t you care for Spring? What do you prefer as an alternative?

Carlo Sciolla
9 years ago
Reply to  Michael Russo

@Michael Siegel: it’s 100% a personal opionion, but what I don’t like of Spring is the amount of magic that it introduces into your code. To me, magic == hidden complexity, which translate in a higher risk for surprises. As a clojure fanatic, I more than anything value simple, clean and composable abstractions over multifaceted features such as what Spring tends to provide. Like in its latest developments, where @EnableAwesomeness style of annotations, while doing the heavy lifting for you, are almost never completely clear to the developer as to what extent their effects go. Or the sheer amount of… Read more »

Michael Russo
Michael Russo
9 years ago

Thanks for elaborating. I’m a fan of Spring myself but I like to hear informed opinions which have a different mindset and can highlight some of the drawbacks of techniques and libraries that I rely on. I can see where you’re coming from with the hidden complexity, and code certainly can go overboard relying on these annotations and the external components which enable them when simpler, more direct solutions exist. And yes, code that is overly reliant on Spring will have several extra method invocations appear in stack traces, making that code harder to debug without a solid understanding of… Read more »

Carlo Sciolla
9 years ago

Well, perhaps tooling is not strictly required, but I would argue that we might as well just accept the efforts it takes to go through them as unavoidable complexity, without realising that it’s actually unnecessary pain. The very fact that there are companies making products to tackle that complexity (http://stackifier.takipi.com/) might be a hint that the latter is true, and Spring is indeed doing its part in inflating our stack traces.

Back to top button