目录
(2)如何"精准"控制两个容器分别加载各自bean。(分析)
(2)方法二:直接扫描主包(com.xxx),再排除controller包。
<1>排除过滤器(excludeFilters)与包含过滤器(includeFilters)。
<2>设置过滤规则(type)与过滤类型(classes)。
<1>方法createRootApplicationContext()。
<2>Web容器配置类实现AbstractDispatcherServletInitializer类。(bean加载格式)
[<3>实现类AbstractAnnotationConfigDispatcherServletInitializer 。(更简单操作)](#<3>实现类AbstractAnnotationConfigDispatcherServletInitializer 。(更简单操作))
一、SpringMVC、Spring的bean加载控制。
(1)实际开发的包结构层次。
- 在简单的SpringMVC入门案例中:整体项目的核心包结构只有controller层与config层。
- SpringMVC学习(入门案例思路及实现、Web容器初始化与SpringMVC配置类)(2)-CSDN博客
- 但实际上真正的项目没有这么简单。其项目的主要包结构如下所示:
- config 目录。包含Web容器初识化配置类、Spring配置类、SpringMVC配置类。(取代传统开发的XML配置文件)
- controller 目录。其内部是所有SpringMVC需要加载的bean。
- service 、dao等目录。其内部都是各种业务bean、功能bean。而这些bean都是需要让Spring加载。
- 其中Spring需要管理的业务bean(service层)。需要管理的功能bean(第三方bean)如:DataSource(数据源对象)、SqlSessionFactoryBean等等MyBatis相关bean。
(2)如何"精准"控制两个容器分别加载各自bean。(分析)
<1>SpringMVC相关bean加载控制。(方法)
- 让controller层的bean被SpringMVC加载控制很容易做到。------控制SpringMVC加载的bean对应包位于对应的自己项目的controller目录下即可。
<2>Spring相关bean加载控制。(方法)
- 让Spring只加载对应的业务bean、功能bean。而避免加载到SpringMVC管理的bean。
- 方式一:Spring加载的bean设定扫描范围为com.xxx,再排除掉controller包内的bean。
- 方式二:Spring加载的bean设定扫描范围为精准范围。就是扫描包设定每层的精确范围:com.xxx.service包、com.xxx.dao包等。
- 方式三:不区分Spring与springMVC的环境,加载到同一个环境中。
二、Spring配置类------bean加载控制。
(1)方法一:设定精确范围。
- 缩小具体包对应的范围。这样就不会扫描到SpringMVC管理的bean所在controller层中。
<1>controller层。
- ExampleController类。
javapackage com.hyl.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; /** * 控制器类 */ //1.使用注解@Controller定义bean @Controller public class ExampleController { /** * 随机写一个处理请求的方法 * @return 字符串(模仿json数据) */ //设置当前方法操作的访问路径 @RequestMapping("/save") //设置当前操作的返回值类型(如何响应给客户端) @ResponseBody public String save(){ //方便测试查看运行结果。 System.out.println("exampleController save ..."); return "{'module':'springMVC'}"; } }
<2>Spring配置类。
javapackage com.hyl.config; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; //创建Spring的配置类 //排除加载controller包对应bean,使controller层交给SpringMVC管理 @Configuration @ComponentScan({"com.hyl.service","com.hyl.dao"}) /*@ComponentScan("com.hyl")*/ public class SpringConfig { }
<3>SpringMVC配置类。
javapackage com.hyl.config; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; //创建SpringMVC的配置类,加载controller包对应bean @Configuration @ComponentScan("com.hyl.controller") public class SpringMvcConfig { }
- 测试类。(App)
javapackage com.hyl.test; import com.hyl.config.SpringConfig; import com.hyl.controller.ExampleController; import org.junit.Test; import org.springframework.context.annotation.AnnotationConfigApplicationContext; public class App { @Test public void test(){ AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class); ExampleController exampleController = context.getBean(ExampleController.class); System.out.println(exampleController); } }
- 测试运行结果。无法获取controller层的对应bean。
(2)方法二:直接扫描主包(com.xxx),再排除controller包。
- 按住ctrl进入注解@ComponentScan查看其内部的可用属性。
<1>排除过滤器(excludeFilters)与包含过滤器(includeFilters)。
<2>设置过滤规则(type)与过滤类型(classes)。
- excludeFilters取值:注解@ComponentScan的Filter。
- 属性type、classes根属地。
- 过滤规则。分为很多个过滤策略:FilterType.xxx。(包括按注解过滤规则、用户自定义过滤规则、正则过滤规则等等)
- 过滤类型。当过滤规则设定为:按注解进行过滤时。就需要再手动指定需要过滤的注解是哪个类型(注解:@Controller),才能完成注解的过滤扫描。
<3>最终的Spring配置类。
- 简单说以上操作的目的:当Spring扫描整个包"com.xxx"下所有包时,需要按照注解排除扫描------注解@Controller下标明的bean。
javapackage com.hyl.config; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.FilterType; import org.springframework.stereotype.Controller; //创建Spring的配置类 //排除加载controller包对应bean,使controller层交给SpringMVC管理 @Configuration /*@ComponentScan({"com.hyl.service","com.hyl.dao"})*/ @ComponentScan(value = "com.hyl", excludeFilters = @ComponentScan.Filter( type = FilterType.ANNOTATION, classes = Controller.class ) ) public class SpringConfig { }
- 测试类。
javapackage com.hyl.test; import com.hyl.config.SpringConfig; import com.hyl.controller.ExampleController; import org.junit.Test; import org.springframework.context.annotation.AnnotationConfigApplicationContext; public class App { @Test public void test(){ AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class); ExampleController exampleController = context.getBean(ExampleController.class); System.out.println(exampleController); } }
- 测试前需要将SpringMVC的配置类的注解@Configuration注释,否则即使在spring配置类中使用了注解拦截扫描,但最终还是会因为该注解自动将bean交给Spring容器管理。
- 注释@Configuration后,继续获取Controller层的对应bean就会报错。
- 为了既可以拦截注解生效,又可以让SpringMVC配置类被扫描到,可以将其提到上一级目录或者上上级目录即可。(如:放置com包下,不放在com.xxx下的某个目录)
三、Web容器初始化配置类加载Spring环境。
- 在SpringMVC的入门案例中。配置Tomcat运行的Web容器初识化启动配置类中,当时只配置了SpringMVC的环境。这次顺手将Spring的环境一起配置了。
<1>方法createRootApplicationContext()。
- createRootApplicationContext()方法作用就是配置Spring的环境,加载Spring配置类。
- 与加载SpringMVC配置类的操作一模一样。不一样的地方就是修改:配置类.class。
<2>Web容器配置类实现AbstractDispatcherServletInitializer类。(bean加载格式)
- 这样当服务器启动时,不仅有SpringMVC容器,还有Spring容器。
- createServletApplicationContext()------>加SpringMVC容器。
- createRootApplicationContext()------>Spring容器。
javapackage com.hyl.config; import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; import org.springframework.web.servlet.support.AbstractDispatcherServletInitializer; //定义一个Servlet容器启动的配置类,在里面加载SpringMVC的配置 public class ServletContainersInitConfig extends AbstractDispatcherServletInitializer { /** *加载SpringMVC配置类 * @return */ @Override protected WebApplicationContext createServletApplicationContext() { AnnotationConfigWebApplicationContext webApplicationContext = new AnnotationConfigWebApplicationContext(); webApplicationContext.register(SpringMvcConfig.class); return webApplicationContext; } /** *加载Spring配置类(加载Spring容器) * @return */ @Override protected WebApplicationContext createRootApplicationContext() { AnnotationConfigWebApplicationContext webApplicationContext = new AnnotationConfigWebApplicationContext(); webApplicationContext.register(SpringConfig.class); return webApplicationContext; } /** * 设置哪些请求归属SpringMVC处理 * @return */ @Override protected String[] getServletMappings() { return new String[]{"/"}; } }
<3>实现类AbstractAnnotationConfigDispatcherServletInitializer 。(更简单操作)
- 简化后的Web容器配置类。
javapackage com.hyl.config; import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; //定义一个Servlet容器启动的配置类,在里面加载SpringMVC、Spring的配置 public class ServletContainersInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer { /** *加载Spring配置类(加载Spring容器) * @return */ @Override protected Class<?>[] getRootConfigClasses() { return new Class[]{SpringConfig.class}; } /** *加载SpringMVC配置类 * @return */ @Override protected Class<?>[] getServletConfigClasses() { return new Class[]{SpringMvcConfig.class}; } @Override protected String[] getServletMappings() { return new String[]{"/"}; } }