在多模块Java-Config Spring MVC应用程序中使用@ComponentScan的正确方法 [英] Right way to use @ComponentScan in multi module Java-Config Spring MVC app

查看:62
本文介绍了在多模块Java-Config Spring MVC应用程序中使用@ComponentScan的正确方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我刚刚开始了一个新的春季项目,这次我想做的事情正确".在上一个项目中,由于有多个@ComponentScan批注,我对某些类的多次注册遇到了问题. (即所有服务类别都注册了两次)

I've just started a new spring project, and this time I want to do things "right". In the last project I had issues with multiple registering of certain classes because of multiple @ComponentScan annotations. (i.e. all service classes got registered twice)

基本上我正在使用以下布局:

Basically I'm using the following layout:

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

}

RootConfig:

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

WebMvcConfig:

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

DatabaseConfig:

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

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

是否只有WebMvcConfig扫描@Controller类?

第二个问题是: 还是我应该只使用软件包来缩小扫描路径?

示例:

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

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

and then place all @Controller classes under rootpackage.mvc.*?

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

The third question is: Is it more common to let RootConfig scan for DatabaseConfig? Or should I place DatabaseConfig inside the getRootConfigClasses method of WebAppInitializer class?

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

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

Example: If I chose the way I described in question two, I could say, that every module of the app will in fact consist of a few different modules. Let's say, I want to create a module X which will have a @Service class and a few @Controller classes, I could put them in them in different packages. Like this:

Maven Module X Service

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

Maven Module X Controller

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

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

And if you'd suggest this way, then: Where to place models and repositories (for accessing the database)? Should I create a new module for each of those?

提前谢谢!

推荐答案

我认为我现在发现了一个非常不错的项目布局:

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

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

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?

这篇关于在多模块Java-Config Spring MVC应用程序中使用@ComponentScan的正确方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆