I'm running a Spring application in a Servlet 3.0+ environment to programmatically configure the servlet context using all Java configuration. My question (with details below): how is a project structured to support component scanning for both root and web application contexts without duplicating component initialization?
As I understand it, there are two contexts in which to register Spring beans. First, the root context is where non-servlet-related components go. For example batch jobs, DAOs, etc. Second, the servlet context is where servlet-related components go such as controllers, filters, etc.
I've implemented a WebApplicationInitializer to register these two contexts just as the JavaDoc in WebApplicationInitializer specifies with a AppConfig.class and DispatcherConfig.class.
I want both to automatically find their respective components so I've added @ComponentScan to both (which is resulting in my Hibernate entities being initiated twice). Spring finds these components by scanning some specified base package. Does that mean I need to put all my DAO-related objects in a separate package from the controllers? If so, that'd be quite inconvenient as I generally like to package by functionality (as opposed to type).
Code snippets...
WebApplicationInitializer:
public class AppInitializer implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext container) throws ServletException {
// Create the 'root' Spring application context
AnnotationConfigWebApplicationContext rootContext =
new AnnotationConfigWebApplicationContext();
rootContext.register(AppConfig.class);
// Manage the lifecycle of the root application context
container.addListener(new ContextLoaderListener(rootContext));
// Create the dispatcher servlet's Spring application context
AnnotationConfigWebApplicationContext dispatcherContext =
new AnnotationConfigWebApplicationContext();
dispatcherContext.register(WebAppConfig.class);
// Register and map the dispatcher servlet
ServletRegistration.Dynamic dispatcher =
container.addServlet("dispatcher", new DispatcherServlet(dispatcherContext));
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("/");
}
}
AppConfig:
@Configuration
@ComponentScan
public class AppConfig {
}
WebAppConfig:
@Configuration
@EnableWebMvc
@EnableSpringDataWebSupport
@ComponentScan(basePackageClasses = AppConfig.class)
public class WebAppConfig extends WebMvcConfigurerAdapter {
}