我在Servlet 3.0+环境中运行Spring应用程序,以编程方式使用所有Java配置配置servlet上下文。我的问题(详情如下):如何构建一个项目来支持根和Web应用程序上下文的组件扫描而不重复组件初始化?
据我了解,有两种情况可以注册Spring bean。首先,根上下文是非servlet相关组件所在的位置。例如批处理作业,DAO等。其次,servlet上下文是与servlet相关的组件,例如控制器,过滤器等。
我已经实现了一个WebApplicationInitializer来注册这两个上下文,就像WebApplicationInitializer中的JavaDoc使用AppConfig.class和DispatcherConfig.class指定一样。
我希望两者都能自动找到各自的组件,因此我已将@ComponentScan添加到两者中(这导致我的Hibernate实体被启动两次)。 Spring通过扫描一些指定的基础包来找到这些组件。这是否意味着我需要将所有与DAO相关的对象放在与控制器不同的包中?如果是这样,那将非常不方便,因为我通常喜欢按功能打包(而不是打字)。
代码段......
WebApplicationInitializer:
public class AppInitializer implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext container) throws ServletException {
// Create the 'root' Spring application context
AnnotationConfigWebApplicationContext rootContext =
new AnnotationConfigWebApplicationContext();
rootContext.register(AppConfig.class);
// Manage the lifecycle of the root application context
container.addListener(new ContextLoaderListener(rootContext));
// Create the dispatcher servlet's Spring application context
AnnotationConfigWebApplicationContext dispatcherContext =
new AnnotationConfigWebApplicationContext();
dispatcherContext.register(WebAppConfig.class);
// Register and map the dispatcher servlet
ServletRegistration.Dynamic dispatcher =
container.addServlet("dispatcher", new DispatcherServlet(dispatcherContext));
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("/");
}
}
的AppConfig:
@Configuration
@ComponentScan
public class AppConfig {
}
WebAppConfig:
@Configuration
@EnableWebMvc
@EnableSpringDataWebSupport
@ComponentScan(basePackageClasses = AppConfig.class)
public class WebAppConfig extends WebMvcConfigurerAdapter {
}
答案 0 :(得分:8)
只需在每个配置中定义要扫描的内容即可。通常,您的根配置应扫描除@Controller
以外的所有内容,并且您的Web配置应仅检测@Controller
s。
您可以使用includeFilters
注释的excludeFilters
和@ComponentScan
属性来完成此操作。使用包含过滤器时,在这种情况下,您还需要通过将useDefaultFilters
设置为false
来禁用默认过滤器。
@Configuration
@ComponentScan(excludeFilters={@Filter(org.springframework.stereotype.Controller.class)})
public class AppConfig {}
适用于您的WebConfig
@Configuration
@EnableWebMvc
@EnableSpringDataWebSupport
@ComponentScan(basePackageClasses = AppConfig.class, useDefaultFilters=false, includeFilters={@Filter(org.springframework.stereotype.Controller.class)})
public class WebAppConfig extends WebMvcConfigurerAdapter {}
此外,您需要导入@Filter
注释:
import static org.springframework.context.annotation.ComponentScan.Filter;
答案 1 :(得分:1)
简短的回答是: 是的,您应该为每个上下文定义单独的组件扫描,从而以不同方式对项目进行建模,并将DAO提取到单独的名称空间(包)中。
较长的答案分为两部分,一部分关于servlet上下文,另一部分关于项目建模。
关于root和servlet上下文:您已正确定义了根上下文和servlet上下文的不同职责。这是大多数开发人员倾向于错过的理解,这非常重要。
只是为了澄清这个主题,您可以创建一个根上下文和几个(0+)servlet上下文。根上下文中定义的所有bean都可用于所有servlet上下文,但每个servlet上下文中定义的bean不会与其他servlet上下文(不同的spring容器)共享。
现在,由于您有多个弹簧容器并且在相同的包上使用组件扫描,因此每个容器创建两次bean。 为了避免这种情况,你可以做一些事情:
最后,关于项目建模的几句话。我个人喜欢分层编写项目,因此将我的代码分成控制器(应用层),业务逻辑(bl层)和DAO(数据库层)。 这样的建模有很多方面,包括您遇到的root / servlet上下文问题。 有大量关于分层架构的信息,这里有一个快速的peed:wiki-Multilayered_architecture