Spring, IoC Containers, and Static Code Principles

by:

Softwares


In this article, I would like to discuss the inversion of control patterns, static code (can be legacy or newly created) within an IoC framework like spring, and the issue of wiring utility methods in static code inside the IoC framework.

Static Methods

For example, we have an HttpUtils class with inside a bunch of static methods. Should we remove the static keyword and annotate the class with a Spring stereotype, which would immediately turn it into a spring singleton?

In java, the static keyword indicates that a member or method belongs to the type itself rather than an instance of that type. This means that only one instance of this static member is created and that it is shared between all instances of the class; if it is a static method within an IoC framework, this means that the way the method is run is unique for all the usages of this class and this method.

In this case, 3 possibilities:

  1. the method does not modify context data (data being handled by the application). So we can consider that despite its static character, it is thread-safe
  2. the method modifies context data, so it is thread-unsafe
  3. the method modifies context data, but it is thread-safe because it is “synchronized” (one execution at a time), which can severely penalize performance

Static methods in Java are provided as is at build time. This is why it is never possible to overload them. As a result, abstract methods cannot be static, and they can never access class or context values without being passed as an argument (cannot access this or super).

So does static code apply to “Utils” classes? Yes, since we are in case 1, there will be no modified data from the context, the input is translated into output, and as a general rule, this type of class can be exported regardless of the context. BUT, if it is exportable, shouldn’t this code be then squarely in a lib available to all projects? Yes, cross-functional teams would be happy to receive regular contributions from teams that have thought of making utility codes available to everyone that doesn’t need context.

Does static code apply to anything else? Not if there is a better thing to do.

Scopes Usable on Spring

Scope Description
singleton This scopes the bean definition to a single instance per Spring IoC container (default).
prototype This scopes a single bean definition to have any number of object instances.
request This scopes a bean definition to an HTTP request. Only valid in the context of a web-aware Spring ApplicationContext.
session This scopes a bean definition to an HTTP session. Only valid in the context of a web-aware Spring ApplicationContext.
global-session This scopes a bean definition to a global HTTP session. Only valid in the context of a web-aware Spring ApplicationContext.

Singletons

If a scope is set to Singleton, the spring IoC container creates exactly one instance of the object defined by that bean definition. This single instance is stored in a cache of these singleton beans, and all subsequent requests and references for this bean return the object in the cache.

The engine manages as for any cache, an expiration, and regeneration of the bean if it is taken out of the stock. A cache exit is possible if the bean has no more or no state.

For example, when calling an httpsUtils.callUrl(), the container must decide if it wants to reuse an already instantiated bean or create a new one. How does the container decide? When registering the bean httpUtils in the container (on the framework), it is possible to indicate to this container how we would like it to behave. Also, the first instance can be created at the start of the application or the first call on the bean. That said, bean callers don’t have to know about the bean’s life cycle; they call httpUtils.callUrl().

This is the optimal way to provide class methods in an application that contains a quantity of classes and a quantity of methods per class.

We, therefore, have a first (global) performance argument to transform all the static methods into singletons in order to benefit from the spring IoC cache. Accessing a static method is faster in theory because the JVM doesn’t need to look up the function before executing it, but in practice, most JDKs optimize instance method calls. That said, when it comes to performance, the most common cause is poor design. If static code is faster, then we could code the entire application in static code; why even declare classes and methods following the IoC pattern when that pattern and static code can do the same job well that they are constructed differently?

If we take again the example of the HttpUtils class, the principle of using static code is that I can directly access the callUrl() method from the class; we combine the definition of callUrl() and its implementation in the same place. IoC strives to separate this kind of detail, so instead, we define a method outside of it in an interface. This allows, for example, to decline this interface with several implementations. An interface implementation for HttpUtils would become a configuration of HttpUtils. Note that classes using HttpUtils will have no idea of the execution scope of callUrl() since the scopes used in the framework also depend on a configuration.

In summary, IoC and static are generally at odds. IoC promotes change while static, by definition, prevents it. Inject your dependencies according to the framework, and you will see that you can completely dispense with using static features.

Security

One more argument: according to sonar, all members of a spring bean should be injected (cf

Vulnerability: Critical

spring

owasp

Spring @Component, @Controller, @Service, and @Repository classes are singletons by default, meaning only one instance of the class is ever instantiated in the application. Typically such a class might have a few static members, such as a logger, but all non-static members should be managed by Spring. That is, they should have one of these annotations: @Resource, @Inject, @Autowired or @Value.

Having non-injected members in one of these classes could indicate an attempt to manage state. Because they are singletons, such an attempt is almost guaranteed to eventually expose data from User1's session to User2.

This rule raises an issue when a singleton @Component, @Controller, @Service, or @Repository, not annotated with @ConfigurationProperties, has non-static members that are not annotated with one of:

  • org.springframework.beans.factory.annotation.Autowired
  • org.springframework.beans.factory.annotation.Value
  • javax.annotation.Inject
  • javax.annotation.Resource

non-compliant code

@Controller
public class HelloWorld 
  private String name = null;
  @RequestMapping("/greet", method = GET)
  public String greet(String greetee) 
    if (greete != null) 
      this.name = greetee;
    
    return "Hello " + this.name; // if greetee is null, you see the previous user's data
  

String is a class, any class is concerned, including those that contain static methods that would be called within a spring bean.



Source link

Leave a Reply

Your email address will not be published.