Aspect Oriented Programming: Spring

One of the most powerfull tools spring provides us with is aspect orientation.
Aspect oriented programming helps us to continue development for special use cases, without breaking our modularity.

This is part of a series of blog posts on aspect orientation using different tools.
The first one is about aspect orientation on Spring.

In this example I will display the behaviour of two beans from the same definition but each one has a different aspect.

The employe class will be used to create the beans for this project.

package com.gkatzioura.spring.employees;

public class Employee {

    public void enterWorkArea() {

    }

    public void leaveWorkArea() {

    }

}

However considering a company, probably there are more than one types of employes.
For our project we will use the aspect of the supervisor employee and the aspect of the worker employee.

The worker employee before entering the work area should inform the supervisor employee that he has arrived.
The supervisor employee before entering the area should check that everything is ok.

package com.gkatzioura.spring.employees;

import org.apache.log4j.Logger;
import org.springframework.aop.MethodBeforeAdvice;

import java.lang.reflect.Method;

public class WorkerBeforeAdvice implements MethodBeforeAdvice {

    private static final Logger LOGGER = Logger.getLogger(WorkerBeforeAdvice.class);

    @Override
    public void before(Method method, Object[] objects, Object o) throws Throwable {

        if (method.getName().equals("enterWorkArea")) {
            System.out.println("Informing the supervisor that I have arrived");
        }

    }

}
package com.gkatzioura.spring.employees;

import org.apache.log4j.Logger;
import org.springframework.aop.MethodBeforeAdvice;

import java.lang.reflect.Method;

public class SupervisorBeforeAdvice implements MethodBeforeAdvice {

    private static final Logger LOGGER = Logger.getLogger(SupervisorBeforeAdvice.class);

    @Override
    public void before(Method method, Object[] objects, Object o) throws Throwable {
        
        if(method.getName().equals("enterWorkArea")) {
            System.out.println("Check if everything is ok");
        }
    }
}

The advices defined above would have to be wired on our employee bean according to the aspect needs.
For the worker bean we will use the WorkerBeforeAdvice before entering the factory.
For the employee bean we wil use the SupervisorBeforeAdvice before leaving the factory

On your META-INF create a spring directory and inside the spring directory create the employeeapects.xml file. This file would wire the employee bean with the behaviours described above.
The first ProxyFactory Bean will be used to create employee beans wired with the WorkerBeforeAdvice behaviour.
The second ProxyFactory Bean will be used to create employee beans wired with the SupervisorBeforeAdvice behaviour.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="employee" class="com.gkatzioura.spring.employees.Employee"/>

    <bean id="workerBeforeBean" class="com.gkatzioura.spring.employees.WorkerBeforeAdvice"/>
    <bean id="supervisorBeforeBean" class="com.gkatzioura.spring.employees.SupervisorBeforeAdvice"/>

    <bean id="workerProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
        <property name="target" ref="employee"/>
        <property name="interceptorNames">
            <list>
                <value>workerBeforeBean</value>
            </list>
        </property>
    </bean>

    <bean id="superVisorProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
        <property name="target" ref="employee"/>
        <property name="interceptorNames">
            <list>
                <value>supervisorBeforeBean</value>
            </list>
        </property>
    </bean>

</beans>

On your dispatcher-servlet.xml you need to import employeeapects.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:mvc="http://www.springframework.org/schema/mvc"
       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-3.0.xsd
       http://www.springframework.org/schema/mvc
       http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">

    <context:component-scan base-package="com.gkatzioura.spring"/>

    <import resource="classpath:/META-INF/spring/employeeapects.xml"/>
    <mvc:annotation-driven/>
</beans>

We will create a controller in order to create the beans.

package com.gkatzioura.spring.controllers;

import com.gkatzioura.spring.employees.Employee;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class AspectController {

    @Autowired
    @Qualifier("workerProxy")
    Employee workEmployee;

    @Autowired
    @Qualifier("superVisorProxy")
    Employee superVisorEmployee;

    @RequestMapping(value = "/")
    @ResponseBody
    public String index() {

        return "Check other endpoints";
    }

    @RequestMapping(value = "/worker/enter")
    @ResponseBody
    public String workerEnter() {
        workEmployee.enterWorkArea();
        return "Worker entered the factory";
    }

    @RequestMapping(value = "/supervisor/enter")
    @ResponseBody
    public String superVisortEnter() {
        superVisorEmployee.enterWorkArea();
        return "Supervisor entered the factory";
    }

}

You should hit the endpoint /worker/enter and /supervisor/enter.
You will notice that the workerEmployee and superVisorEmployee have a different reaction once calling the enterWorkArea function.

By hitting the /worker/enter endpoint, the string “Informing the supervisor that I have arrived” is printed on the console.
By hitting the /supervisor/enter endpoint, the string “Check if everything is ok” is printed on the console.