What is Spring Aspect Oriented Programming?

I have to admit that AOP and all the concepts behind it are not easy to catch at the beginning. After reading some definitions about Spring-aop and looking examples, I found a good and simple definition that I’d like to share:

“Spring AOP (Aspect-oriented programming) framework is used to modularize cross-cutting concerns in aspects. Put it simple, it’s just an interceptor to intercept some processes, for example, when a method is executed, Spring AOP can hijack the executing method, and add extra functionality before or after the method execution” https://mkyong.com/spring/spring-aop-examples-advice/.

Examples that are mentioned in many sites are related to logging and verification and in most cases are temporal or have a cross-cutting concern, it means a same code that needs to be used in many places (temporal or not) could be hijacked without changing the original code.

How can I use it?

Well to start simple, we can create a custom annotation and then use AOP to understand how it works.

Dependencies

In this example, I’m using Spring Boot and the AOP starter that pulls the libraries required to implement with Aspects.

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.3.12.RELEASE</version>
</parent>

<dependencies>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
</dependencies>

Custom Annotation

I’m creating an annotation where I define that it only can be used by methods, and it will be available to the JVM at runtime.

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface LogElapsedTime {

}

Example Service Component

Now, let’s create a component with a fake slow method and then include our annotation, until now we don’t have any Aspect configured yet.

@Component
public class ExampleService {

    @LogElapsedTime
    public void simulateSlowMethod() throws InterruptedException {
        Thread.sleep((int)(Math.random() * 1000));
    }
}

Example Aspect Component

Let’s create another component and in this case annotate also with @Aspect. In this component we need to create the pointcut and advice. I defined the advice to be @Around, it means I’m including extra code before and after the method execution. The advice argument is the pointcut and it says to apply when the @LogElapsedTime annotation is used.

The goal is to inject extra code to log how much time some methods take to finish. As you can see it’s very flexible and to include any method in this flow just needs an annotation.

@Aspect
@Component
@Slf4j
public class ExampleAspect {

    @Around("@annotation(com.sample.aop.LogElapsedTime)")
    public Object logElapsedTime(ProceedingJoinPoint joinPoint) throws Throwable {
        long startTime = System.currentTimeMillis();
        Object proceed = joinPoint.proceed();
        log.info(String.format("%s took %d ms", joinPoint.getSignature(), System.currentTimeMillis() - startTime));
        return proceed;
    }

}

Testing

The happy part, to test it and see how it works!

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
public class LogElapsedTimeTest {

    @Autowired
    private ExampleService service;

    @Test
    public void validateLogElapsedTimeAnnotation() throws InterruptedException {
        service.simulateSlowMethod();
    }

}

The complete code is available in my Github repository.

I hope it helps to understand better.

References:

[1] https://docs.spring.io/spring-framework/docs/2.5.x/reference/aop.html

[2] https://mkyong.com/spring/spring-aop-examples-advice/

[3] https://www.baeldung.com/spring-aop-annotation

Spring Bean Scopes

With a simple Spring annotation you get the flexibility to choose the scope of a bean definition and objects created for a particular bean definition.

The scope of a bean defines the lifecycle and visibility of a bean inside a given context. In case of Spring Framework we have the following types:

  • Singleton
  • Prototype
  • Request
  • Session
  • Application
  • Websocket

Singleton

It’s the default scope, the container will create a single instance of a bean and every request for this bean will return the same object which is cached. This scope reaches only the ApplicationContext.

@Bean
@Scope(value = ConfigurableBeanFactory.SCOPE_SINGLETON)

Prototype

In this case the container will create a new object each time a request is made to this bean. It’s mostly used when we need to maintain state.

@Bean
@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)

Request

In this case a new bean is created for each HTTP request that is made. It’s mostly used in authentication and authorization context.

@Bean
@Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)

Session

In this case only one bean will be created for each HTTP session

@Bean
@Scope(value = WebApplicationContext.SCOPE_SESSION, proxyMode = ScopedProxyMode.TARGET_CLASS)

Application

In this case a bean will be created for all the lifecycle of the ServletContext.

@Bean
@Scope(
  value = WebApplicationContext.SCOPE_APPLICATION, proxyMode = ScopedProxyMode.TARGET_CLASS)

Websocket

In this case the bean will be alive while the websocket session remains.

@Bean
@Scope(scopeName = "websocket", proxyMode = ScopedProxyMode.TARGET_CLASS)

References:

https://www.baeldung.com/spring-bean-scopes

https://docs.spring.io/spring-framework/docs/3.0.0.M3/reference/html/ch04s04.html

Spring IoC & Dependency Injection

It’s possible that in technical meetings you listened these terms, at the beginning they sound a little confusing and complex but the true is that they are just principles in Software Engineering.

Inversion of Control (IoC) is a concept to delegate the full responsibility to manage objects to some container or framework. Using this concept allows you more flexibility in your code as switching between implementations, decoupling your code and letting your code easy to be tested by the simple reason that the components will be isolated.

And one way to achieve it is using Dependency Injection (DI)

Dependency Injection is a pattern where the main idea is to have a separate object responsible to populates a dependency for another object.

Looking at an example below related to Books and Sections, if we don’t use DI and we need to create a book object, in this case we need to define a specific implementation for “sections” inside the constructor, and we create an unnecessary coupling:

public class Book {
    private List<Section> sections;
 
    public Book() {
        sections = new ArrayList<>();    
    }
}

On the other hand, if we use DI we can delegate the responsibility to create “sections” to other object, container or framework, and this lets your code more flexible.

public class Book {
    private List<Section> sections;
    public Book(List<Section> sections) {
        this.sections = sections;
    }
}

And using the Spring Framework and just using an “annotation” allows us to delegate the responsibility to another object that could has many implementations and letting easy to interchange between them:

public class Book {
    @Autowired
    private List<Section> sections;
}

I hope it allows you to understand better!

References:

https://www.baeldung.com/inversion-control-and-dependency-injection-in-spring

https://www.martinfowler.com/articles/injection.html