Theme NexT works best with JavaScript enabled
0%

Spring Framework Guide


IMPORTANT:
Some of the content here is a personal summary/abbreviation of contents on the Offical Spring Framework Documentation. Feel free to refer to the official site if you think some of the sections written here are not clear.


This is a Guide, since it is mostly conceptual and does not include much actual coding (except for examples illustrating those concepts). For more practical uses/examples, please refer to the Spring Boot Manual or the Spring Cloud Manual.

Spring Intro

The term “Spring” means different things in different contexts. It can be used to refer to the Spring Framework project itself, which is where it all started. Over time, other Spring projects have been built on top of the Spring Framework. Most often, when people say “Spring”, they mean the entire family of projects. This reference documentation focuses on the foundation: the Spring Framework itself.

When you learn about a framework, it’s important to know not only what it does but what principles it follows. Here are the guiding principles of the Spring Framework:

  • Provide choice at every level. Spring lets you defer design decisions as late as possible. For example, you can switch persistence providers through configuration without changing your code.
  • Accommodate diverse perspectives. Spring embraces flexibility and is not opinionated about how things should be done. It supports a wide range of application needs with different perspectives.
  • Maintain strong backward compatibility. Spring’s evolution has been carefully managed to force few breaking changes between versions. Spring supports a carefully chosen range of JDK versions and third-party libraries to facilitate maintenance of applications and libraries that depend on Spring.
  • Care about API design. The Spring team puts a lot of thought and time into making APIs that are intuitive and that hold up across many versions and many years.
  • Set high standards for code quality. The Spring Framework puts a strong emphasis on meaningful, current, and accurate javadoc. It is one of very few projects that can claim clean code structure with no circular dependencies between packages.

IoC - Inversion of Control

IoC is also known as dependency injection (DI). It is a process whereby objects define their dependencies (that is, the other objects they work with) only 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. The container then injects those dependencies when it creates the bean. This process is fundamentally the inverse (hence the name, Inversion of Control) of the bean itself controlling the instantiation or location of its dependencies by using direct construction of classes or a mechanism such as the Service Locator pattern.

In Spring, the objects that form the backbone of your application and that are managed by the Spring IoC container are called beans. A bean is an object that is instantiated, assembled, and otherwise managed by a Spring IoC container. Otherwise, a bean is simply one of many objects in your application. Beans, and the dependencies among them, are reflected in the configuration metadata used by a container.

The main tasks performed by IoC container are:

  • to instantiate the application class
  • to configure the object
  • to assemble the dependencies between the objects

And there are two types of IoC containers. They are:

  • BeanFactory (org.springframework.beans)
  • ApplicationContext (org.springframework.context)

In short, the BeanFactory provides the configuration framework and basic functionality, and the ApplicationContext adds more enterprise-specific functionality. The ApplicationContext is a complete superset of the BeanFactory and is used exclusively in this chapter in descriptions of Spring’s IoC container. For more information on using the BeanFactory instead of the ApplicationContext, see The BeanFactory.

Java Beans vs Spring Beans vs POJOs

(additional reference: http://www.shaunabram.com/beans-vs-pojos/)

  • JavaBeans are classes that encapsulate many objects into a single object (the bean). It is a java class that should follow following conventions:

    • Must implement Serializable.

    • It should have a public no-arg constructor.

    • All properties in java bean must be private with public getters() and public setter() methods.

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      public class TestBean { 
      private String name;

      public void setName(String name){
      this.name = name;
      }
      public String getName(){
      return name;
      }
      }

    setter methods:

    • It should be public in nature.
    • The return-type should be void.
    • The setter method should be prefixed with set.
    • It should take some argument i.e. it should not be no-arg method.

    getter methods

    • It should be public in nature.
    • The return-type should not be void i.e. according to our requirement we have to give return-type.
    • The getter method should be prefixed with get.
    • It should not take any argument.

    Boolean properties getter method

    • name can be prefixed with either “get” or “is”. But recommended to use “is”.
    • returns a boolean
  • POJO is an acronym for Plain Old Java Object. The term was coined by Martin Fowler et. al., as a ‘fancy’ way to describe ordinary Java Objects that do not require a framework to use, nor need to be run in a application server environment.

  • A Spring bean is basically an object managed by Spring. More specifically, it is an object that is instantiated, configured and otherwise managed by a Spring Framework container. Spring beans are defined in a Spring configuration file (or, more recently, by using annotations), instantiated by the Spring container, and then injected into your application.

    Spring can manage just about any object, even if it doesn’t have JavaBean type characteristics such as default constructors or mutator methods (getters and setters).

IoC Container Overview

The org.springframework.context.ApplicationContext interface represents the Spring IoC container and is responsible for instantiating, configuring, and assembling the beans. The container gets its instructions on what objects to instantiate, configure, and assemble by reading configuration metadata.

The configuration metadata is represented in XML, Java annotations, or Java code.

The following diagram shows a high-level view of how Spring works. Your application classes are combined with configuration metadata so that, after the ApplicationContext is created and initialized, you have a fully configured and executable system or application.

A Spring IoC container manages one or more beans. These beans are created with the configuration metadata that you supply to the container (e.g. via an XML file).

Within the container itself, these bean definitions are represented as BeanDefinition objects, which contain (among other information) the following metadata:

  • A package-qualified class name: typically, the actual implementation class of the bean being defined.
  • Bean behavioral configuration elements, which state how the bean should behave in the container (scope, lifecycle callbacks, and so forth).
  • References to other beans that are needed for the bean to do its work. These references are also called collaborators or dependencies.
  • Other configuration settings to set in the newly created object — for example, the size limit of the pool or the number of connections to use in a bean that manages a connection pool.

This metadata translates to a set of properties that make up each bean definition. The following table describes these properties:

Property Explained in
Class Instantiating Beans
Name Naming Beans
Scope Bean Scopes
Constructor arguments Dependency Injection
Properties Dependency Injection
Autowiring mode Autowiring Collaborators
Lazy initialization mode Lazy-initialized Beans
Initialization method Initialization Callbacks
Destruction method Destruction Callbacks

Configuration Metadata

As the preceding diagram shows, the Spring IoC container consumes a form of configuration metadata. This configuration metadata represents how you, as an application developer, tell the Spring container to instantiate, configure, and assemble the objects in your application.

Configuration metadata is can be supplied using one of the three forms:

  • XML file
  • Java-based configuration
  • Annotation-based configuration

(the following chapters only cover Java-based Configuration. If you prefer other means of configuration, please refer to the Offical Documentation for more information.)

Java Based Configuration

The central artifacts in Spring’s new Java-configuration support are @Configuration-annotated classes and @Bean-annotated methods.

The @Bean annotation is used to indicate that a method instantiates, configures, and initializes a new object (type signature of the method) to be managed by the Spring IoC container. For those familiar with Spring’s <beans/> XML configuration, the @Bean annotation plays the same role as the <bean/> element. You can use @Bean-annotated methods with any Spring @Component. However, they are most often used with @Configuration beans.

Annotating a class with @Configuration indicates that its primary purpose is as a source of bean definitions. Furthermore, @Configuration classes let inter-bean dependencies be defined by calling other @Bean methods in the same class. The simplest possible @Configuration class reads as follows:

1
2
3
4
5
6
7
8
@Configuration
public class AppConfig {

@Bean
public MyService myService() {
return new MyServiceImpl();
}
}

Note:

  • Unlike full @Configuration, lite @Bean methods (declared within classes that are not annotated with @Configuration) cannot declare inter-bean dependencies. Instead, they operate on their containing component’s internal state and, optionally, on arguments that they may declare. Such a @Bean method should therefore not invoke other @Bean methods. Each such method is literally only a factory method for a particular bean reference, without any special runtime semantics.

The @Bean and @Configuration annotations are discussed in depth in the following sections. First, however, we need to cover the various ways of creating a spring container using by Java-based configuration.

Instantiating the Spring Container Using AnnotationConfigApplicationContext

When @Configuration classes are provided as input, the @Configuration class itself is registered as a bean definition and all declared @Bean methods within the class are also registered as bean definitions.

This means that instead of using XML files, you can use @Configuration classes as input when instantiating an AnnotationConfigApplicationContext. This allows for completely XML-free usage of the Spring container, as the following example shows:

1
2
3
4
5
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
MyService myService = ctx.getBean(MyService.class);
myService.doStuff();
}

AnnotationConfigApplicationContext is not limited to working only with @Configuration classes. Any @Component or JSR-330 annotated class may be supplied as input to the constructor, as the following example shows:

1
2
3
4
5
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(MyServiceImpl.class, Dependency1.class, Dependency2.class);
MyService myService = ctx.getBean(MyService.class);
myService.doStuff();
}

The preceding example assumes that MyServiceImpl, Dependency1, and Dependency2 use Spring dependency injection annotations such as @Autowired.

Building the Container Programmatically by Using register(Class<?>…​)

One thing we see before for using AnnotationConfigApplicationContext is that the configurations need to be specified when you instantiate the ApplicationContext. However, sometimes you might need to programmatically add configurations later. This can be done by instantiate an AnnotationConfigApplicationContext by using a no-arg constructor and then configure it by using the register() method. This approach is particularly useful when programmatically building an AnnotationConfigApplicationContext. The following example shows how to do so:

1
2
3
4
5
6
7
8
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(AppConfig.class, OtherConfig.class);
ctx.register(AdditionalConfig.class);
ctx.refresh();
MyService myService = ctx.getBean(MyService.class);
myService.doStuff();
}

Enabling Component Scanning with scan(String…​)

To enable component scanning, you can annotate your @Configuration class as follows:

1
2
3
4
5
@Configuration
@ComponentScan(basePackages = "com.acme") // this enables component scanning
public class AppConfig {
...
}

In the preceding example, the com.acme package is scanned to look for any @Component-annotated classes, and those classes are registered as Spring bean definitions within the container.

Additionally, you can use the AnnotationConfigApplicationContext object with the scan(String…​) method to allow for the same component-scanning functionality, as the following example shows:

1
2
3
4
5
6
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.scan("com.acme");
ctx.refresh();
MyService myService = ctx.getBean(MyService.class);
}

In the preceding example, assuming that AppConfig is declared within the com.acme package (or any package underneath). The above works since @Configuration classes are meta-annotated with @Component, so they are candidates for component-scanning as well. Then the AppConfig along with its components is picked up during the call to scan(). Upon refresh(), all its @Bean methods are processed and registered as bean definitions within the container.

Using the @Bean Annotation

You can use the @Bean annotation in a @Configuration-annotated or in a @Component-annotated class.

To declare a bean, you can annotate a method with the @Bean annotation. You use this method to register a bean definition within an ApplicationContext of the type specified as the method’s return value. By default, the bean name is the same as the method name. The following example shows a @Bean method declaration:

1
2
3
4
5
6
7
8
@Configuration
public class AppConfig {

@Bean
public TransferServiceImpl transferService() {
return new TransferServiceImpl();
}
}

The preceding configuration is exactly equivalent to the following Spring XML:

1
2
3
<beans>
<bean id="transferService" class="com.acme.TransferServiceImpl"/>
</beans>

Both would make a bean (method for getting an Object) named transferService available in the ApplicationContext, bound to an object instance of type TransferServiceImpl, as the following text image shows:

1
transferService -> com.acme.TransferServiceImpl

You can also declare your @Bean method with an interface (or base class) return type, as the following example shows:

1
2
3
4
5
6
7
8
@Configuration
public class AppConfig {

@Bean
public TransferService transferService() {
return new TransferServiceImpl();
}
}

However, this limits the visibility for advance type prediction to the specified interface type (TransferService), such that the full type (TransferServiceImpl) is known to the container only once.

Determining a Bean’s Runtime Type

The runtime type of a specific bean is non-trivial to determine. A specified class in the bean metadata definition is just an initial class reference, potentially combined with a declared factory method or being a FactoryBean class which may lead to a different runtime type of the bean, or not being set at all in case of an instance-level factory method (which is resolved via the specified factory-bean name instead).

The recommended way to find out about the actual runtime type of a particular bean is a BeanFactory.getType call for the specified bean name. This takes all of the above cases into account and returns the type of object that a BeanFactory.getBean call is going to return for the same bean name.

Bean Dependencies

A @Bean-annotated method can have an arbitrary number of parameters that describe the dependencies required to build that bean. For instance, if our TransferService requires an AccountRepository, we can materialize that dependency with a method parameter, as the following example shows:

1
2
3
4
5
6
7
8
@Configuration
public class AppConfig {

@Bean
public TransferService transferService(AccountRepository accountRepository) {
return new TransferServiceImpl(accountRepository);
}
}

The resolution mechanism is pretty much identical to constructor-based dependency injection. See below sections for more details.

Dependency Injection

Dependency injection (DI) is a process whereby objects define their dependencies (that is, the other objects with which they work) only 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.

The container then injects those dependencies when it creates the bean.

Code is cleaner with the DI principle, and decoupling is more effective when objects are provided with their dependencies. The object does not look up its dependencies and does not know the location or class of the dependencies. As a result, your classes become easier to test, particularly when the dependencies are on interfaces or abstract base classes, which allow for stub or mock implementations to be used in unit tests.

DI exists in two major variants:

  • Constructor-based dependency injection
  • Setter-based dependency injection

Constructor-based dependency injection

(additional reference: https://www.tutorialspoint.com/spring/constructor_based_dependency_injection.htm)

Constructor-based DI is accomplished when the container invokes a class constructor with a number of arguments, each representing a dependency on the other class.

Consider you have an application which has a text editor component and you want to provide a spell check. Your standard code would look something like this:

1
2
3
4
5
6
7
public class TextEditor {
private SpellChecker spellChecker;

public TextEditor() {
spellChecker = new SpellChecker();
}
}

What we’ve done here is, create a dependency between the TextEditor and the SpellChecker.** In an inversion of control scenario, we would instead do something like this:**

1
2
3
4
5
6
7
public class TextEditor {
private SpellChecker spellChecker;

public TextEditor(SpellChecker spellChecker) { // Constructor based DI
this.spellChecker = spellChecker;
}
}

Here, the TextEditor should not worry about SpellChecker implementation. The SpellChecker will be implemented independently and will be provided to the TextEditor at the time of TextEditor instantiation. This entire procedure is controlled by the Spring Framework.

Constructor Arguments Resolution

There may be an ambiguity while passing arguments to the constructor,** in case there are more than one parameters**. To resolve this ambiguity, the order in which the constructor arguments are defined in a bean definition is the order in which those arguments are supplied to the appropriate constructor. Consider the following class:

1
2
3
4
5
6
7
package x.y;

public class Foo {
public Foo(Bar bar, Baz baz) {
// ...
}
}

The following configuration works fine:

1
2
3
4
5
6
7
8
9
@Configuration
public class AppConfig{

@Bean
public Foo foo(Bar bar, Baz baz){
return new Foo(bar, baz)
}

}

Let us check one more case where we pass different types to the constructor, and we want to specify a specific value for them. Consider the following class:

1
2
3
4
5
6
7
package x.y;

public class Foo {
public Foo(int year, String name) {
// ...
}
}

The container can also use type matching with simple types, if you explicitly specify the type of the constructor argument using the type attribute. For example −

1
2
3
4
5
6
7
8
@Configuration
public class AppConfig{

@Bean
public Foo foo(int year, String name){
return new Foo(2001,"Zara");
}
}

If you are using XML, then the best way to pass constructor arguments is to use the index attribute to specify explicitly the index of constructor arguments. Here, the index is 0 based. For example:

1
2
3
4
5
6
7
8
<beans>

<bean id = "foo" class = "x.y.Foo">
<constructor-arg index = "0" value = "2001"/>
<constructor-arg index = "1" value = "Zara"/>
</bean>

</beans>

A final note, in case you are passing a reference to an object as an argument, you need to use ref attribute of <constructor-arg> tag in the XML, and if you are passing a value directly then you should use value attribute as shown above.

Setter-based Dependency Injection

Setter-based DI is accomplished by the container calling setter methods on your beans after invoking a no-argument constructor or a no-argument static factory method to instantiate your bean.

For example:

(referece: https://www.tutorialspoint.com/spring/setter_based_dependency_injection.htm)

the content of TextEditor.java file:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class TextEditor {
private SpellChecker spellChecker;

public TextEditor(){}

// a setter method to inject the dependency.
public void setSpellChecker(SpellChecker spellChecker) {
this.spellChecker = spellChecker;
}
// a getter method to return spellChecker
public SpellChecker getSpellChecker() {
return spellChecker;
}
public void spellCheck() {
spellChecker.checkSpelling();
}
}

Here you need to check the naming convention of the setter methods. To set an object SpellChecker we are using setSpellChecker() method which is very similar to Java POJO classes. Then the content of another dependent class file SpellChecker.java could be:

1
2
3
4
5
6
7
8
9
public class SpellChecker {
public SpellChecker(){
System.out.println("Inside SpellChecker constructor." );
}

public void checkSpelling() {
System.out.println("Inside checkSpelling." );
}
}

Finally, the configuration would look like:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Configuration
public class AppConfig{

@Bean
public TextEditor textEditor(SpellChecker spellChecker){
TextEditor textEditor = new TextEditor();
textEditor.setSpellChecker(spellChecker);
return textEditor;
}

@Bean
public SpellChecker spellChecker(){ // this is necessary as the above Bean uses the Bean SpellChecker
return new SpellChecker();
}
}

Finally, just to finish the example, you would have your main class (called Example here):

1
2
3
4
5
6
7
8
9
10
11
12
import com.mySpringProject.app.testIoC.AppConfig;
import com.mySpringProject.app.testIoC.TextEditor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Example {
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
TextEditor txtedr = ctx.getBean(TextEditor.class);
txtedr.spellCheck();
}
}

You will see that the container managed the construction of objects/dependencies for us, so that SpellChecker is first created, and then passed into the TextEditor object. Lastly, you would be able to call the method spellCheck().

Constructor-based or Setter-based DI

Since you can mix constructor-based and setter-based DI, it is a good rule of thumb to use constructors for mandatory dependencies and setter methods or configuration methods for optional dependencies. Note that use of the @Required annotation on a setter method can be used to make the property be a required dependency; however, constructor injection with programmatic validation of arguments is preferable.

Using only constructor injection, lets you implement application components as immutable objects and ensures that required dependencies are not null. Furthermore, constructor-injected components are always returned to the client (calling) code in a fully initialized state.

Setter injection should primarily only be used for optional dependencies that can be assigned reasonable default values within the class. Otherwise, not-null checks must be performed everywhere the code uses the dependency.

Lazy-initialized Beans

By default, ApplicationContext implementations eagerly create and configure all singleton beans as part of the initialization process. Generally, this pre-instantiation is desirable, because errors in the configuration or surrounding environment are discovered immediately, as opposed to hours or even days later. When this behavior is not desirable, you can prevent pre-instantiation of a singleton bean by marking the bean definition as being lazy-initialized.** A lazy-initialized bean tells the IoC container to create a bean instance when it is first requested, rather than at startup**.

To achieve this in a Java-annotation based configuration, you add the @Lazy to the configuration class. This will make all @Bean bean methods to become lazily initialized:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;

@Configuration
@Lazy // all beans inside this class will be lazily initialized
public class AppConfig {

@Bean
public TextEditor textEditor(SpellChecker spellChecker){
TextEditor textEditor = new TextEditor();
textEditor.setSpellChecker(spellChecker);
return textEditor;
}

@Bean
public SpellChecker spellChecker(){
return new SpellChecker();
}
}

If you only want to lazily initialize a speicific bean, then add @Lazy(true) or @Lazy() above that bean:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;

@Configuration
public class AppConfig {

@Bean
@Lazy() // this will be lazily initialized
public TextEditor textEditor(SpellChecker spellChecker){
TextEditor textEditor = new TextEditor();
textEditor.setSpellChecker(spellChecker);
return textEditor;
}

@Bean
public SpellChecker spellChecker(){
return new SpellChecker();
}
}

Component Scanning

(additional reference: https://www.baeldung.com/spring-bean-annotations)

Spring can automatically scan a package for beans if component scanning is enabled.

@ComponentScan configures which packages to scan for classes with annotation configuration. We can specify the base package names directly with one of the basePackages or value arguments (value is an alias for basePackages):

1
2
3
4
@Configuration
@ComponentScan(basePackages = "com.baeldung.annotations")

class VehicleFactoryConfig {}

Also, we can point to classes directly in the base packages with the basePackageClasses argument:

1
2
3
4
@Configuration
@ComponentScan(basePackageClasses = VehicleFactoryConfig.class)

class VehicleFactoryConfig {}

Alternatively, we can use** @ComponentScans to specify multiple @ComponentScan configurations**:

1
2
3
4
5
6
7
@Configuration
@ComponentScans({ // notice this is ComponentScans, not ComponentScan
@ComponentScan(basePackages = "com.baeldung.annotations"),
@ComponentScan(basePackageClasses = VehicleFactoryConfig.class)
})

class VehicleFactoryConfig {}

Using @Component Annotation

@Component is a class level annotation. During the component scan, Spring Framework automatically detects classes annotated with @Component.

For example:

1
2
3
4
@Component
class CarUtility {
// ...
}

By default, the bean instances of this class have the same name as the class name with a lowercase initial. On top of that, we can specify a different name using the optional value argument of this annotation.

Since @Repository,@Service, @Configuration, and @Controller are all meta-annotations of @Component, they share the same bean naming behavior. Also, Spring automatically picks them up during the component scanning process.

For example, you can have an @Component with:

1
2
3
4
5
6
7
8
9
10
11
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

@Component // or @Configuration
public class Config2 {

@Bean
public WordDictionary wordDictionary(){
return new WordDictionary();
}
}

Then in your main @Configuration, you have:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import org.springframework.context.annotation.*;

@Configuration
@ComponentScans(
{@ComponentScan(basePackageClasses=Config2.class)} // Scans that class for beans
)
public class AppConfig {

@Bean
public TextEditor textEditor(SpellChecker spellChecker){
TextEditor textEditor = new TextEditor();
textEditor.setSpellChecker(spellChecker);
return textEditor;
}

@Bean
public SpellChecker spellChecker(){
return new SpellChecker();
}
}

Finally, in your main class, you would be able to use WordDictionary class even if it was not specified in the ApplicationContext:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import com.mySpringProject.app.testIoC.AppConfig;
import com.mySpringProject.app.testIoC.TextEditor;
import com.mySpringProject.app.testIoC.WordDictionary;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Example {
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
TextEditor txtedr = ctx.getBean(TextEditor.class);
WordDictionary dict = ctx.getBean(WordDictionary.class); // not directly in AppConfig, but scanned
txtedr.spellCheck();
}
}

Using @Autowired to configure your beans and dependencies

(additional reference: https://www.baeldung.com/spring-autowire)

Starting with Spring 2.5, the framework introduced a new style of Dependency Injection driven by @Autowired Annotations. This annotation allows Spring to automatically resolve and inject collaborating beans into your bean. It has the following adavantages:

  • Autowiring can significantly reduce the need to specify properties or constructor arguments. (Other mechanisms such as a bean template discussed elsewhere in this chapter are also valuable in this regard.)

  • Autowiring can update a configuration as your objects evolve. For example, if you need to add a dependency to a class, that dependency can be satisfied automatically without you needing to modify the configuration. Thus autowiring can be especially useful during development, without negating the option of switching to explicit wiring when the code base becomes more stable.

Once annotation injection is enabled, autowiring can be used on properties, setters, and constructors.

@Autowired on properties

First, to enable annotation-driven injection, you need to be using AnnotationConfigApplicationContext to load your spring configuration as below:

1
2
3
4
5
public class Example {
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(); // actually what we've been doing so far
}
}

Then, you can have the following Components/classes:

1
2
3
4
5
6
7
8
9
10
11
package com.mySpringProject.app.testIoC.AutowiredSamples;

import org.springframework.stereotype.Component;

@Component
public class FooforMatter {

public String message(){
return "foo";
}
}

And importantly, this class:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package com.mySpringProject.app.testIoC.AutowiredSamples;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class FooService {

@Autowired
private FooforMatter fooforMatter; // notice that this field is Autowired.
// It means that it will be automatically created and attached
// to the FooService object

public FooforMatter getFooforMatter() {
return fooforMatter; // so that we can use the message() method
}
}

Now, all you need to do in your @Configuration clas is to point it to the correctly component using the component scan:

1
2
3
4
5
6
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan("com.mySpringProject.app.testIoC.AutowiredSamples") // the package where we had the @Components
public class AutowiredConfig { // no bean needs to be declared inside this configuration
}

Then, in the main application class, we can see the message by:

1
2
3
4
5
6
7
8
9
10
11
12
13
import com.mySpringProject.app.testIoC.AutowiredConfig;
import com.mySpringProject.app.testIoC.AutowiredSamples.FooService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Example {
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(AutowiredConfig.class);

FooService fsrv = ctx.getBean(FooService.class); // Autowired figured this out for us
System.out.println(fsrv.getFooforMatter().message());
}
}

@Autowired on constructors

The @Autowired annotation can also be used on constructors. In the below example, when the annotation is used on a constructor, an instance of FooFormatter is injected as an argument to the constructor when FooService is created:

1
2
3
4
5
6
7
8
9
10
@Component
public class FooService {

private FooFormatter fooFormatter;

@Autowired
public FooService(FooFormatter fooFormatter) {
this.fooFormatter = fooFormatter;
}
}

Now, an instance of FooFormatter is injected as an argument to the constructor when FooService is created.

This technically has the same effect as using @Autowired on a specific field, but it turns out that** using @Autowired on a constructor is always the better approach**. This is because:

  • you can only @Autowired one field at a time, but above a constructor, all arguments will be instantiated/autowired.
  • using @Autowired on a field is vulnerable for the problem of having a NullPointerException. This is because if the autowired field is not correctly instantiated, the** main object that depends on it might still be created, but invoking methods of that private field will cause NullPointerException. However, by **having the @Autowired for a constructor, it forces the main object to be created WITH an instantiation of that dependent object.

Optional Dependencies for @Autowired

(additional reference: https://www.baeldung.com/spring-autowire)

Spring expects @Autowired dependencies to be available when the dependent bean is being constructed. If the framework cannot resolve a bean for wiring, it will throw the below-quoted exception and prevent the Spring container from launching successfully:

1
2
3
4
5
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: 
No qualifying bean of type [com.autowire.sample.FooDAO] found for dependency:
expected at least 1 bean which qualifies as autowire candidate for this dependency.
Dependency annotations:
{@org.springframework.beans.factory.annotation.Autowired(required=true)}

To avoid this from happening, a bean can optional be specified as below:

1
2
3
4
5
6
public class FooService {

@Autowired(required = false)
private FooDAO dataAccessor;

}

Bean Scopes

(additional reference: https://www.baeldung.com/spring-bean-scopes)

When you create a bean definition, you create a recipe for creating actual instances of the class defined by that bean definition. The idea that a bean definition is a recipe is important, because it means that, as with a class, you can create many object instances from a single recipe.

In addition to all those configurations that you can specify to a bean, you can also specify its scope:** the scope of a bean defines the life cycle and visibility of that bean in the contexts in which it is used**.

The latest version of Spring framework defines 6 types of scopes:

The last four scopes listed above - request, session, application and websocket - are only available in a web-aware application.

Singleton Scope

Defining a bean with singleton scope means the container creates a single instance of that bean, and all requests for that bean name will return the same object, which is cached. Any modifications to the object will be reflected in all references to the bean. This scope is the default value if no other scope is specified.

For example, if you have a Person object that stores a name:

1
2
3
4
5
public class Person {
private String name;

// standard constructor, getters and setters
}

Afterwards, we define the bean with singleton scope by using the @Scope annotation:

1
2
3
4
5
@Bean
@Scope("singleton")
public Person personSingleton() {
return new Person();
}

Now, if you use the getBean(Person.class) to create that object, you will only get one and the same instance of it no matter how many times you this method call. This also means that if you change the name field of one of the Person object you get, it will be changed for all Person objects that you got.

Prototype Scope

A bean with prototype scope will return a different instance every time it is requested from the container. It is defined by setting the value prototype to the @Scope annotation in the bean definition:

1
2
3
4
5
@Bean
@Scope("prototype") // everytime this bean is used, a new Person object will be created
public Person personPrototype() {
return new Person();
}

Now, if you make multiple calls of getBean(Person.class), you will get multiple Person objects instantiated (as many as the number of times you called the method). This will not cause the problem that, if you change the name of one Person object, all names of other Person objects will be changed.

As mentioned, there are four additional scopes that are only available in a web-aware application context. These are less often used in practice:

Request Scope

The request scope creates a bean instance for a single HTTP request.

We can define the bean with request scope using the @Scope annotation:

1
2
3
4
5
@Bean
@Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
public HelloMessageGenerator requestScopedBean() {
return new HelloMessageGenerator();
}

The proxyMode attribute is necessary here because, at the moment of the instantiation of the web application context, there is no active request. Spring will create a proxy to be injected as a dependency, and instantiate the target bean when it is needed in a request.

We can also use a @RequestScope composed annotation that acts as a shortcut for the above definition:

1
2
3
4
5
@Bean
@RequestScope
public HelloMessageGenerator requestScopedBean() {
return new HelloMessageGenerator();
}

Next, we can define a controller that has an injected reference to the requestScopedBean. We need to access the same request twice in order to test the web specific scopes.

If we display the message each time the request is run, we can see that the value is reset to null, even though it is later changed in the method. This is because of a different bean instance being returned for each request.

1
2
3
4
5
6
7
8
9
10
11
12
13
@Controller
public class ScopesController {
@Resource(name = "requestScopedBean")
HelloMessageGenerator requestScopedBean;

@RequestMapping("/scopes/request")
public String getRequestScopeMessage(final Model model) {
model.addAttribute("previousMessage", requestScopedBean.getMessage());
requestScopedBean.setMessage("Good morning!");
model.addAttribute("currentMessage", requestScopedBean.getMessage());
return "scopesExample";
}
}

Session Scope

The session scope creates for an HTTP Session.

We can define the bean with session scope in a similar manner:

1
2
3
4
5
@Bean
@Scope(value = WebApplicationContext.SCOPE_SESSION, proxyMode = ScopedProxyMode.TARGET_CLASS)
public HelloMessageGenerator sessionScopedBean() {
return new HelloMessageGenerator();
}

There’s also a dedicated composed annotation we can use to simplify the bean definition:

1
2
3
4
5
@Bean
@SessionScope
public HelloMessageGenerator sessionScopedBean() {
return new HelloMessageGenerator();
}

Next, we define a controller with a reference to the sessionScopedBean. Again, we need to run two requests in order to show that the value of the message field is the same for the session.

In this case, when the request is made for the first time, the value message is null. But once, it is changed, then that value is retained for subsequent requests as the same instance of the bean is returned for the entire session.

1
2
3
4
5
6
7
8
9
10
11
12
13
@Controller
public class ScopesController {
@Resource(name = "sessionScopedBean")
HelloMessageGenerator sessionScopedBean;

@RequestMapping("/scopes/session")
public String getSessionScopeMessage(final Model model) {
model.addAttribute("previousMessage", sessionScopedBean.getMessage());
sessionScopedBean.setMessage("Good afternoon!");
model.addAttribute("currentMessage", sessionScopedBean.getMessage());
return "scopesExample";
}
}

Application Scope

The application scope creates the bean instance for the lifecycle of a ServletContext.

This is similar to the singleton scope but there is a very important difference with regards to the scope of the bean.

When beans are application scoped the same instance of the bean is shared across multiple servlet-based applications running in the same ServletContext, while singleton-scoped beans are scoped to a single application context only.

Let’s create the bean with application scope:

1
2
3
4
5
6
@Bean
@Scope(
value = WebApplicationContext.SCOPE_APPLICATION, proxyMode = ScopedProxyMode.TARGET_CLASS)
public HelloMessageGenerator applicationScopedBean() {
return new HelloMessageGenerator();
}

Analogously as for the request and session scopes, we can use a shorter version:

1
2
3
4
5
@Bean
@ApplicationScope
public HelloMessageGenerator applicationScopedBean() {
return new HelloMessageGenerator();
}

Now, let’s create a controller that references this bean:

1
2
3
4
5
6
7
8
9
10
11
12
13
@Controller
public class ScopesController {
@Resource(name = "applicationScopedBean")
HelloMessageGenerator applicationScopedBean;

@RequestMapping("/scopes/application")
public String getApplicationScopeMessage(final Model model) {
model.addAttribute("previousMessage", applicationScopedBean.getMessage());
applicationScopedBean.setMessage("Good afternoon!");
model.addAttribute("currentMessage", applicationScopedBean.getMessage());
return "scopesExample";
}
}

In this case, value message once set in the applicationScopedBean will be retained for all subsequent requests, sessions and even for a different servlet application that will access this bean, provided it is running in the same ServletContext.

Websocket Scope

The websocket scope creates it for a particular WebSocket session.

Finally, let’s create the bean with websocket scope:

1
2
3
4
5
@Bean
@Scope(scopeName = "websocket", proxyMode = ScopedProxyMode.TARGET_CLASS)
public HelloMessageGenerator websocketScopedBean() {
return new HelloMessageGenerator();
}

WebSocket-scoped beans when first accessed are stored in the WebSocket session attributes. The same instance of the bean is then returned whenever that bean is accessed during the entire WebSocket session.

We can also say that it exhibits singleton behavior but limited to a WebSocket session only.

Specifying Bean Scope

Spring includes the @Scope annotation so that you can specify the scope of a bean.

You can specify that your beans defined with the @Bean annotation should have a specific scope. You can use any of the standard scopes specified in the Bean Scopes section above.

The default scope is singleton, but you can override this with the @Scope annotation, as the following example shows:

1
2
3
4
5
6
7
8
9
@Configuration
public class MyConfiguration {

@Bean
@Scope("prototype")
public Encryptor encryptor() {
// ...
}
}

Method Injection

In most application scenarios, most beans in the container are singletons. When a singleton bean needs to collaborate with another singleton bean or a non-singleton bean needs to collaborate with another non-singleton bean, you typically handle the dependency by defining one bean as a property of the other. A problem arises when the bean lifecycles are different. Suppose singleton bean A needs to use non-singleton (prototype) bean B, perhaps on each method invocation on A. The container creates the singleton bean A only once, and thus only gets one opportunity to set the properties. The container cannot provide bean A with a new instance of bean B every time one is needed.

The solution is to use the @Lookup, namely, Method Injection.

Using @Lookup for Method Injection

@Lookup is a method annotated that tells Spring to return an instance of the method’s return type every time when we invoke it.

First, let’s create a prototype bean that we will later inject into a singleton bean:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package com.mySpringProject.app.testIoC.MethodInjectionSamples;

import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

@Component
@Scope("prototype") // so that everytime a bean of this is created, you get a new SchoolNotification
public class SchoolNotification {
static int count = 0;

public SchoolNotification(){
System.out.println("Notification "+(++count) +" created");
}
}

And if we create a singleton bean that uses @Lookup:

1
2
3
4
5
6
7
8
9
10
11
12
13
package com.mySpringProject.app.testIoC.MethodInjectionSamples;

import org.springframework.beans.factory.annotation.Lookup;
import org.springframework.stereotype.Component;

@Component // no @Scope specifed defaults it to a singleton
public class StudentService {

@Lookup // this will be overridden by the container, calling: beanFactory.getBean()(StudentNotification.class)
public SchoolNotification getSchoolNotification(){
return null; // therefore, whatever you have here doesn't really matter
}
}

Using @Lookup, we can get an new instance of SchoolNotification through our singleton bean** everytime when the method getSchoolNotification is called** (assuming you have a ScopeConfig class with @Configuration and ComponentScan setup correctly):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package com.mySpringProject.app;

import com.mySpringProject.app.testIoC.*;
import com.mySpringProject.app.testIoC.AutowiredSamples.FooService;
import com.mySpringProject.app.testIoC.MethodInjectionSamples.StudentService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Example {
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(ScopeConfig.class);

StudentService stdsrv1 = ctx.getBean(StudentService.class);
StudentService stdsrv2 = ctx.getBean(StudentService.class);
StudentService stdsrv3 = ctx.getBean(StudentService.class);
StudentService stdsrv4 = ctx.getBean(StudentService.class);

stdsrv1.getSchoolNotification();
stdsrv2.getSchoolNotification();
stdsrv3.getSchoolNotification();
stdsrv4.getSchoolNotification();
stdsrv1.getSchoolNotification(); // you will see that the count monotonously increases
}
}

Customizing the Nature of Bean

The Spring Framework provides a number of interfaces you can use to customize the nature of a bean. This section groups them as follows:

  • Lifecycle Callbacks
  • ApplicationContextAware and BeanNameAware
  • Other Aware Interfaces

Lifecycle Callbacks

(additional reference: https://www.tutorialspoint.com/spring/spring_bean_life_cycle.htm; https://www.baeldung.com/running-setup-logic-on-startup-in-spring)

The life cycle of a Spring bean is easy to understand. When a bean is instantiated, it may be required to perform some initialization to get it into a usable state. Similarly, when the bean is no longer required and is removed from the container, some cleanup may be required.

The whole concept of lifecycle callbacks is to solve the problem of handling too much control to the container. For example, We can’t simply include our logic in the beans’ constructors or call methods after instantiation of any object; we are simply not in control during those processes:

1
2
3
4
5
6
7
8
9
10
11
@Component
public class InvalidInitExampleBean {

@Autowired
private Environment env;

public InvalidInitExampleBean() {
env.getActiveProfiles(); // this could get called before Spring bean is fully initialized
// namely, before env gets initialized and attached
}
}

Therefore, this is problematic because calling not yet initialized fields will of course result in NullPointerExceptions.

Initialization Callbacks

The org.springframework.beans.factory.InitializingBean interface lets a bean perform initialization work after the container has set all necessary properties on the bean. The InitializingBean interface specifies a single method:

1
void afterPropertiesSet() throws Exception;

However, it is not recommend that you use the InitializingBean interface, because it unnecessarily couples the code to Spring. Alternatively, we suggest using the @PostConstruct annotation or specifying a POJO initialization method.

The @PostConstruct annotation can be used for annotating** a method that should be run once immediately after the bean’s initialization**. Keep in mind that the annotated method will be executed by Spring even if there is nothing to inject.

Here’s @PostConstruct in action:

1
2
3
4
5
6
7
8
9
10
11
@Component
public class PostConstructExampleBean {

@Autowired
private Environment environment;

@PostConstruct // called immediately after successful initialization
public void betterApproach() {
env.getActiveProfiles();
}
}

In the example above you can see that the Environment instance was safely injected and then called in the @PostConstruct annotated method without throwing a NullPointerException.

Destruction Callbacks

Implementing the org.springframework.beans.factory.DisposableBean interface lets a bean get a callback when the container that contains it is destroyed. The DisposableBean interface specifies a single method:

1
void destroy() throws Exception;

It is recommended that you do not use the DisposableBean callback interface, because it unnecessarily couples the code to Spring. Alternatively, we suggest using the @PreDestroy annotation or specifying a generic method that is supported by bean definitions.

A method annotated with @PreDestroy runs only once, just before Spring removes our bean from the application context.

Same as with @PostConstruct, the methods annotated with @PreDestroy can have any access level but can’t be static.

1
2
3
4
5
6
7
8
9
@Component
public class UserRepository {

private DbConnection dbConnection;
@PreDestroy
public void preDestroy() {
dbConnection.close();
}
}

The purpose of this method should be to release resources or perform any other cleanup tasks before the bean gets destroyed, for example closing a database connection.

Note:

  • Note that both @PostConstruct and @PreDestroy annotations are part of Java EE. And since Java EE has been deprecated in Java 9 and removed in Java 11 we have to add an additional dependency to use these annotations if you are using versions of Java beyond 11.
1
2
3
4
5
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.3.2</version>
</dependency>
Default initMethod and destroyMethod

When you write initialization and destroy method callbacks that do not use the Spring-specific InitializingBean and DisposableBean callback interfaces, you should typically write methods with names such as init(), initialize(), dispose(), and so on. Ideally, the names of such lifecycle callback methods are standardized across a project so that all developers use the same method names and ensure consistency.

More importantly, you can specify a default initMethod property or a destroyMethod that can be used to always execute a method after a bean’s initialization/before destruction.

Here’s what a bean looks like:

1
2
3
4
5
6
7
8
9
10
public class InitMethodExampleBean {

@Autowired
private Environment environment;

public void init() {
// do some initialization work;
// notice no interface nor annotation is used here
}
}

You can notice that there are no special interfaces implemented nor any special annotations used.

Then, we can define the bean using the @Bean(intiMethod="<initMethodName>") annotation:

1
2
3
4
@Bean(initMethod="init")  // the key step
public InitMethodExampleBean exBean() {
return new InitMethodExampleBean();
}

And this is will be equivalent to the XML config:

1
2
3
4
<beans default-init-method="init">
<bean id="initMethodExampleBean" class="com.something.InitMethodExampleBean">
</bean>
</beans>

The presence of the initMethod="init" attribute on the top-level causes the Spring IoC container to recognize a method called init on the bean class as the initialization method callback. When a bean is created and assembled, if the bean class has such a method, it is invoked at the appropriate time.

You can configure destroy method callbacks similarly by using the @Bean(destroyMethod="<destroyMethoName>") attribute on the top-level.

Combining Lifecycle Mechanisms

Multiple lifecycle mechanisms configured for the same bean, with different initialization methods, are called as follows in order:

  • Methods annotated with @PostConstruct
  • afterPropertiesSet() as defined by the InitializingBean callback interface
  • A custom configured init() method

Destroy methods are called in the same order:

  • Methods annotated with @PreDestroy
  • destroy() as defined by the DisposableBean callback interface
  • A custom configured destroy() method
Startup and Shutdown Callbacks

The Lifecycle interface defines the essential methods for any object that has its own lifecycle requirements (such as starting and stopping some background process):

1
2
3
4
5
6
7
8
public interface Lifecycle {

void start();

void stop();

boolean isRunning();
}

Any Spring-managed object may implement the Lifecycle interface. Then, when the ApplicationContext itself receives start and stop signals (for example, for a stop/restart scenario at runtime), it cascades those calls to all Lifecycle implementations defined within that context. It does this by delegating to a LifecycleProcessor, shown in the following listing:

1
2
3
4
5
6
public interface LifecycleProcessor extends Lifecycle {

void onRefresh();

void onClose();
}

Notice that the LifecycleProcessor is itself an extension of the Lifecycle interface. It also adds two other methods for reacting to the context being refreshed and closed.

Note:

  • Note that the regular org.springframework.context.Lifecycle interface is a plain contract for explicit start and stop notifications and does not imply auto-startup at context refresh time. For fine-grained control over auto-startup of a specific bean (including startup phases), consider implementing org.springframework.context.SmartLifecycle instead.
Order of Startup and Shutdown with Dependencies

The order of startup and shutdown invocations can be important. If a “depends-on” relationship exists between any two objects, the dependent side starts after its dependency, and it stops before its dependency. However, sometimes you might not want this order of execution. In this case, you would need to use the SmartLifeCycle Interface:

1
2
3
4
5
6
public interface SmartLifecycle extends Lifecycle, Phased {

boolean isAutoStartup();

void stop(Runnable callback);
}

and the Phased interface looks like:

1
2
3
4
public interface Phased {

int getPhase();
}

When starting, the objects with the lowest phase start first. When stopping, the reverse order is followed. Therefore, an object that implements SmartLifecycle and whose getPhase() method returns Integer.MIN_VALUE would be among the first to start and the last to stop. At the other end of the spectrum, a phase value of Integer.MAX_VALUE would indicate that the object should be started last and stopped first (likely because it depends on other processes to be running). When considering the phase value, it is also important to know that the default phase for any “normal” Lifecycle object that does not implement SmartLifecycle is 0.

Shuttingdown a Non-Web application

If you use Spring’s IoC container in a non-web application environment (for example, in a rich client desktop environment), you should register a shutdown hook with the JVM. Doing so ensures a graceful shutdown and calls the relevant destroy methods on your singleton beans so that all resources are released. You must still configure and implement these destroy callbacks correctly (e.g. with @Bean(destoryMethod="dispose"), and implement the dispose() methods).

To register a shutdown hook, call the registerShutdownHook() method that is declared on the ConfigurableApplicationContext interface, as the following example shows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public final class Boot {

public static void main(final String[] args) throws Exception {
ConfigurableApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");

// add a shutdown hook for the above context...
ctx.registerShutdownHook();

// app runs here...

// main method exits, hook is called prior to the app shutting down...
}
}
ApplicationContextAware and BeanNameAware

When an ApplicationContext creates an object instance that implements the org.springframework.context.ApplicationContextAware interface, the instance is provided with a reference to that ApplicationContext. This means that object could manipulate the container. The following listing shows the definition of the ApplicationContextAware interface:

1
2
3
4
public interface ApplicationContextAware {

void setApplicationContext(ApplicationContext applicationContext) throws BeansException;
}

Thus, beans can programmatically manipulate the ApplicationContext that created them, through the ApplicationContext interface or by casting the reference to a known subclass of this interface (such as ConfigurableApplicationContext, which exposes additional functionality). One use would be the programmatic retrieval of other beans. Sometimes this capability is useful. However, in general, you should avoid it, because it couples the code to Spring and does not follow the Inversion of Control style, where collaborators are provided to beans as properties.

When an ApplicationContext creates a class that implements the org.springframework.beans.factory.BeanNameAware interface, the class is provided with a reference to the bean with name defined in its associated object definition. The following listing shows the definition of the BeanNameAware interface:

1
2
3
4
public interface BeanNameAware {

void setBeanName(String name) throws BeansException;
}

The callback is invoked after population of normal bean properties but before an initialization callback such as InitializingBean, afterPropertiesSet, or a custom init-method.

Bean Definition Inheritance

(additional reference: https://www.tutorialspoint.com/spring/spring_bean_definition_inheritance.htm)

A bean definition can contain a lot of configuration information, including constructor arguments, property values, and container-specific information, such as the initialization method, a static factory method name, and so on. A child bean definition inherits configuration data from a parent definition. The child definition can override some values or add others as needed. Using parent and child bean definitions can save a lot of typing. Effectively, this is a form of templating.

In Java, this should be simple enough to have the extends keyword for that specific class, and then use @Bean at the correct place. You could also inherit an @Configuration class, which will also inherit all the @Bean configurations with it.

Without using the XML file, it should be similar to the normal Java inheritance.

Customizing your Container

Typically, an application developer does not need to subclass ApplicationContext implementation classes. Instead, the Spring IoC container can be extended by plugging in implementations of special integration interfaces, or simply by using some anotations, in order to add some customized functionalities for the container (e.g. @Autowired is one example)

Using @Primary

Because autowiring by type may lead to multiple candidates, it is often necessary to have more control over the selection process. One way to accomplish this is with Spring’s @Primary annotation. @Primary indicates that a particular bean should be given preference when multiple beans are candidates to be autowired to a single-valued dependency. If exactly one primary bean exists among the candidates, it becomes the autowired value.

Consider the following configuration that defines firstMovieCatalog as the primary MovieCatalog if an MovieCatalog is to be autowired:

1
2
3
4
5
6
7
8
9
10
11
12
@Configuration
public class MovieConfiguration {

@Bean
@Primary
public MovieCatalog firstMovieCatalog() { ... }

@Bean
public MovieCatalog secondMovieCatalog() { ... }

// ...
}

With the preceding configuration, the following MovieRecommender is autowired with the firstMovieCatalog:

1
2
3
4
5
6
7
public class MovieRecommender {

@Autowired
private MovieCatalog movieCatalog; // so that the firstMovieCatalog would be created

// ...
}
Using @Qualifier

@Primary is an effective way to use autowiring by type with several instances when one primary candidate can be determined. When you need even more control over the selection process, for example letting each bean to be autowired in a different setting, you can use Spring’s @Qualifier annotation. You can associate qualifier values with specific arguments, narrowing the set of type matches so that a specific bean is chosen for each argument. In the simplest case, this can be a plain descriptive value, as shown in the following example:

1
2
3
4
5
6
7
8
public class MovieRecommender {

@Autowired
@Qualifier("main")
private MovieCatalog movieCatalog;

// ...
}

You can also specify the @Qualifier annotation on individual constructor arguments or method parameters, as shown in the following example:

1
2
3
4
5
6
7
8
9
10
11
public class MovieRecommender {

private MovieCatalog movieCatalog;

@Autowired
public void prepare(@Qualifier("main") MovieCatalog movieCatalog) { // specifies which MovieCatalog gets used
this.movieCatalog = movieCatalog;
}

// ...
}
Type Matching for Generics

In addition to the @Qualifier annotation, you can use Java generic types as an implicit form of qualification. For example, suppose you have the following configuration:

1
2
3
4
5
6
7
8
9
10
11
12
13
@Configuration
public class MyConfiguration {

@Bean
public StringStore stringStore() {
return new StringStore();
}

@Bean
public IntegerStore integerStore() {
return new IntegerStore();
}
}

Assuming that the preceding beans implement a generic interface, (that is, Store<String> and Store<Integer>), you can @Autowire the Store interface and the generic is used as a qualifier, as the following example shows:

1
2
3
4
5
@Autowired
private Store<String> s1; // equivalent as having a <String> qualifier, injects the stringStore bean

@Autowired
private Store<Integer> s2; // equivalent as having a <Integer> qualifier, injects the integerStore bean

Generic qualifiers also apply when autowiring Lists, Map instances and Arrays. The following example autowires a generic List:

1
2
3
4
// Inject all Store beans as long as they have an <Integer> generic
// Store<String> beans will not appear in this list
@Autowired
private List<Store<Integer>> s;
Using @Resource

(additional reference: https://www.baeldung.com/spring-annotations-resource-inject-autowire)

The @Resource annotation is part of the JSR-250 annotation collection and is packaged with Jakarta EE. This is used for field or setter dependency injection. This annotation has the following execution order:

  • Match by Name (if a name is specified as an argument to @Resource, so it resolves the bean with the name specified)
  • Match by Type (if a name is not specified as an argument to @Resource, so it resolves the name by type )
  • Match by Qualifier (if a name is specified as an argument to @Resource, but there is no bean with that name nor resolvable by type, then need to be resolved by @Qualifier)

These execution paths are applicable to both setter and field injection.

  • Field Injection with @Resource

    • Match by name:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      import javax.annotation.Resource;
      import java.io.File;

      public class FieldResourceInjection {

      @Resource(name="namedFile") // injection by finding the corresponding Bean
      private File defaultFile;

      public void printMessage(){
      System.out.println("Hello");
      }
      }

      Your configuration:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      import org.springframework.context.annotation.Bean;
      import org.springframework.context.annotation.Configuration;

      import java.io.File;

      @Configuration
      public class ResourceConfig {

      @Bean(name="namedFile") // match by name
      public File generateFile(){
      return new NamedFile("test NamedFile");
      }

      @Bean(name="annotatedFile")
      public File generateAnotatedFile(){
      return new AnnotatedFile("test NamedFile");
      }

      @Bean
      public FieldResourceInjection testInjectionByName(){
      return new FieldResourceInjection();
      }
      }
    • Match by Type:

      This works the same as having @Autowired, so that you canont have two beans with the same type produced:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      import javax.annotation.Resource;
      import java.io.File;

      public class FieldResourceInjection {

      @Resource // injection by finding the corresponding type amongst the Beans
      private File defaultFile;

      public void printMessage(){
      System.out.println("Hello");
      }
      }

      The Configuration file:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      import org.springframework.context.annotation.Bean;
      import org.springframework.context.annotation.Configuration;

      import java.io.File;

      @Configuration
      public class ResourceConfig {

      @Bean(name="namedFile") // won't work if there is another Bean with outputting a File object
      public File generateFile(){
      return new NamedFile("test NamedFile");
      }

      @Bean
      public FieldResourceInjection testInjectionByName(){
      return new FieldResourceInjection();
      }
      }
    • Match by Qualifier:

      This works the same as match by name, but instead of specifying the name in the @Resource, you specify in @Qualifier():

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      import javax.annotation.Resource;
      import java.io.File;

      public class FieldResourceInjection {

      @Resource
      @Qualifier("namedFile") // injection by finding the corresponding Bean
      private File defaultFile;

      public void printMessage(){
      System.out.println("Hello");
      }
      }

      Your configuration:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      import org.springframework.context.annotation.Bean;
      import org.springframework.context.annotation.Configuration;

      import java.io.File;

      @Configuration
      public class ResourceConfig {

      @Bean(name="namedFile") // match by qualifier, but pretty much the same as Match By Name

      // properly, the following also works
      // @Bean
      // @Qualifer("namedFile")
      public File generateFile(){
      return new NamedFile("test NamedFile");
      }

      @Bean(name="annotatedFile")
      public File generateAnotatedFile(){
      return new AnnotatedFile("test NamedFile");
      }

      @Bean
      public FieldResourceInjection testInjectionByName(){
      return new FieldResourceInjection();
      }
      }
  • Setter Injection

    • The only difference is that the @Resource is placed above the setter method instead of the field. For example, matching by name would look like:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      import javax.annotation.Resource;
      import java.io.File;

      public class FieldResourceInjection {

      private File defaultFile;

      @Resource(name="namedFile") // injection by finding the corresponding Bean
      public void setFile(File namedFile){
      this.defaultFile = namedFile;
      }

      public void printMessage(){
      System.out.println("Hello");
      }
      }

      Your configuration:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      import org.springframework.context.annotation.Bean;
      import org.springframework.context.annotation.Configuration;

      import java.io.File;

      @Configuration
      public class ResourceConfig {

      @Bean(name="namedFile") // match by name
      public File generateFile(){
      return new NamedFile("test NamedFile");
      }

      @Bean(name="annotatedFile")
      public File generateAnotatedFile(){
      return new AnnotatedFile("test NamedFile");
      }

      @Bean
      public FieldResourceInjection testInjectionByName(){
      return new FieldResourceInjection();
      }
      }
    • the other matching schemes follow the same pattern, so they are not shown here.

Using @Value

@Value is typically used to inject externalized properties:

1
2
3
4
5
6
7
8
9
@Component
public class MovieRecommender {

private final String catalog;

public MovieRecommender(@Value("${catalog.name}") String catalog) {
this.catalog = catalog;
}
}

With the following configuration:

1
2
3
@Configuration
@PropertySource("classpath:application.properties") // refers to an external .properties file
public class AppConfig { }

And the following application.properties file:

1
catalog.name=MovieCatalog

In that case, the catalog parameter and field will be equal to the "MovieCatalog" value.

Also, built-in converter support provided by Spring allows simple type conversion (to Integer or int for example) to be automatically handled. Multiple comma-separated values can be automatically converted to String array without extra effort.

When @Value contains a SpEL expression the value will be dynamically computed at runtime as the following example shows:

1
2
3
4
5
6
7
8
public class MovieRecommender {

private final String catalog;

public MovieRecommender(@Value("#{systemProperties['user.catalog'] + 'Catalog' }") String catalog) {
this.catalog = catalog;
}
}

SpEL also enables the use of more complex data structures:

1
2
3
4
5
6
7
8
9
10
@Component
public class MovieRecommender {

private final Map<String, Integer> countOfMoviesPerCatalog;

public MovieRecommender(
@Value("#{{'Thriller': 100, 'Comedy': 300}}") Map<String, Integer> countOfMoviesPerCatalog) {
this.countOfMoviesPerCatalog = countOfMoviesPerCatalog;
}
}

Classpath Scanning and Managed Components

@Component and Further Stereotype Annotations

(additional reference: https://www.baeldung.com/spring-bean-annotations)

For example, the @Repository annotation is a marker for any class that fulfills the role or stereotype of a repository (also known as Data Access Object or DAO). Among the uses of this marker is the automatic translation of exceptions.

Spring provides further stereotype annotations: @Component, @Service, and @Controller. @Component is a generic stereotype for any Spring-managed component. @Repository, @Service, and @Controller are specializations of @Component for more specific use cases (in the persistence, service, and presentation layers, respectively). Therefore, you can annotate your component classes with @Component, but, by annotating them with @Repository, @Service, or @Controller instead, your classes are more properly suited for processing by tools or associating with aspects.

Using @Repository

DAO or Repository classes usually represent the database access layer in an application, and should be annotated with @Repository:

1
2
3
4
@Repository
class VehicleRepository {
// ...
}

One advantage of using this annotation is that it has automatic persistence exception translation enabled. When using a persistence framework such as Hibernate, native exceptions thrown within classes annotated with @Repository will be automatically translated into subclasses of Spring’s DataAccessExeption.

To enable exception translation, we need to declare our own PersistenceExceptionTranslationPostProcessor bean:

1
2
3
4
@Bean
public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
return new PersistenceExceptionTranslationPostProcessor();
}

Note, that in most cases, Spring does the step above automatically.

Using @Service

The business logic of an application usually resides within the service layer – so we’ll use the @Service annotation to indicate that a class belongs to that layer:

1
2
3
4
@Service
public class VehicleService {
// ...
}
Using @Controller

@Controller is a class level annotation which tells the Spring Framework that this class serves as a controller in Spring MVC:

1
2
3
4
@Controller
public class VehicleController {
// ...
}

Automatic Detecting Stereotype Annotations

Spring can automatically detect stereotyped classes and register corresponding BeanDefinition instances with the ApplicationContext. For example, the following two classes are eligible for such autodetection:

1
2
3
4
5
6
7
8
9
@Service
public class SimpleMovieLister {

private MovieFinder movieFinder;

public SimpleMovieLister(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
}

and

1
2
3
4
@Repository
public class JpaMovieFinder implements MovieFinder {
// implementation elided for clarity
}

To autodetect these classes and register the corresponding beans, you need to add @ComponentScan to your @Configuration class, where the basePackages attribute is a common parent package for the two classes. (Alternatively, you can specify a comma- or semicolon- or space-separated list that includes the parent package of each class.)

1
2
3
4
5
@Configuration
@ComponentScan(basePackages = "org.example")
public class AppConfig {
// ...
}

Customizing ComponentScanning using Filters

By default, classes annotated with @Component,@Repository, @Service, @Controller, @Configuration, or a custom annotation that itself is annotated with @Component are the only detected candidate components. However, you can modify and extend this behavior by applying custom filters. Add them as includeFilters or excludeFilters attributes of the @ComponentScan annotation.

Filter Type Example Expression Description
annotation (default) SomeAnnotation An annotation to be present or meta-present at the type level in target components.
assignable SomeClass A class (or interface) that the target components are assignable to (extend or implement).
aspectj .*Service+ An AspectJ type expression to be matched by the target components.
regex org.example.Default.* A regex expression to be matched by the target components’ class names.
custom MyTypeFilter A custom implementation of the org.springframework.core.type.TypeFilter interface.

For example, you can have the configuration to** ignoring all @Repository annotations** and using “stub” repositories instead:

1
2
3
4
5
6
7
@Configuration
@ComponentScan(basePackages = "org.example",
includeFilters = @Filter(type = FilterType.REGEX, pattern = ".*Stub.*Repository"),
excludeFilters = @Filter(Repository.class))
public class AppConfig {
...
}

AOP - Aspect Oriented Programming with Spring

(additional reference: https://www.tutorialspoint.com/springaop/springaop_overview.htm)

Aspect-oriented Programming (AOP) complements Object-oriented Programming (OOP) by providing another way of thinking about program structure. The key unit of modularity in OOP is the class, whereas in AOP the unit of modularity is the aspect. Aspects enable the modularization of concerns (such as transaction management) that cut across multiple types and objects. (Such concerns are often termed “crosscutting” concerns in AOP literature.)

One of the key components of Spring is the AOP framework. While the Spring IoC container does not depend on AOP (meaning you do not need to use AOP if you don’t want to), AOP complements Spring IoC to provide a very capable middleware solution.

The key unit of modularity in OOP is the class, whereas in AOP the unit of modularity is the aspect. Dependency Injection helps you decouple your application objects from each other, while AOP helps you decouple cross-cutting concerns from the objects that they affect. AOP is like triggers in programming languages such as Perl, .NET, Java, and others.

Spring AOP module lets interceptors intercept an application. For example, when a method is executed, you can add extra functionality before or after the method execution.

Core Concepts in AOP

Before we start working with AOP, let us become familiar with the AOP concepts and terminologies. These terms are not specific to Spring, rather they are related to AOP.

Terms Description
Aspect A module which has a set of APIs providing cross-cutting requirements. For example, a logging module would be called AOP aspect for logging. An application can have any number of aspects depending on the requirement.
Join point This represents a point in your application where you can plug-in AOP aspect. You can also say, it is the actual place in the application where an action will be taken using Spring AOP framework.
Advice This is the** actual action to be taken either before or after the method execution. This is the **actual piece of code that is invoked during program execution by Spring AOP framework.
PointCut This is a set of one or more joinpoints where an advice should be executed. You can specify PointCuts using expressions or patterns as we will see in our AOP examples.
Introduction An introduction allows you to add new methods or attributes to existing classes.
Target object The object being advised by one or more aspects. This object will always be a proxied object. Also referred to as the advised object.
AOP proxy An object created by the AOP framework in order to implement the aspect contracts (advise method executions and so on). In the Spring Framework, an AOP proxy is a JDK dynamic proxy or a CGLIB proxy.
Weaving Weaving is the process of linking aspects with other application types or objects to create an advised object. This can be done at compile time, load time, or at runtime.

Spring aspects can work with five kinds of advice mentioned in the following table.

Advice Type Description
before Run advice before the method execution.
after Run advice after the method execution, regardless of its outcome.
after-returning Run advice after the method execution, only if the method completes successfully.
after-throwing Run advice after the method execution, only if the method exits by throwing an exception.
around Run advice before and after the advised method is invoked.

Around advice is the most general kind of advice. Since Spring AOP, like AspectJ, provides a full range of advice types, it is recommended that you use the least powerful advice type that can implement the required behavior. For example, if you need only to update a cache with the return value of a method, you are better off implementing an after returning advice than an around advice, although an around advice can accomplish the same thing. Using the most specific advice type provides a simpler programming model with less potential for errors.

The concept of join points matched by pointcuts is the key to AOP, which distinguishes it from older technologies offering only interception. Pointcuts enable advice to be targeted independently of the object-oriented hierarchy. For example, you can apply an around advice providing declarative transaction management to a set of methods that span multiple objects (such as all business operations in the service layer).

Enabling AspectJ

To use annotations from AspectJ, you need to make sure that you have the aspectjweaver.jar in your classpath. Since we are using Maven and will be mainly focused on Java-annotation based, it is as simple as adding a dependency in your POM file:

1
2
3
4
5
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.9</version>
</dependency>

Then, to enable @AspectJ support with Java @Configuration, add the @EnableAspectJAutoProxy annotation, as the following example shows:

1
2
3
4
5
@Configuration
@EnableAspectJAutoProxy
public class AppConfig {

}

Note:

  • By auto-proxying, we mean that, if Spring determines that a bean is advised by one or more aspects, it automatically generates a proxy for that bean to intercept method invocations and ensures that advice is executed as needed.
Declaring an Aspect

With @AspectJ support enabled, any bean defined in your application context with a class that is an @AspectJ aspect (has the @Aspect annotation) is automatically detected by Spring and used to configure Spring AOP.

The following shows a NotVeryUsefulAspect class definition, which is annotated with the org.aspectj.lang.annotation.Aspect annotation to become an aspect:

1
2
3
4
5
6
7
package org.xyz;
import org.aspectj.lang.annotation.Aspect;

@Aspect
public class NotVeryUsefulAspect {

}

Aspects (classes annotated with @Aspect) can have methods and fields, the same as any other class. They can also contain pointcut, advice, and introduction (inter-type) declarations.

Note:

  • You can register aspect classes as regular beans in your Spring XML configuration or autodetect them through classpath scanning — the same as any other Spring-managed bean. However, note that the @Aspectannotation is not sufficient for autodetection in the classpath. For that purpose, you need to add a separate @Component annotation (or, alternatively, a custom stereotype annotation that qualifies, as per the rules of Spring’s component scanner).
  • In Spring AOP, aspects themselves cannot be the targets of advice from other aspects. The @Aspect annotation on a class marks it as an aspect and, hence, excludes it from auto-proxying.

Declaring a Pointcut

Pointcuts determine join points of interest and thus enable us to control when advice executes. Spring AOP only supports method execution join points for Spring beans, so you can think of a pointcut as matching the execution of methods on Spring beans.

A pointcut declaration has two parts:

  • a method signature comprising a name and any parameters
    • this will look like a standard java method, except that it must have a void return type
  • a pointcut expression that determines exactly which method executions we are interested in.

The following example defines a pointcut named anyOldTransfer that matches the execution of any method named transfer:

1
2
3
@Pointcut("execution(* transfer(..))") // the pointcut expression
private void anyOldTransfer() {} // the pointcut signature
// this can be used later for advice annotations to refer to this pointcut.

The pointcut expression that forms the value of the @Pointcut annotation is a regular AspectJ 5 pointcut expression. For a full discussion of AspectJ’s pointcut language, see the Offical AspectJ Programming Guide.

Supported Pointcut Designators

Spring AOP supports the following AspectJ pointcut designators (PCD) for use in pointcut expressions:

  • execution: For matching method execution join points. This is the primary pointcut designator to use when working with Spring AOP.
  • within: Limits matching to join points within certain types (the execution of a method declared within a matching type when using Spring AOP).
  • this: Limits matching to join points (the execution of methods when using Spring AOP) where the bean reference (Spring AOP proxy) is an instance of the given type.
  • target: Limits matching to join points (the execution of methods when using Spring AOP) where the target object (application object being proxied) is an instance of the given type.
  • args: Limits matching to join points (the execution of methods when using Spring AOP) where the arguments are instances of the given types.
  • @target: Limits matching to join points (the execution of methods when using Spring AOP) where the class of the executing object has an annotation of the given type.
  • @args: Limits matching to join points (the execution of methods when using Spring AOP) where the runtime type of the actual arguments passed have annotations of the given types.
  • @within: Limits matching to join points** within types that have the given annotation (the execution of methods declared in types with the given annotation when using Spring AOP)**.
  • @annotation: Limits matching to join points where the subject of the join point (the method being executed in Spring AOP) has the given annotation.
  • bean: Spring AOP also supports an additional PCD named bean. This PCD lets you limit the matching of join points to a particular named Spring bean or to a set of named Spring beans (when using wildcards).

More on using "execution"

Spring AOP users are likely to use the execution pointcut designator the most often. The format of an execution expression follows:

1
execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern) throws-pattern?)

All parts except the returning type pattern (ret-type-pattern in the preceding snippet), the name pattern, and the parameters pattern are optional (the ones ending with “?“ are optional). The returning type pattern determines what the return type of the method must be in order for a join point to be matched. * is most frequently used as the returning type pattern. It matches any return type. A fully-qualified type name matches only when the method returns the given type. The name pattern matches the method name. You can use the * wildcard as all or part of a name pattern. If you specify a declaring type pattern, include a trailing . to join it to the name pattern component. The parameters pattern is slightly more complex: () matches a method that takes no parameters, whereas (..) matches any number (zero or more) of parameters. The (*) pattern matches a method that takes one parameter of any type. (*,String) matches a method that takes two parameters. The first can be of any type, while the second must be a String. Consult the Language Semantics section of the AspectJ Programming Guide for more information.

Note:

  • Declaring type pattern means: Package or class (ex: com.app.service.* - applies to all classes in this package; com.app.service.UserService - applies only to UserService class; * - all)

Combining PointCut Expressions

You can combine pointcut expressions by using &&, || and !. You can also refer to pointcut expressions by name(method name). The following example shows three pointcut expressions:

1
2
3
4
5
6
7
8
9
10
@Pointcut("execution(public * *(..))")  // anyPublicOperation matches if a method execution
// join point represents the execution of any public method.
private void anyPublicOperation() {}

@Pointcut("within(com.xyz.someapp.trading..*)") // inTrading matches if a method execution is in the trading module.
private void inTrading() {}

@Pointcut("anyPublicOperation() && inTrading()") // tradingOperation matches if a method execution
// represents any public method in the trading module.
private void tradingOperation() {}

Examples of common PCDs

The following examples show some common pointcut expressions:

The execution of any public method (any return-type, any name, any number of arguments):

1
execution(public * *(..))

The execution of any method with a name that begins with set:

1
execution(* set*(..))

The execution of any method defined by the AccountService interface:

1
execution(* com.xyz.service.AccountService.*(..))

The execution of any method defined in the servicepackage:

1
execution(* com.xyz.service.*.*(..))  // notice the extra "." needed connecting the package name and method name

The execution of any method defined in the service package or one of its sub-packages:

1
execution(* com.xyz.service..*.*(..))

Any join point (method execution only in Spring AOP, not all methods) within the service package:

1
within(com.xyz.service.*)

Any join point (method execution only in Spring AOP) within the service package or one of its sub-packages:

1
within(com.xyz.service..*)

Any join point (method execution only in Spring AOP) where the proxy implements the AccountService interface:

1
this(com.xyz.service.AccountService)

Any join point (method execution only in Spring AOP) where the target object implements the AccountService interface:

1
target(com.xyz.service.AccountService)

Any join point (method execution only in Spring AOP) that takes a single parameter and where the argument passed at runtime is Serializable:

1
args(java.io.Serializable)

Any join point (method execution only in Spring AOP) where the target object has a @Transactional annotation:

1
@target(org.springframework.transaction.annotation.Transactional)

Any join point (method execution only in Spring AOP) where the declared type of the target object has an @Transactional annotation:

1
@within(org.springframework.transaction.annotation.Transactional)

Any join point (method execution only in Spring AOP) where the executing method has an @Transactional annotation:

1
@annotation(org.springframework.transaction.annotation.Transactional)

Any join point (method execution only in Spring AOP) which takes a single parameter, and where the runtime type of the argument passed has the @Classified annotation:

1
@args(com.xyz.security.Classified)

Any join point (method execution only in Spring AOP) on a Spring bean named tradeService:

bean(tradeService)

Any join point (method execution only in Spring AOP) on Spring beans having names that match the wildcard expression *Service:

bean(*Service)

Structuring your Pointcuts

When working with enterprise applications, developers often want to refer to modules of the application and particular sets of operations from within several aspects. It is recommended to define a “SystemArchitecture” aspect that captures common pointcut expressions for this purpose. Such an aspect typically resembles the following example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
package com.xyz.someapp;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;

@Aspect
public class SystemArchitecture {

/**
* A join point is in the web layer if the method defined
* is in the com.xyz.someapp.web package or any sub-package
* under that.
*/
@Pointcut("within(com.xyz.someapp.web..*)")
public void inWebLayer() {}

/**
* A join point is in the service layer if the method defined
* is in the com.xyz.someapp.service package or any sub-package
* under that.
*/
@Pointcut("within(com.xyz.someapp.service..*)")
public void inServiceLayer() {}

/**
* A join point is in the data access layer if the method defined
* is in the com.xyz.someapp.dao package or any sub-package
* under that.
*/
@Pointcut("within(com.xyz.someapp.dao..*)")
public void inDataAccessLayer() {}

/**
* A business service is the execution of any method defined on a service
* interface. This definition assumes that interfaces are placed in the
* "service" package, and that implementation types are in sub-packages.
*
* If you group service interfaces by functional area (for example,
* in packages com.xyz.someapp.abc.service and com.xyz.someapp.def.service) then
* the pointcut expression "execution(* com.xyz.someapp..service.*.*(..))"
* could be used instead.
*
* Alternatively, you can write the expression using the 'bean'
* PCD, like so "bean(*Service)". (This assumes that you have
* named your Spring service beans in a consistent fashion.)
*/
@Pointcut("execution(* com.xyz.someapp..service.*.*(..))")
public void businessService() {}

/**
* A data access operation is the execution of any method defined on a
* dao interface. This definition assumes that interfaces are placed in the
* "dao" package, and that implementation types are in sub-packages.
*/
@Pointcut("execution(* com.xyz.someapp.dao.*.*(..))")
public void dataAccessOperation() {}

}

Writing good Pointcuts

During compilation, AspectJ processes pointcuts in order to optimize matching performance. Examining code and determining if each join point matches (statically or dynamically) a given pointcut is a costly process. (A dynamic match means the match cannot be fully determined from static analysis and that a test is placed in the code to determine if there is an actual match when the code is running). On first encountering a pointcut declaration, AspectJ rewrites it into an optimal form for the matching process. What does this mean? Basically, pointcuts are rewritten in DNF (Disjunctive Normal Form) and the components of the pointcut are sorted such that those components that are cheaper to evaluate are checked first. This means you do not have to worry about understanding the performance of various pointcut designators and may supply them in any order in a pointcut declaration.

However, AspectJ can work only with what it is told. For optimal performance of matching, you should think about what they are trying to achieve and narrow the search space for matches as much as possible in the definition. The existing designators naturally fall into one of three groups: kinded, scoping, and contextual:

  • Kinded designators select a particular kind of join point: execution, get, set, call, and handler.
  • Scoping designators select a group of join points of interest (probably of many kinds): within and withincode
  • Contextual designators match (and optionally bind) based on context: this, target, and @annotation

A well written pointcut should include at least the first two types (kinded and scoping). You can include the contextual designators to match based on join point context or bind that context for use in the advice. Supplying only a kinded designator or only a contextual designator works but could affect weaving performance (time and memory used), due to extra processing and analysis.

Declaring an Advice

Advice is** associated with a pointcut expression and runs before, after, or around method executions matched by the pointcut**. The pointcut expression may be either a simple reference to a named pointcut or a pointcut expression declared in place.

In plain words, pointcuts matches the place/method execution, and the advice is the actual piece of code that will execute at that pointcut position (could be before (the method execution), after (the method execution), or around (the method execution)).

Before

You can declare before advice in an aspect by using the @Before annotation. This will then execute (if matched) before the execution of the matched method:

1
2
3
4
5
6
7
8
9
10
11
12
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

@Aspect
public class BeforeExample {

@Before("com.xyz.myapp.SystemArchitecture.dataAccessOperation()") // a better approach would be having a pointcut
public void doAccessCheck() {
// ...
}

}

Now, you could utilize the pointcutting scheme you learnt, which can be applied in two ways in an Advice:

  • in-place pointcut expression
  • refering to the pointcut expression

For example, the following two would be equivalent as the above:

1
2
3
4
5
6
7
8
9
10
11
12
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

@Aspect
public class BeforeExample {

@Before("execute(* com.xyz.myapp.SystemArchitecture.dataAccessOperation(**))")
public void doAccessCheck() {
// ...
}

}

or the recommended if suitable approach:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;

@Aspect
public class BeforeExample {

@Pointcut("execute(* com.xyz.myapp.SystemArchitecture.dataAccessOperation(**))")
public void daoProcess(){}

@Before("daoProcess()") // uses that Pointcut
public void doAccessCheck() {
// ...
}
}
After Returning Advice

After returning advice runs when a matched method execution returns normally. You can declare it by using the @AfterReturning annotation:

1
2
3
4
5
6
7
8
9
10
11
12
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.AfterReturning;

@Aspect
public class AfterReturningExample {

@AfterReturning("com.xyz.myapp.SystemArchitecture.dataAccessOperation()")
public void doAccessCheck() {
// ...
}

}

Note that you can have multiple advice declarations (and other members as well), all inside the same aspect. We show only a single advice declaration in these examples to focus the effect of each one.

One useful feature of After returning advice is that you can use the return value of that method to do some additional work:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.AfterReturning;

@Aspect
public class AfterReturningExample {

@AfterReturning(
pointcut="com.xyz.myapp.SystemArchitecture.dataAccessOperation()",
returning="retVal") // this needs to be the same as the object in the argument below
public void doAccessCheck(Object retVal) { // this matches the return object for all types
// ...
}

}

The name used in the returning attribute must correspond to the name of a parameter in the advice method.** When a method execution returns, the return value is passed to the advice method as the corresponding argument value.** A returning clause also restricts matching to only those method executions that return a value of the specified type (in this case, Object, which matches any return value).

After Throwing Advice

After throwing advice runs when a matched method execution exits by throwing an exception. You can declare it by using the @AfterThrowing annotation, as the following example shows:

1
2
3
4
5
6
7
8
9
10
11
12
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.AfterThrowing;

@Aspect
public class AfterThrowingExample {

@AfterThrowing("com.xyz.myapp.SystemArchitecture.dataAccessOperation()")
public void doRecoveryActions() {
// ...
}

}

Often, you want the advice to run only when exceptions of a given type are thrown, and you also often need access to the thrown exception in the advice body. You can use the throwing attribute to both restrict matching (if desired — use Throwable as the exception type otherwise) and bind the thrown exception to an advice parameter. The following example shows how to do so:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.AfterThrowing;

@Aspect
public class AfterThrowingExample {

@AfterThrowing(
pointcut="com.xyz.myapp.SystemArchitecture.dataAccessOperation()",
throwing="ex") // so that you can use that thrown exception
public void doRecoveryActions(DataAccessException ex) { // if the Exception ex is NOT of type DataAccessException,
// this will NOT run
// ...
}

}

The name used in the throwing attribute must correspond to the name of a parameter in the advice method. When a method execution exits by throwing an exception, the exception is passed to the advice method as the corresponding argument value. A throwing clause also restricts matching to only those method executions that throw an exception of the specified type (DataAccessException, in this case).

After (Finally) Advice

After (finally) advice runs when a matched method execution exits. It is declared by using the @Afterannotation. After advice must be prepared to handle both normal and exception return conditions. It is typically used for releasing resources and similar purposes. The following example shows how to use after finally advice:

1
2
3
4
5
6
7
8
9
10
11
12
13
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.After;

@Aspect
public class AfterFinallyExample {

@After("com.xyz.myapp.SystemArchitecture.dataAccessOperation()") // runs no matter if the matched method
// exits successfully or not
public void doReleaseLock() {
// ...
}

}
Around Advice

The last kind of advice is around advice. Around advice runs “around” a matched method’s execution. It has the opportunity to do work both before and after the method executes and to determine when, how, and even if the method actually gets to execute at all (see the next paragraph). Around advice is often used if you need to share state before and after a method execution in a thread-safe manner (starting and stopping a timer, for example). Always use the least powerful form of advice that meets your requirements (that is, do not use around advice if before advice would do).

Around advice is declared by using the @Around annotation. The first parameter of the advice method must be of type ProceedingJoinPoint. Within the body of the advice, calling proceed() on the ProceedingJoinPoint causes the underlying method to execute. The proceed method can also pass in an Object[]. The values in the array are used as the arguments to the method execution when it proceeds.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.ProceedingJoinPoint;

@Aspect
public class AroundExample {

@Around("com.xyz.myapp.SystemArchitecture.businessService()")
public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable {
// start stopwatch
Object retVal = pjp.proceed();
// stop stopwatch
return retVal;
}

}

Note that proceed() may be invoked once, many times, or not at all within the body of the around advice. All of these are legal.

Additionally, there are other methods of the ProceedingJoinPoint object that you can use to fetch information about the method that your are pointcutting:

  • getArgs(): Returns the method arguments.
  • getThis(): Returns the proxy object.
  • getTarget(): Returns the target object.
  • getSignature(): Returns a description of the method that is being advised.
  • toString(): Prints a useful description of the method being advised.

Passing Parameters to Advice

We have already seen how to bind the returned value or exception value (using after returning and after throwing advice). To make argument values available to the advice body, you can use the binding form of args.

If you use a parameter name in place of a type name in an args expression, the value of the corresponding argument is passed as the parameter value when the advice is invoked. An example should make this clearer. Suppose you want to advise the execution of DAO operations that take an Account object as the first parameter, and you need access to that Account object in the advice body. You could write the following:

1
2
3
4
@Before("com.xyz.myapp.SystemArchitecture.dataAccessOperation() && args(account,..)")
public void validateAccount(Account account) {
// ...
}

The args(account,..) part of the pointcut expression serves two purposes.

  • First, it restricts matching to only those method executions where the method takes at least one parameter, and the argument passed to that parameter is an instance of Account.
  • Second, it makes the actual Account object available to the advice through the account parameter.

Another way of writing this is to declare a Pointcut that “provides” the Account object value when it matches a join point, and then refer to the named pointcut from the advice. This would look as follows:

1
2
3
4
5
6
7
@Pointcut("com.xyz.myapp.SystemArchitecture.dataAccessOperation() && args(account,..)")  // Pointcutting
private void accountDataAccessOperation(Account account) {}

@Before("accountDataAccessOperation(account)") // notice it is passed in here as well
public void validateAccount(Account account) {
// ...
}

Using Advice Parameters for Generics

Spring AOP can handle generics used in class declarations and method parameters. Suppose you have a generic type like the following:

1
2
3
4
public interface Sample<T> {
void sampleGenericMethod(T param);
void sampleGenericCollectionMethod(Collection<T> param);
}

You can restrict interception of method types to certain parameter types by typing the advice parameter to the parameter type for which you want to intercept the method:

1
2
3
4
@Before("execution(* ..Sample+.sampleGenericMethod(*)) && args(param)")
public void beforeSampleMethod(MyType param) {
// Advice implementation
}

Howver, this approach does not work for generic Collections. So you cannot define a pointcut as follows:

1
2
3
4
@Before("execution(* ..Sample+.sampleGenericCollectionMethod(*)) && args(param)")
public void beforeSampleMethod(Collection<MyType> param) {
// Advice implementation
}

To make this work, we would have to inspect every element of the collection, which is not reasonable, as we also cannot decide how to treat null values in general. To achieve something similar to this, you have to type the parameter to Collection<?> and manually check the type of the elements.

Advice Ordering

The problem comes when you have multiple advice executing at the same join point. Suppose you have two advices running at the same join point,, what would happen?

  • The *highest precedence advice (@Order(<the smallest int>)) runs first “on the way in” *(so, given two pieces of before advice, the one with highest precedence runs first).
  • “On the way out” from a join point, the highest precedence advice (@Order(<the smallest int>)) runs last (so, given two pieces of after advice, the one with the highest precedence will run second).

Note that this means both (or more if you do have more) advices WILL execute, but the order of execution will be defined by the @Order annotation that you specify.

For example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
@Aspect
public class AspectModule1 {

@Pointcut("execution(* com.mySpringProject.app.testIoC.MethodInjectionSamples.*.get*(..))")
public void testPointCut(){
System.out.println("Placed a Pointcut here");
}

@Before("testPointCut()")
@Order(1) // this will run first
public void printMessage(){
System.out.println("Pointcutted 1 Entering here");
}

@Before("testPointCut()")
@Order(2) // this runs second
public void printMessage2(){
System.out.println("Pointcutted 2 Entering here");
}

@After("testPointCut()")
@Order(1) // this will run last
public void printMessage(){
System.out.println("Pointcutted 1 Exiting here");
}

@After("testPointCut()")
@Order(2) // this runs second last
public void printMessage2(){
System.out.println("Pointcutted 2 Exiting here");
}
}

Note:

  • When two pieces of advice defined in different aspects both need to run at the same join point, unless you specify otherwise, the order of execution is undefined.

Using Introductions/@DeclareParents

Introductions (known as inter-type declarations in AspectJ) enable an aspect to declare that advised objects implement a given interface, and to provide an implementation of that interface on behalf of those objects.

You can make an introduction by using the @DeclareParents annotation. This annotation is used to declare that matching types have a new parent (hence the name).

For example, given an interface named UsageTracked and an implementation of that interface named DefaultUsageTracked, the following aspect declares that all implementors of service interfaces also implement the UsageTracked interface.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.DeclareParents;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class AspectConfig {

// this should make them all implement the Interface ProvidePrint, using implementations of DefaultPrint
@DeclareParents(value="com.mySpringProject.app.testIoC.IntroductionsWithDeclareParents.*",
defaultImpl = DefaultPrint.class)
public static ProvidePrint testObj; // the Interface that matching classes will implement

}

with the simple interface ProvidePrint:

1
2
3
4
5
package com.mySpringProject.app.testIoC.IntroductionsWithDeclareParents;

public interface ProvidePrint {
public void printIntroductionMessage();
}

Now, suppose there is just one class inside that package:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package com.mySpringProject.app.testIoC.IntroductionsWithDeclareParents;

// unaware of the interface ProvidePrint
public class NormalObject {
private int count;

public NormalObject(int count) {
this.count = count;
}

public int getCount() {
return count;
}

public void setCount(int count) {
this.count = count;
}

}

and you have that defaultImp = DefaultPrint.class:

1
2
3
4
5
6
7
8
package com.mySpringProject.app.testIoC.IntroductionsWithDeclareParents;

public class DefaultPrint implements ProvidePrint{
@Override
public void printIntroductionMessage() {
System.out.println("Default Implementations.");
}
}

Then the result is that any bean created inside/being matched by the package value="com.mySpringProject.app.testIoC.IntroductionsWithDeclareParents.*" will all automatically implement the necessary method public void printIntroductionMessage(), with the actual implementation using the one from defaultImpl = DefaultPrint.class.

So that when you create that NormalObject class using a bean, you can:

1
2
3
NormalObject testObj = ctx.getBean(NormalObject.class);
System.out.println("Count is: "+testObj.getCount()); // to test we get the correct object
((ProvidePrint)testObj).printIntroductionMessage(); // it will automatically implement the interface we specified

However, what if the interface method public void printIntroductionMessage(); has already been implemented by that NormalObject class? It turns out that the container will run the method native to that NormalObject class in the end. This means that the implementation in your DefaultImplementation class will only run if the method has not been implemented.

Understanding the Mechanism of an AOP Proxy

Spring AOP is proxy-based. It is vitally important that you grasp the semantics of what that last statement actually means before you write your own aspects or use any of the Spring AOP-based aspects supplied with the Spring Framework.

Consider first the scenario where you have a plain-vanilla, un-proxied, nothing-special-about-it, straight object reference, as the following code snippet shows:

1
2
3
4
5
6
7
8
9
10
11
public class SimplePojo implements Pojo {

public void foo() {
// this next method invocation is a direct call on the 'this' reference
this.bar();
}

public void bar() {
// some logic...
}
}

Now, when you use this class and call the method foo():

1
2
3
4
5
6
7
8
public class Main {

public static void main(String[] args) {
Pojo pojo = new SimplePojo();
// this is a direct method call on the 'pojo' reference
pojo.foo();
}
}

This means that JVM first reaches that object Pojo, then looks for the foo() method, and finally executes and returns the result back if there is any return arguments.

However, things change slightly when the reference that client code has is a proxy. Consider the following diagram and code snippet:

1
2
3
4
5
6
7
8
9
10
11
12
public class Main {

public static void main(String[] args) {
ProxyFactory factory = new ProxyFactory(new SimplePojo());
factory.addInterface(Pojo.class);
factory.addAdvice(new RetryAdvice());

Pojo pojo = (Pojo) factory.getProxy();
// this is a method call on the proxy!
pojo.foo();
}
}

The key thing to understand here is that the client code inside the main(..) method of the Main class has a reference to the proxy, which contains an inner reference to the actual object you built. This means that method (pojo.foo()) calls on that object reference are calls on the proxy. Therefore, you can see it as the proxy having the full power to control the executions of that object you built.

As a result, the proxy can delegate to all of the interceptors (advice) that are relevant to that particular method call. However, once the call has finally reached the target object (the SimplePojo, reference in this case), any method calls that it may make on itself, such as this.bar() or this.foo(), are going to be invoked against the actual object/SimplePojo reference, and not the proxy.

This has important implications. It means that self-invocation is not going to result in the advice associated with a method invocation getting a chance to execute.

Okay, so what is to be done about this? The best approach (the term, “best,” is used loosely here) is to refactor your code such that the self-invocation does not happen. This does entail some work on your part, but it is the best, least-invasive approach. The next approach is absolutely horrendous, and we hesitate to point it out, precisely because it is so horrendous. You can (painful as it is to us) totally tie the logic within your class to Spring AOP, as the following example shows:

1
2
3
4
5
6
7
8
9
10
11
public class SimplePojo implements Pojo {

public void foo() {
// this works, but... gah!
((Pojo) AopContext.currentProxy()).bar();
}

public void bar() {
// some logic...
}
}

This totally couples your code to Spring AOP, and it makes the class itself aware of the fact that it is being used in an AOP context, which flies in the face of AOP. It also requires some additional configuration when the proxy is being created, as the following example shows:

1
2
3
4
5
6
7
8
9
10
11
12
13
public class Main {

public static void main(String[] args) {
ProxyFactory factory = new ProxyFactory(new SimplePojo());
factory.addInterface(Pojo.class);
factory.addAdvice(new RetryAdvice());
factory.setExposeProxy(true);

Pojo pojo = (Pojo) factory.getProxy();
// this is a method call on the proxy!
pojo.foo();
}
}

Finally, it must be noted that AspectJ does not have this self-invocation issue because it is not a proxy-based AOP framework. (However, since this guide do uses the AOP framework, this is relevant.)

Manually Creating @AspectJ Proxies

If you used @EnableAspectJAutoProxy, then this will not be necessary (also, as I tested in my program, once this is declared (at any place), the auto proxy mechanism will be enabled everywhere in the same project). However, if you want to have full control of what is happening under the hood, you can choose to manually create/add proxies to your POJOs.

You can use the org.springframework.aop.aspectj.annotation.AspectJProxyFactory class to create a proxy for a target object that is advised by one or more @AspectJ aspects. The basic usage for this class is very simple, as the following example shows:

1
2
3
4
5
6
7
8
9
10
11
12
// create a factory that can generate a proxy for the given target object
AspectJProxyFactory factory = new AspectJProxyFactory(targetObject);

// add an aspect, the class must be an @AspectJ aspect
// you can call this as many times as you need with different aspects
factory.addAspect(SecurityManager.class);

// you can also add existing aspect instances, the type of the object supplied must be an @AspectJ aspect
factory.addAspect(usageTracker);

// now get the proxy object...
MyInterfaceType proxy = factory.getProxy();