I'm considering migrating an application from PicoContainer and wanted to ask for some advice from the Spring community. Has anyone gone through this process before and have any advice from their experience?
I have many questions, but I'll start first with the bean container/DI questions. In particular, I'm not sure whether I should use Spring 2.5 annotations or JavaConfig to register my beans.
- JDK 5 (soon 6) on Tomcat 5.5.
- Webapp running WebWork 2.1, planning to upgrade to Struts 2.
- Data access using Hibernate 3 with Annotations.
- Quartz to schedule and run jobs
I'm using PicoContainer 1.x with NanoContainer 1.x, which provides a hierarchy of connected app, request, and session scope containers. I'm using these scopes but only a handful of objects actually are tied to the object (e.g. some objects use the HttpSession).
I'm using a NanoContainer XWorkObjectFactory which instantiates my WebWork Actions with all the right dependencies. I don't have to explicitly register my actions; the ObjectFactory finds them. The only other times I explicitly use Pico are for instantiating/injecting Quartz jobs and in the integration tests.
All bean registration is done programmatically via a bootstrap loader, either registering a bean identified either by a String name or by its class. The application has around 450 beans registered.
1. I'd like to keep using Constructor Injection, which sounds like is possible. I'll also want to auto-wire by default, since that's what most of my Pico beans use. In addition, there are some lifecycle methods that Pico provides like Start() and Stop() which we use for resource management (e.g. disposing of Hibernate Sessions, etc.) It looks like Spring has this also via the init-method and destroy-method callbacks.
2. It seems like a simple first step would be to convert the object where I register my beans with Pico to instead use a Spring container. Does this mean using JavaConfig, or is there some other way to do this? In particular, this class has many lines of code like this:
// args are scope, key, and implementing class
registerImplementation(requestContainer, BookRepository.class, HibernateBookRepository.class);
registerImplementation(sessionContainer, User.class, SessionBasedUser.class);
In addition you can register beans with specific parameters, which includes calling other Java objects to find those parameters:
// args = scope, key, implementation, and specify the constructor dependencies -- either find the default one, or some specific constant.
registerNamedImplementation(requestContainer, OvernightJob.class.getSimpleName(), OvernightJob.class,
new BasicComponentParameter(), new ConstantParameter(ReportingExportJobs.values()));
Of all the ~450 beans, the majority are simple registration (just key and value), and about 100 specify specific parameters.
3. I use that same configuration with three scopes for my integration tests and Quartz jobs, but instead 'flatten' the scopes myself -- I cache the 'app' container (which holds the HibernateSessionFactory, etc.) and make a child container which holds the request and session components. From my understanding of Spring's app/request/session scopes, they must have a real web counterpart around to work (and wouldn't work in Quartz or tests).
4. One difficulty I can see is that my integration tests sometimes grab a PicoContainer with the default registered dependencies, replace a registered bean with a fake one, and then get the component under test. My understanding is that Spring does not let you replace or remove components from a BeanFactory. I'm not really sure what to do here; I understand that the Spring test classes let you specify a bean configuration to use and you typically chain together XML configuration files to generate permutations of bean configurations. Is there any other way?
Thanks for your advice!