After spending some time using aspects to do various cross cutting application tasks like live profiling and logging mechanisms in one of my Spring MVC web applications, I found myself wanting to use Spring’s IoC mechanism without it’s AOP implementation. Spring provides a dynamic runtime pure Java implementation of Aspects that they promote as a complement to AspectJ. It works great with all of the injected components you use as spring already uses a proxy layer to manipulate them. If you want to be able to place join points on code that isn’t managed by spring you will find yourself looking for an AspectJ weaver/compiler.
If you use Maven2 much like I do, you’ll find it quite simple to setup an AspectJ compiler/weaver. I’m using the aspectj-maven-plugin configured to attach to the compile and test-compile life cycle goals. Here is the configuration I used:
org.codehaus.mojo aspectj-maven-plugin 1.3 compile test-compile src/main/aspect true true 1.6
Getting the Application Context…
Enough with this fluffy preamble, what I wanted to do was get the application context so I could access my Hibernate managed data access object and services tier. Initially, I wanted to autowire my service and declare the class as a component that would be injected with Spring’s IoC mechanism. Unfortunately, I could not discover a method of doing so without using Spring’s proxy based runtime AOP solution. One obvious solution would be to use the XML class path context loader and specify the context file via filename and location, but this was a very brittle method that would just introduce multiple points of context file configuration (not a very good solution.).
I realized my join points where on controller actions; therefore, I always had access to the incoming HttpServletRequest object supplied by our Apache Tomcat container. With the request object I was able to get the servlet context which gave me access to both the servlet configuration parameters and a method of retrieving the Spring application context that the servlet was configured with. We used the web.xml to define spring as the dispatch servlet (following the common MVC pattern) and had our context definition split into several XML documents. By using Spring’s WebApplicationContextUtils.getRequiredWebApplicationContext() helper one can get the entire application context that the servlet is configured with.
Here is an example of retrieving a dynamic setting from a database inside of an advice annotated method that wraps around a controller action:
public String getWebSetting(String settingName, Object[] joinPointArgs) {
for(Object arg: joinPointArgs) {
if(arg instanceof HttpServletRequest) {
return ((WebSettingService)WebApplicationContextUtils.
getRequiredWebApplicationContext(
((HttpServletRequest) arg).getSession(false).getServletContext()
).getBean("webSettingService"))
.getNameValuePairedWebSettings().get(settingName);
}
}
return null;
}
@Around("xxx.yyy.profiling.ControllerRequestActionProfilerAspect.inControllers()")
public Object profileControllers(ProceedingJoinPoint pjp) throws Throwable {
String setting = getWebSetting("enable_performance_logging", pjp.getArgs());
[...]
}
@Pointcut("execution(@org.springframework.web.bind.annotation.RequestMapping * (@org.springframework.stereotype.Controller *).*(..))")
private void inControllers() {}
Recent Comments