【SpringMVC】Bean 加载控制
在实际开发中,SpringMVC 负责扫描和加载 Controller 层的 Bean 对象,而业务层和数据层等其他模块的 Bean 则由 Spring 框架负责扫描和加载。那么,如何控制 Spring 仅加载除了 Controller 层之外的其他 Bean 呢?为了解决这个问题,通常可以采取以下两种方案,来避免 Spring 错误地加载 SpringMVC 的 Bean:
- 直接指定:在 Spring 的配置中精确设定扫描范围,只加载特定的包,例如 service 包和 dao 包。
- 过滤排除:将 Spring 的扫描范围设定为 com.it(假设 groupId 为 com.it),并排除 controller 包内的 Bean。
当然,在实际开发中,有时也会选择不区分 Spring 和 SpringMVC 的环境,将它们加载到同一个环境中。这里创建一个入门版的 SpringMVC 项目进行演示,创建过程可以参考 SpringMVC 快速入门。假设,现在的 SpringMVC 配置类和启动配置类如下:
@Configuration
@ComponentScan("com.it.controller")
public class SpringMvcConfig {
}
public class InitConfig extends AbstractDispatcherServletInitializer {
// 用于加载 SpringMVC 容器配置
@Override
protected WebApplicationContext createServletApplicationContext() {
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.register(SpringMvcConfig.class);
return ctx;
}
// 设置哪些请求归属 SpringMVC 处理
@Override
protected String[] getServletMappings() {
// 设置所有的请求归属 SpringMVC 处理
return new String[]{"/"};
}
// 加载 Spring 容器配置
@Override
protected WebApplicationContext createRootApplicationContext() {
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.register(SpringConfig.class);
return ctx;
}
}
方式 1:直接指定
在 Spring 配置类中,通过 @ComponentScan
直接指定多个待扫描模块:
@Configuration
@ComponentScan({"com.it.service", "com.it.dao"})
public class SpringConfig {
}
方式 2:过滤排除
在 Spring 配置类中,通过 @ComponentScan
排除不扫描模块:
@Configuration
@ComponentScan(
value = "com.it",
excludeFilters = @ComponentScan.Filter(
type = FilterType.ANNOTATION,
classes = Controller.class
)
)
public class SpringConfig {
}
这里按照注解类型排除不需要扫描的模块,说明一下:@ComponentScan
存在两个重要的属性:
- excludeFilters:排除扫描路径中加载的 Bean,需要指定类别(type)与具体项(classes)
- includeFilters:加载指定的 Bean,需要指定类别(type)与具体项(classes)
测试
在 com.it 下创建一个 App 类,观察运行后是否能获取到 Controller 层 Bean:
public class App {
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
System.out.println(ctx.getBean(UserController.class));
}
}
测试前,需要将 SpringMvcConfig 类上的 @Configuration
注解先注释掉,因为 SpringConfig 在设置扫描 com.it 包时,如果包中某个类添加了 @Configuration
注解,那么这个类被扫描的同时,该类 @ComponentScan
指定的 com.it.controller
也会被扫描,这样会影响 Bean 加载控制的测试效果。
优化
在实际开发中,可以优化 InitConfig 类中加载 Spring 和 SpringMVC 容器配置的过程。通过继承 AbstractDispatcherServletInitializer 类的子类,使得配置过程更加简洁:
public class InitConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[]{SpringConfig.class};
}
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{SpringMvcConfig.class};
}
@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
}