Search code examples
springspring-mvcdefaultstartupcomponent-scan

Spring web app start up - @ComponentScan - app context and web context


Our Spring MVC web app is trying to follow the recommended style. It uses AppContext (ContextLoaderListener) to store the DAO's and Services. It uses WebAppContext (DispatcherServlet) to store Controllers.

The DAO objects are getting into both the AppContext and the WebAppContext. I don't understand why.

The AppContext config is supposed to load everything except the Controllers (and a class that loads code tables into the ServletContext):

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true, jsr250Enabled = true)
@EnableTransactionManagement
@EnableScheduling
@ComponentScan(
  basePackages = {"blah"},
  excludeFilters = {
    @Filter(type = FilterType.ANNOTATION, value = {Controller.class}),
    @Filter(type = FilterType.ASSIGNABLE_TYPE, value = LoadOnStartup.class) 
  } 
)
public class SpringRootConfiguration {

and the web part is supposed to load the Controllers only:

@Configuration
@EnableWebMvc
@ComponentScan(
 basePackages = {"blah"},
 includeFilters = @Filter(type = FilterType.ANNOTATION, classes={Controller.class})
)
public class SpringWebConfiguration extends WebMvcConfigurerAdapter {

(The above classes are in a separate package that is a sibling to 'blah'; there's no self-scanning going on).

Of course, the Controllers reference DAO objects. In the Controller, those DAO objects are @Autowired.

My expectation was that those @Autowired DAO objects are retrieved from the AppContext, and not created a second time, and placed in the WebAppContext. But I think they are being created a second time. For example, this line appears twice in the log, once for AppContext, and once for WebAppContext:

Creating shared instance of singleton bean 'labelDao'

Am I missing something?

It's as if the parent-child relation between the root context and the web context is missing.


Solution

  • When using an include filter that doesn't automatically mean that the defaults are disabled. By default @ComponentScan will detect all @Component classes, regardless of what yu specify by the include. So if you want to explicitly to control which annotations to scan you first have to disable the defaults. To do set the useDefaultFilters attribute of @ComponentScan to false.

    @ComponentScan(
     basePackages = {"blah"},
     useDefaultFilters=false,
     includeFilters = @Filter(type = FilterType.ANNOTATION, classes={Controller.class})
    )
    

    Now it will only detect @Controller annotated beans.