If you’ve been working with Spring MVC, you already know this. Whenever you create a new Controller you end up injecting the services or DAOs (if you’re not using the service layer) that you’re going to use. It gets to be a little cumbersome and repetitive. It could be improved. How? By defining a Spring aware factory.
First, the problem. There are several problems or inconveniences. First, you’re injecting the same service or DAO everywhere. If you’re checking if it actually was injected, then you’re duplicating that code. A violation of best practices. If you’re not used to inversion of control, it tends to be confusing. You’re asking yourself, where did this object come from? Any time you write a new controller, you also have to write some more XML and you don’t get syntax checking (that’s my number one complain about Spring). You’re braking the DRY principle: Don’t Repeat Yourself.
Is there a solution to this? Yes, there is. A nice one, actually. I got the idea from Hibernate Quickly, which I’m currently reading. You create a Factory (best practice, anyway) and you use that to retrieve your services or DAOs. No injection, no Spring. But how do you read the beans from the Spring XML files? The factory will implement ContextAware interface. (You have to also configure the Factory as a bean in the XML file for this to work.) Once you do that, you have access to all of the beans you defined. Nice and easy.
Here’s an example bean that you’ll end up with:
public class AppServiceFactory implements ApplicationContextAware {static Log log = LogFactory.getLog(AppServiceFactory.class);/*** Set by Spring when initialized.*/private static ApplicationContext appContext;public void setApplicationContext(ApplicationContext applicationContext) {log.debug("Setting application context [" + applicationContext + "]");appContext = applicationContext;}static ApplicationContext getAppContext() {if (appContext == null)throw new IllegalStateException("Application context should have been set");return appContext;}
private AppServiceFactory() { /* singleton */ }
public static AccountService getAccountService() {String serviceName = "accountService";AccountService service =(AccountService) getAppContext().getBean(serviceName);validateService(service, serviceName);return service;}
static void validateService(Object service, String name) {if (service == null)throw new IllegalStateException(name + " has to be configured.");}
// ...}
What are the benefits fo doing it this way? It’s a whole lot easier to understand. You’re asking the factory to give you the DAO or a service. It’s easier to debug. It follows the DRY principle — you’re not re-injecting the same bean all over the place. It’s easier, and faster: You define the controller in the XML config, you create it, and just use the factory in the controler. Don’t need to inject anything, no extra configuration for other controllers. You’re following the DRY principle. The service is retrieved and set in only one place. If there’s any validation you need to do, you’ll do it in one place. It works nicely for me.