Aspect Oriented Spring Hello World!

together with some notes!


Notes

Aspects
  • Advice
  • Join Points
  • Pointcuts

Advice
Defines "what" and "when".
  • Before
  • After
  • After Returning
  • After Throwing
  • Around

Join Points
Points in your application where an aspect can be plugged in.

Pointcuts
Defines "where". Pointcuts match Join Points. Pointcuts are often specified by class names, method names or regular expressions that define matching class and or method names.

An "Aspect" is a merger of Advice and Pointcuts.

In Spring Framework

  • With Springs "aop" namespace, you can turn POJOs into Aspects.
  • Spring supports only method join points.
  • In Spring, pointcuts are defined by using AspectJ's pointcut expression language.

Hello World Example

Directory Layout
.
├── pom.xml
└── src
    └── main
        ├── java
        │   └── biz
        │       └── tugay
        │           └── spashe
        │               ├── App.java
        │               ├── Bar.java
        │               ├── Foo.java
        │               └── FooImpl.java
        └── resources
            └── beans.xml

pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
                             http://maven.apache.org/maven-v4_0_0.xsd">
 
    <modelVersion>4.0.0</modelVersion>
 
    <groupId>biz.tugay</groupId>
    <artifactId>spashe</artifactId>
    <packaging>jar</packaging>
 
    <version>1.0-SNAPSHOT</version>
 
    <name>bare-maven-project</name>
    <url>http://www.tugay.biz</url>
 
    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>4.3.12.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjtools</artifactId>
            <version>1.8.12</version>
        </dependency>
    </dependencies>
 
    <build>
        <finalName>spashe</finalName>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <version>1.2.1</version>
                <configuration>
                    <mainClass>biz.tugay.spashe.App</mainClass>
                </configuration>
            </plugin>
        </plugins>
    </build>
 
    <properties>
        <maven.compiler.source>1.7</maven.compiler.source>
        <maven.compiler.target>1.7</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
</project>

beans.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                           http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/context
                           http://www.springframework.org/schema/context/spring-context.xsd
                           http://www.springframework.org/schema/aop
                           http://www.springframework.org/schema/aop/spring-aop-4.0.xsd">
 
    <aop:aspectj-autoproxy/>
    <context:annotation-config/>
    <context:component-scan base-package="biz.tugay"/>
</beans>

Bar.java
package biz.tugay.spashe;
 
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
 
/**
 * User: Koray Tugay (koray@tugay.biz)
 * Date: 26/10/2017
 */
 
@Component
@Aspect
public class Bar {
 
    @Before("execution(void biz.tugay.spashe.Foo.foo())")
    public void bar() {
        System.out.println("Bar#bar");
    }
}

Foo.java
package biz.tugay.spashe;
 
/**
 * User: Koray Tugay (koray@tugay.biz)
 * Date: 26/10/2017
 */
public interface Foo {
 
    void foo();
    void bar();
}

FooImpl.java
package biz.tugay.spashe;
 
import org.springframework.stereotype.Component;
 
/**
 * User: Koray Tugay (koray@tugay.biz)
 * Date: 26/10/2017
 */
 
@Component(value = "foo")
public class FooImpl implements Foo {
 
    @Override
    public void foo() {
        System.out.println("FooImpl#foo");
    }
 
    @Override
    public void bar() {
        System.out.println("FooImpl#bar");
    }
}

App.java
package biz.tugay.spashe;
 
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
 
public class App {
 
    public static void main(String[] args) {
        final ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
        final Foo foo = applicationContext.getBean("foo", Foo.class);
        foo.foo();
        foo.bar();
    }
}

In Action
MacBook-Pro:spashe koraytugay$ mvn clean install exec:java -q
Oct 26, 2017 9:07:37 PM org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@30aee2b8: startup date [Thu Oct 26 21:07:37 CEST 2017]; root of context hierarchy
Oct 26, 2017 9:07:37 PM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from class path resource [beans.xml]
Bar#bar
FooImpl#foo
FooImpl#bar