Writing First Aspect in spring
We have explained what is Aspect oriented Programming in our previous article What is AOP. To start writing first aspect, lets use the Bank business case where we will have some Bank service that will retrieve some bank information(say for example address). We will have a main class that will get the instance of this business service using Spring dependency injection and call the method to get the bank information.
HDFC.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
package com.j2eereference.spring.model; public class HDFC { private String address; public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } } |
CITI.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
package com.j2eereference.spring.model; public class CITI { private String address; public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } } |
BankService.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
package com.j2eereference.spring.service; import com.j2eereference.spring.model.CITI; import com.j2eereference.spring.model.HDFC; public class BankService { private HDFC hdfc; private CITI citi; public HDFC getHdfc() { return hdfc; } public void setHdfc(HDFC hdfc) { this.hdfc = hdfc; } public CITI getCiti() { return citi; } public void setCiti(CITI citi) { this.citi = citi; } } |
Configure the beans in spring.xml. For the BankService bean lets use auto-wiring byName to inject the dependencies since the names of beans and the properties in service can be retained same.
spring.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
<?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:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd"> <bean name="hdfc" class="com.j2eereference.spring.model.HDFC"> <property name="address" value="HDFC Address"></property> </bean> <bean name="citi" class="com.j2eereference.spring.model.CITI"> <property name="address" value="CITI Address"></property> </bean> <bean name="bankService" class="com.j2eereference.spring.service.BankService" autowire="byName"> </bean> </beans> |
Now instantiate the service bean in the main method and run it.
BankApp.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
package com.j2eereference.spring; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.j2eereference.spring.service.BankService; public class BankApp { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml"); BankService bankService = context.getBean("bankService", BankService.class); System.out.println(bankService.getHdfc().getAddress()); } } |
Output:
HDFC Address
We will use this execution flow to write our Aspect. Lets use a simple Logging aspect, that is to print a log message before a particular method is called. In this example, we shall print a log message every time getAddress() of HDFC.java is called.
The first step is to create the Aspect.
LoggingAspect.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
package com.j2eereference.spring.aspects; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; @Aspect public class LoggingAspect { @Before("execution(public String getAddress())") public void loggingAdvice() { System.out.println("Advice run. Get address method is called"); } } |
We have used @Aspect annotation to let Spring know that LoggingAspect class should be treated as an aspect. loggingAdivce() is the method that we want to execute before the execution of getAddress() method. We have used @Before annotation to tell Spring that, before executing loggingAdvice() execute getAddress() method.
This is just creating the Aspect and configuring the Aspect behavior. We have to tell Spring that we have AOP in place with a special annotation in spring.xml. Also include the LoggingAspect bean definition in order to see LoggingAspect as an aspect with PostProcessor or any other bean.
spring.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
<?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:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd"> <aop:aspectj-autoproxy /> <bean name="hdfc" class="com.j2eereference.spring.model.HDFC"> <property name="address" value="HDFC Address"></property> </bean> <bean name="citi" class="com.j2eereference.spring.model.CITI"> <property name="address" value="CITI Address"></property> </bean> <bean name="bankService" class="com.j2eereference.spring.service.BankService" autowire="byName" /> <bean name="loggingAspect" class="com.j2eereference.spring.aspects.LoggingAspect" /> </beans> |
<aop:aspectj-autoproxy />
This is included to tell Spring that we are using AOP, if there are any aspects make sure the aspect methods are executed as configured.
Output:
Advice run. Get address method is called
HDFC Address
loggingAdvice() is called before calling the getAddress() on the HDFC class. Notice that getAddress() is common in both HDFC.java and CITI.java. In @Before(“executing(public String getAddress())”), we have no mention of HDFC.java. It is the bankService instance that is getting the HDFC object and calling getAddress() on it in BankApp.java.
In BankApp.java, what if we replaced
System.out.println(bankService.getHdfc().getAddress());
with
System.out.println(bankService.getCiti().getAddress());
Output would be:
Advice run. Get address method is called
Citi Address
Notice that LoggingAspect runs for CITI as well. Because we have not asked LoggingAspect to be specific for HDFC. We have configured it to execute whenever ‘public String getAddress()’ is called no matter which class the method belongs to.
Leave a Reply