AspectWerkz with Spring dependency injected aspects
Aspect Oriented Programming and Dependency Injection are two very powerful frameworks that would help in eliminating cross-cutting concerns and providing a way of injecting dependencies at run-time. Two most powerful frameworks for Java, through which we can achieve these, are Aspectwerkz and Spring.
Read my previous article – “AspectWerkz – Declaring war on spaghetti code” for an overview of Aspectwerkz.
Now what to do if we want to use the power of Aspects and DI? Spring framework comes with the AOP support. But you may want to use Aspectwerkz instead of Spring AOP for various reasons like prior experience with Aspectwerkz, trying to use Spring with a project that is already using Aspectwerkz, etc…
No matter whatever the reason, this article tries to solve your problem of integrating Aspectwerkz with Spring. Let us first start with some basics of Aspectwerkz’s architecture.
Aspectwerkz’s Container Architecture
Aspectwerkz has a container style architecture. All the aspects are initialized, managed and destroyed by the Aspectwerkz’s container. The following diagram depicts how a normal Aspectwerkz’s container looks like:
Aspectwerkz’s Extensible Aspect Container
An interesting feature of the Aspectwerkz container architecture is the “extensible aspect container”. This feature helps us integrate other frameworks like Spring, AspectJ, etc with Aspectwerkz. The following diagram depicts the extensible aspect container.
Let’s Code!!!
After seeing the Aspectwerkz framework, it is time to write some code. First we need a problem statement.
Problem Statement
We need authentication as an aspect that would be weaved when a method is tagged with an annotation @Authenticated. The method arguments will contain the username and password required for authentication. Now which database to connect to the user credentials will be injected using Spring.
The Solution
The Aspect definition file: aop.xml
Let’s start with the Aspect Definition File, aop.xml.
<aspectwerkz> <system id="Example"> <package name="foo.aspects"> <aspect class="MethodCallAuthenticator" container="foo.aspects.MyContainer" name="bean_MethodCallAuthenticator"> <pointcut name="authenticatedMethods" expression="execution(@foo.aspects.Authenticated * foo.methods.*.*(..))"/> <advice name="authenticate" type="before" bind-to="authenticatedMethods"/> </aspect> </package> </system> </aspectwerkz>
You can see that the aspect definition “MethodCallAuthenticator” has been configured with the custom built container “foo.aspects.MyContainer”. We will not be going into the details of the Aspects and how they are weaved in this article. You may download the complete source code.
Aspectwerkz container extension: foo.aspects.MyContainer
Let us look at the implementation of the container class ‘foo.aspects.MyContainer’. The class should extend “org.codehaus.aspectwerkz.aspect.AbstractAspectContainer”.
package foo.aspects; import org.codehaus.aspectwerkz.AspectContext; import org.codehaus.aspectwerkz.aspect.AbstractAspectContainer; import org.springframework.beans.factory.xml.XmlBeanFactory; import org.springframework.core.io.ClassPathResource; public class MyContainer extends AbstractAspectContainer { private XmlBeanFactory bean_factory = null; public MyContainer(final AspectContext aspectContext) { super(aspectContext); } protected Object createAspect() { if (bean_factory == null) { bean_factory = new XmlBeanFactory(new ClassPathResource("aspect-context.xml")); } System.out.println(bean_factory.getBean(m_aspectContext.getAspectDefinition().getName())); return bean_factory.getBean(m_aspectContext.getAspectDefinition().getName()); } }
There are three important things to note here:
- The instance variable bean_factory
- Implementing the abstract method “protected Object createAspect()”
- The aspect-context.xml loaded from the classpath
The instance variable bean_factory is used to load the Spring bean configuration. The createAspect() is invoked by the aspectwerkz framework to get new aspect instance. In the above code, we are letting the Spring initialize the dependency injected aspect. The bean configuration is defined in the aspect-context.xml file that should be in the application’s classpath.
Spring bean definition file: aspect-context.xml
The aspect-context.xml should be in the application’s classpath.
<?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 name="bean_MethodCallAuthenticator" class="foo.aspects.MethodCallAuthenticator" id="bean_MethodCallAuthenticator"> <property name="userCredentials"> <bean class="foo.security.DummyUserCredentials"/> </property> </bean> </beans>
We are done with the basics of integrating Aspectwerkz and Spring. You may download the complete source code.