Right way to use @ComponentScan in multi module Java-Config Spring MVC app

偶尔善良 提交于 2019-12-03 01:38:19

I think I found now a pretty nice project layout:

rootpackage.web.WebAppInitializer (see below)
rootpackage.web.SecurityWebAppInitializer (creates "springSecurityFilterChain")
rootpackage.web.WebMvcConfig (scans for everything in its own package and subpackages)
rootpackage.web.SecurityConfig (Spring Security config)

rootpackage.web.moduleA.SomeAController
rootpackage.web.moduleB.SomeBController

rootpackage.service.ServiceConfig (scans for everything in its own package and subpackages)
rootpackage.service.moduleA.AService
rootpackage.service.moduleA.AServiceImpl
rootpackage.service.moduleB.BService
rootpackage.service.moduleB.BServiceImpl
rootpackage.service.security.UserDetailsServiceImpl (for Spring Security)

rootpackage.model.DatabaseConfig (scans for everything in its own package and subpackages)
rootpackage.model.moduleA.SomeADomainObject
rootpackage.model.moduleB.SomeBDomainObject

WebAppInitializer:

@Order(2)
public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class[] {
            SecurityConfig.class,
            ServiceConfig.class,
            DatabaseConfig.class
        };
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class[] { WebMvcConfig.class };
    }

    @Override
    protected String[] getServletMappings() {
        return new String[] { "/" };
    }

}

SecurityWebAppInitializer:

@Order(1) // should always be registered in first place (= before WebAppInitializer)
public class SecurityWebAppInitializer extends AbstractSecurityWebApplicationInitializer {
    /* ... */
}

WebMvcConfig:

@Configuration
@EnableWebMvc
@ComponentScan // scans for everything in its own package and subpackages
               // so it only finds SomeAController.class and SomeBController.class
public class WebMvcConfig extends WebMvcConfigurerAdapter {
    /* ... */
}

SecurityConfig:

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    /* ... */
}

ServiceConfig:

@Configuration
@ComponentScan // scans for everything in its own package and subpackages
               // so it only finds AServiceImpl.class and BServiceImpl.class
public class ServiceConfig {
    /* ... */   
}

I put some "System.out.println" inside the constructor of all those classes in order to see how often they get registered/loaded. Each constructor is getting executed exactly once!

What do you think about this? Any improvements?

With an XML based config you would typically have 2 contexts one parent context that will load all your business services, database config, repositories, domain objects, etc. and a web context for loading controllers, etc.

Both should use packages to ensure they don't try to load the same beans twice. You specify both to the ContextLoaderListener to get the ApplicationContext created.

The web application context is aware of the parent (not the other way round) and will search the parent for any beans not found in it's own context. This means your controllers can access your services.

I've not done this in Java config, but I'm presuming the approach is the same

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!