spring - 在多模块 Java-Config Spring MVC 应用程序中使用 @ComponentScan 的正确方法

标签 spring maven spring-mvc multi-module spring-java-config

我刚刚开始了一个新的 Spring 项目,这次我想做“正确”的事情。在上一个项目中,由于多个 @ComponentScan 注释,我在多次注册某些类时遇到了问题。 (即所有服务类都注册了两次)

基本上我使用以下布局:

WebAppInitializer:

public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

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

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

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

}

根配置:

@Configuration
@ComponentScan
public class RootConfig {
    /* ... */
}

WebMvcConfig:

@EnableWebMvc
@ComponentScan
public class WebMvcConfig extends WebMvcConfigurerAdapter {
    /* ... */
}

数据库配置:

@Configuration
@EnableJpaRepositories("my.base.class.path")
public class DataConfig {
    /* ... */
}

第一个基本问题是: 哪个类应该扫描哪些类/注释?

是否应该仅使用 WebMvcConfig 扫描 @Controller 类?哪一个应该扫描 @Service@Configuration 以及 @Component

第二个问题是: 或者我应该简单地使用包来缩小扫描路径?

示例:

rootpackage
rootpackage.config.RootConfig
rootpackage.config.DatabaseConfig
rootpackage.mvc.WebMvcConfig

然后将所有@Controller类放在rootpackage.mvc.*下?

第三个问题是: RootConfig扫描DatabaseConfig是否更常见?或者我应该将 DatabaseConfig 放在 WebAppInitializer 类的 getRootConfigClasses 方法中?

最后一个问题是: 在多模块项目中:如何组织这些东西?

示例:如果我选择问题二中描述的方式,我可以说,应用程序的每个模块实际上都由几个不同的模块组成。比方说,我想创建一个模块 X ,它将有一个 @Service 类和一些 @Controller 类,我可以将它们放入它们在不同的包中。像这样:

Maven 模块 X 服务

rootpackage.services.x.XService
rootpackage.services.x.XServiceImpl

Maven 模块 X Controller

rootpackage.mvc.controller.x.X1Controller
rootpackage.mvc.controller.x.X2Controller
rootpackage.mvc.controller.x.X3Controller

如果您建议这样做,那么:在哪里放置模型和存储库(用于访问数据库)?我应该为每个模块创建一个新模块吗?

提前致谢!

最佳答案

我想我现在找到了一个非常好的项目布局:

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 {
    /* ... */
}

安全配置:

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

服务配置:

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

我在所有这些类的构造函数中放置了一些“System.out.println”,以便查看它们注册/加载的频率。每个构造函数只执行一次!

你对此有何看法?有什么改进吗?

关于spring - 在多模块 Java-Config Spring MVC 应用程序中使用 @ComponentScan 的正确方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21106094/

相关文章:

java - 无法在 spring 中 Autowiring sessionfactory bean

java - 如何使用java lambda表达式实现RowMapper

eclipse - jpa存储库保存方法返回的ID与插入数据库的ID不同

java - 在Spring Boot中定位/resource/目录下的静态文件

java - 由 : java. lang.ClassNotFoundException : com. sun.xml.bind.v2.model.annotation.AnnotationReader 引起

java - Spring MVC 和 Hibernate 的每个请求一个 session 模式

java - spring mvc请求映射动态url

Spring Boot 测试 : exception in REST controller

java - Spring AOP抛出后继续迭代

maven - 使用资源中的依赖项覆盖属性文件