Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在多模块Java Config Spring MVC应用程序中使用@ComponentScan的正确方法_Spring_Maven_Spring Mvc_Multi Module_Spring Java Config - Fatal编程技术网

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

在多模块Java Config Spring MVC应用程序中使用@ComponentScan的正确方法,spring,maven,spring-mvc,multi-module,spring-java-config,Spring,Maven,Spring Mvc,Multi Module,Spring Java Config,我刚刚开始了一个新的spring项目,这次我想把事情做得“正确”。在上一个项目中,由于有多个@ComponentScan注释,我在多次注册某些类时遇到了问题。(即所有服务类别均注册两次) 基本上,我使用以下布局: WebAppInitializer: public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { @Override protected C

我刚刚开始了一个新的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[] { "/" };
    }

}
WebMvcConfig

@Configuration
@ComponentScan
public class RootConfig {
    /* ... */
}
@EnableWebMvc
@ComponentScan
public class WebMvcConfig extends WebMvcConfigurerAdapter {
    /* ... */
}
@Configuration
@EnableJpaRepositories("my.base.class.path")
public class DataConfig {
    /* ... */
}
数据库配置

@Configuration
@ComponentScan
public class RootConfig {
    /* ... */
}
@EnableWebMvc
@ComponentScan
public class WebMvcConfig extends WebMvcConfigurerAdapter {
    /* ... */
}
@Configuration
@EnableJpaRepositories("my.base.class.path")
public class DataConfig {
    /* ... */
}
第一个基本问题是:哪个类应该扫描哪些类/注释

是否只应
WebMvcConfig
扫描
@Controller
类?哪个应该扫描
@服务
@配置
以及
@组件

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

例如:

rootpackage
rootpackage.config.RootConfig
rootpackage.config.DatabaseConfig
rootpackage.mvc.WebMvcConfig
然后将所有
@Controller
类放在
rootpackage.mvc.*

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

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

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

Maven模块X服务

rootpackage.services.x.XService
rootpackage.services.x.XServiceImpl
Maven模块X控制器

rootpackage.mvc.controller.x.X1Controller
rootpackage.mvc.controller.x.X2Controller
rootpackage.mvc.controller.x.X3Controller
如果您建议这样做,那么:在哪里放置模型和存储库(用于访问数据库)?我是否应该为每个模块创建一个新模块


提前谢谢

使用基于XML的配置,您通常会有两个上下文—一个将加载所有业务服务、数据库配置、存储库、域对象等的父上下文,以及一个用于加载控制器等的web上下文

两者都应该使用包来确保它们不会尝试两次加载相同的bean。您可以向
ContextLoaderListener
指定这两个属性,以创建应用程序上下文

web应用程序上下文知道父级(而不是相反),并将在父级中搜索在其自身上下文中未找到的任何bean。这意味着您的控制器可以访问您的服务


我没有在Java配置中这样做,但我认为方法是相同的

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

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[] { "/" };
    }

}
@Order(1) // should always be registered in first place (= before WebAppInitializer)
public class SecurityWebAppInitializer extends AbstractSecurityWebApplicationInitializer {
    /* ... */
}
@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 {
    /* ... */   
}
WebMvcConfig:

@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[] { "/" };
    }

}
@Order(1) // should always be registered in first place (= before WebAppInitializer)
public class SecurityWebAppInitializer extends AbstractSecurityWebApplicationInitializer {
    /* ... */
}
@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 {
    /* ... */   
}
安全配置:

@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[] { "/" };
    }

}
@Order(1) // should always be registered in first place (= before WebAppInitializer)
public class SecurityWebAppInitializer extends AbstractSecurityWebApplicationInitializer {
    /* ... */
}
@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 {
    /* ... */   
}
ServiceConfig:

@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[] { "/" };
    }

}
@Order(1) // should always be registered in first place (= before WebAppInitializer)
public class SecurityWebAppInitializer extends AbstractSecurityWebApplicationInitializer {
    /* ... */
}
@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”,以查看它们注册/加载的频率。每个构造函数只执行一次


你觉得这个怎么样?有什么改进吗?

谢谢。是的,它应该与XML配置中的相同。它仍然是相同的框架,但只是描述配置的另一种方式。。。现在我只需要知道,在那些包上到底应该划清界限:您使用了两次等等。你能提供一个链接到一些好的解释吗,或者只是自己解释一些更详细的内容?这实际上取决于你如何组织你的代码,但是如果组件是分散的,你可以为每个组件提供一个包列表。稍后我将添加更多细节。我用自己的解决方案创建了一个新的答案。到目前为止,它似乎像预期的那样起作用。也许你想对此发表评论:)是的,这与XML几乎相同,基于Java的配置更灵活。请注意Spring安全性。您正在web模块中初始化
springSecurityFilterChain
(SSFC),现在可以了。问题是应用程序中只能有一个SSFC,即不能在其他模块(子上下文)中注册另一个SSFC。我最近在一个我想模块化的项目中遇到了它。不幸的是,我不知道如何解决这个问题。对不起,我真的不明白
:-(
有什么更好的解决方案可以提高灵活性?我应该为每个模块放置一个吗?我现在还没有对Spring Security进行过太多的工作。您当前的配置很好,也很合理。我只是说,如果您添加另一个(dispatcher)servlet上下文(即子上下文),您将遇到问题,可能使用REST API,也可以使用Spring Security进行保护。原因是您无法在第二个servlet上下文中注册另一个
springSecurityFilterChain
,只能有一个实例。我知道的唯一解决方法是在根上下文中注册SSFC,然后在任何servlet上下文中注册(以及根上下文本身)可以使用它,但这是非常有限和不灵活的。请注意这个限制。好的,现在我理解得更好了一点
:-)
。我认为当前的项目布局不会遇到这样的问题,因为它是一个仅REST的API。没有HTML,没有JSP,没有其他,只有JSON(如果有人强迫我们……,可能是XML。我很高兴……)如果您像现在一样只在一个上下文中使用Spring安全性,那么就没有什么可担心的了。