Claudine Broke It

Spring Beans

Posted on 20 June 2016

Spring

Spring Beans

The weather being uncooperative two weekends ago gave me the perfect excuse to bake (I made bear paw cookies) and start playing around with the Spring Framework. I know, I'm pretty cool.

One of the core concepts behind Spring is the Inversion of Control (IoC) principle, which, in application, "define[s] object dependencies through constructor arguments, arguments to a factory method, or properties that are set on the object instance after it is constructed or returned from a factory method."[1]. The objects manipulated through this process are referred to as beans.

Callbacks, schedulers, event loops and dependency injection are examples of design patterns that follow the inversion of control principle.

A bean is a Java object that does not control its instantiation and the location of its dependencies; instead, it receives -- through a process named injection -- its dependencies from the container.

I really liked the recipe analogy used when attempting to describe beans -- perhaps because beans and baking are some of my favorite things. Creating a bean object indicates to the container how to bake an object within a specific scope [2], much like you would do if you were to jot down a recipe on a card and hand it to a friend. Your friend can then replicate your dish whenever (s)he wants in the kitchen, i.e. in h(is|her) own context.

So what does all this look like in application? Well, here it is in its simplest form, that is, through constructor dependency injection:

public class Bookshelf {
    private Book book;

    public void read() {
        this.book.read();
    }
}

public class Book {
    public String read() {
        return "Reading...";
    }
}

@Configuration
public class BookService {
    @Bean
    public Bookshelf bookshelf() {
        return new Bookshelf(Book());
    }

    @Bean
    public Book book() {
        return new Book();
    }
}

All this goes to show that although the theory seem complicated, the IoC principle allows for effective decoupling strategies; individual modules focus solely on their tasks, while their implementations are delegated to the framework. The result is interoperability between beans and the programs that manipulate them.

Scopes

One of the notions I briefly covered when using the recipe analogy is that of scopes, or in what context our recipes are instantiated and executed? Here they are as described in the official documentation:

Singleton

(Default) Only one shared instance of a singleton bean is managed, and all requests for beans with an id or ids matching that bean definition result in that one specific bean instance being returned by the Spring container.

Prototype

Results in the creation of a new bean instance every time a request for that specific bean is made.

Web-Aware

Available if you use a web-aware Spring ApplicationContext implementation are the request, session, globalSession, application, and websocket scopes.

Example

In practice, setting the scope in a component scanning Spring application, setting the scope to prototype can be done like so:

@Service
@Scope("prototype")
public class BookService 
{
    String book;

    public String getBook() {
       return book;
    }

    public void setBook(String book) {
       this.book = book;
    }
}

In effect, this will mean that a new instance of a BookService will be created every time I request a book -- which is awesome because you never have enough books.

The latter example also brings us to another important concept concerning our recipes; that of accessors and conventions.

Bean conventions

Spring can manage virtually any class you want it to manage as a bean, and does not require that you follow the default constructor and setter-getter property model. However, to achieve consistent bean-container interoperability, the JavaBean conventions should be followed.

Following basic component conventions allows Spring to create and manage beans. I won't dwell into all the specifics because the official documentation does such a great job at doing it. However, here are the properties that make up each bean definition:

  1. class
  2. name
  3. scope
  4. constructor arguments
  5. properties
  6. autowiring mode
  7. lazy-initialization mode
  8. initialization method
  9. destruction method

Which is too much to cover in this post, so we will only very briefly overview #4 and #5:

Constructor

A bean must provide a no-parameter constructor so a container can instantiate and manipulate the bean.

Properties

Properties follow naming conventions that enable the IoC container to access and retrieve data.

Getter
public T getP()
Array getter
public T[] getP()
Array element Getter
public T getP(int)
Boolean getter
public boolean isP()
Setter
public void setP(T)
Array setter
public void setP(T[])
Array element setter
public void setP(int,T)

Conclusion

Now, there is a lot more to learn when exploring beans and IoC containers, and I feel like I've only begun to make some sense out of it. I hope that in further posts I can further dwelve into some of the nit and grit of these little leguminosas.