Showing posts with label Spring. Show all posts
Showing posts with label Spring. Show all posts

Monday, June 30, 2008

Using custom spring annotations in the Web and App tier

I had blogged earlier about why I thought Spring 2.5 annotations were really cool and well implemented. I had mentioned in that article how one could use one's own custom annotations through Spring 2.5 to inject dependencies into web application classes as well as the EJBs in the application tier. I went ahead and tried this out for the web and app tier to see how challenging this really was. It required the web classes that had my custom annotations to be instantiated through Spring. The Struts2 framework that's really getting a lot of momentum these days (check out Matt Raible's stats on this here) integrates well with Spring and though the documentation is not thorough, the link here gives a fairly good idea of how one goes about Spring enabling struts2. The gist here is that the object factory for all struts actions is the StrutsSpringObjectFactory. The configuration of my web.xml really needed only this listener:

  <listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>

I also had an applicationContext.xml (under WEB-INF) that scanned for my own custom annotations. So that allowed my Action classes to use my custom annotations. With Struts2's native annotations, you don't need to worry about the struts-config.xml for result-jsp mappings either. Its all there in your action class. I even had advice around the action to capture timing stats thus implementing "seperation of concerns" to the hilt!! Well that took care of the web tier.

My app tier was EJB 3.0 based and I found that Spring had an interceptor that helped my cause. So my session facade had to be annotated with my custom Spring interceptor as shown here:

@Stateless(name = "HelloWorldService")
@Interceptors(MySpringBeanAutowiringInterceptor.class)
public class HelloWorldService implements HelloWorld, Serializable

The custom Spring interceptor essentially helps me to use a custom annotation (my own type for autowiring) in the EJB. The code for the interceptor looks like:

public class MySpringBeanAutowiringInterceptor extends SpringBeanAutowiringInterceptor
{
@Override
protected void configureBeanPostProcessor(AutowiredAnnotationBeanPostProcessor processor, Object target) {
processor.setAutowiredAnnotationType(CustomAutowiring.class);
}
}

Now here came the tricky part - I had to create the beanRefContext.xml for Spring and had to have it load up another context file that had information to setup Spring to search for my custom annotations as so -

<bean class="org.springframework.context.support.ClassPathXmlApplicationContext">
<constructor-arg type="java.lang.String" value="ejbApplicationContext.xml"/>
</bean>

In the ejbApplicationContext.xml, I setup the component-scan tag to search for my annotations. This worked though I was initially at a loss as to why I need to specify two context files to get dependencies to be injected by Spring. I found the reason for this on the Spring forums (by Juergen Hoeller) -

Essentially, your "beanRefContext.xml" file will typically define a ClassPathXmlApplicationContext which in turns loads your actual beans. The "beanRefContext.xml" mechanism allows multiple such shared ApplicationContexts to co-exist, differentiated by bean factory locators. In the default EJB3 case, simply define one such ApplicationContext which will be picked up automatically, regardless of name.

You can also read more on this in the Spring docs here. The other thing also was that I had to make sure I had the correct set of libraries in my EAR. Those libraries were:

- spring.jar
- asm-2.2.3.jar
- asm-commons-2.2.3.jar
- aspectjrt.jar
- aspectjweaver.jar
- common-annotations.jar
- commons-logging.jar
- log4j-1.2.14.jar

Overall, I found that the web side Struts2 integration with Spring seemed much more cleaner that the EJB one. At this point I would still recommend this approach, but make sure you have a little bit of time on your hands to get this working exactly the way you want it. If you are interested, I can further share any other information - just call out.

I will continue to tweak and research on the EJB implementation - but overall, this approach still makes for an interesting application design.

Thursday, April 24, 2008

Liking Spring 2.5 (love annotations)

Ok, I think I feel comfortable in adopting or suggesting the Spring framework for JEE projects. And I am sure some people would say that they had reached that conclusion a long time ago. However, earlier I would tend to disagree on a couple of counts if someone suggested that Spring was the best thing to happen to Java and a better alternative to the existing JEE spec. The things I despised about Spring earlier were:
  • Too many libraries to include
  • Too much in an Xml configuration leading to some tricky runtime debugging errors
However, the Spring folks seem to have taken notice and have addressed these problems with Spring 2.5. So at my first opportunity, I decided to code with Spring 2.5 leveraging it mainly for its annotation facility. A really good resource I found for seeing the customization of Spring's annotation features is on InfoQ. However, I also extended a couple of the classes in Spring to be able to mimic resource manager injection capability (aka autowiring), similar to JPA persistent manager injection in JEE 5. The code looks something like this:

@MyAnnotation
public class WiredBean
{
@MyInjectionAnnotation(resourceManager=AResourceType)
private Resource resource;

public boolean isInjected()
{
if ( resource!=null )
return true;
else
return false;
}
}

Spring allows renaming of annotations so that there is no dependency in your code on Spring classes. However to be able to inject (or autowire objects) based on your own annotation, requires some coding and essentially the following 2 things -
  1. Create your own class that extends InstantiationAwareBeanPostProcessorAdapter ( look at PersistenceAnnotationBeanPostProcessor for an example or email me for my example)
  2. Your Sping xml configuration needs really only 2 entries:
    1. An entry to register your own AnnotationBeanPostProcessor
    2. An entry to scan for your own autowiring annotation that allows one to override default behavior.
And you'll get code that looks like the above. Injecting your own manager objects into a JEE 5 application could be done using a Filter on the web side and Interceptors on the service/ejb side. If you are in an organization that wishes to avoid direct dependency on Spring all over the place in their JEE apps, custom annotations as I've mentioned allows for that separation.