【Spring教程26】Spring框架实战:从零开始学习SpringMVC 之 bean加载控制
作者:mmseoamin日期:2023-12-18

目录

  • 1 问题分析
  • 2 思路分析
  • 3 环境准备
  • 4 设置bean加载控制
  • 5 知识点1:@ComponentScan

    欢迎大家回到《Java教程之Spring30天快速入门》,本教程所有示例均基于Maven实现,如果您对Maven还很陌生,请移步本人的博文《如何在windows11下安装Maven并配置以及 IDEA配置Maven环境》,本文的上一篇为《SpringMVC入门案例总结与SpringMVC工作流程分析》

    【Spring教程26】Spring框架实战:从零开始学习SpringMVC 之 bean加载控制,在这里插入图片描述,第1张

    1 问题分析

    入门案例的内容已经做完了,在入门案例中我们创建过一个SpringMvcConfig的配置类,再回想前面咱们学习Spring的时候也创建过一个配置类SpringConfig。这两个配置类都需要加载资源,那么它们分别都需要加载哪些内容?

    我们先来看下目前我们的项目目录结构:

    【Spring教程26】Spring框架实战:从零开始学习SpringMVC 之 bean加载控制,在这里插入图片描述,第2张

    • config目录存入的是配置类,写过的配置类有:
      • ServletContainersInitConfig
      • SpringConfig
      • SpringMvcConfig
      • JdbcConfig
      • MybatisConfig
      • controller目录存放的是SpringMVC的controller类
      • service目录存放的是service接口和实现类
      • dao目录存放的是dao/Mapper接口

        controller、service和dao这些类都需要被容器管理成bean对象,那么到底是该让SpringMVC加

        载还是让Spring加载呢?

        • SpringMVC加载其相关bean(表现层bean),也就是controller包下的类
        • Spring控制的bean
          • 业务bean(Service)
          • 功能bean(DataSource,SqlSessionFactoryBean,MapperScannerConfigurer等)

            分析清楚谁该管哪些bean以后,接下来要解决的问题是如何让Spring和SpringMVC分开加载各自的内容。

            在SpringMVC的配置类SpringMvcConfig中使用注解@ComponentScan,我们只需要将其扫描范围设置到controller即可,如

            【Spring教程26】Spring框架实战:从零开始学习SpringMVC 之 bean加载控制,在这里插入图片描述,第3张

            在Spring的配置类SpringConfig中使用注解@ComponentScan ,当时扫描的范围中其实是已经包含

            了controller,如:

            【Spring教程26】Spring框架实战:从零开始学习SpringMVC 之 bean加载控制,在这里插入图片描述,第4张

            从包结构来看的话,Spring已经多把SpringMVC的controller类也给扫描到,所以针对这个问题

            该如何解决,就是咱们接下来要学习的内容。

            概况的描述下咱们现在的问题就是因为功能不同,如何避免Spring错误加载到SpringMVC的bean?

            2 思路分析

            针对上面的问题,解决方案也比较简单,就是:

            • 加载Spring控制的bean的时候排除掉SpringMVC控制的备案

              具体该如何排除,有两种方式来解决:

              • 方式一:Spring加载的bean设定扫描范围为com.itheima,排除掉controller包中的bean
              • 方式二:Spring加载的bean设定扫描范围为精准范围,例如service包、dao包等
              • 方式三:不区分Spring与SpringMVC的环境,加载到同一个环境中[了解即可]

                3 环境准备

                • 创建一个Web的Maven项目
                • pom.xml添加Spring依赖
                  
                  
                  4.0.0
                  com.itheima
                  springmvc_02_bean_load
                  1.0-SNAPSHOT
                  war
                  
                  
                  javax.servlet
                  javax.servlet-api
                  16 3.1.0
                  17 provided
                  18 
                  19 
                  20 org.springframework
                  21 spring-webmvc
                  22 5.2.10.RELEASE
                  23 
                  24 
                  25 com.alibaba
                  26 druid
                  27 1.1.16
                  28 
                  29
                  30 
                  31 org.mybatis
                  32 mybatis
                  33 3.5.6
                  34 
                  35
                  36 
                  37 mysql
                  38 mysql-connector-java
                  39 5.1.47
                  40 
                  41
                  42 
                  43 org.springframework
                  44 spring-jdbc
                  45 5.2.10.RELEASE
                  46 
                  47
                  48 
                  49 org.mybatis
                  50 mybatis-spring
                  51 1.3.0
                  52 
                  53 
                  54
                  55 
                  56 
                  57 
                  58 org.apache.tomcat.maven
                  59 tomcat7-maven-plugin
                  60 2.1
                  61 
                  80
                  63 /
                  64 
                  65 
                  66 
                  67 
                  68 
                  
                  • 创建对应的配置类
                    public class ServletContainersInitConfig extends
                    AbstractDispatcherServletInitializer {
                    2 protected WebApplicationContext createServletApplicationContext() {
                    3 AnnotationConfigWebApplicationContext ctx = new
                    AnnotationConfigWebApplicationContext();
                    4 ctx.register(SpringMvcConfig.class);
                    5 return ctx;
                    6 }
                    7 protected String[] getServletMappings() {
                    8 return new String[]{"/"};
                    9 }
                    10 protected WebApplicationContext createRootApplicationContext() {
                    11 return null;
                    12 }
                    13 }
                    14
                    15 @Configuration
                    16 @ComponentScan("com.itheima.controller")
                    17 public class SpringMvcConfig {
                    18 }
                    19
                    20 @Configuration
                    21 @ComponentScan("com.itheima")
                    22 public class SpringConfig {
                    23 }
                    
                    • 编写Controller,Service,Dao,Domain类
                      @Controller
                      2 public class UserController {
                      3
                      4 @RequestMapping("/save")
                      5 @ResponseBody
                      6 public String save(){
                      7 System.out.println("user save ...");
                      8 return "{'info':'springmvc'}";
                      }
                      }
                      public interface UserService {
                      public void save(User user);
                      }
                      @Service
                      public class UserServiceImpl implements UserService {
                      public void save(User user) {
                      System.out.println("user service ...");
                      }
                      }
                      public interface UserDao {
                      @Insert("insert into tbl_user(name,age)values(#{name},#{age})")
                      public void save(User user);
                      }
                      public class User {
                      private Integer id;
                      private String name;
                      private Integer age;
                      //setter..getter..toString略
                      }
                      

                      【Spring教程26】Spring框架实战:从零开始学习SpringMVC 之 bean加载控制,在这里插入图片描述,第5张

                      4 设置bean加载控制

                      方式一:修改Spring配置类,设定扫描范围为精准范围。

                      @Configuration
                      @ComponentScan({"com.itheima.service","comitheima.dao"})
                      public class SpringConfig {
                      }
                      

                      说明:

                      上述只是通过例子说明可以精确指定让Spring扫描对应的包结构,真正在做开发的时候,因为Dao最终是交给MapperScannerConfigurer对象来进行扫描处理的,我们只需要将其扫描到service包即可。

                      方式二:修改Spring配置类,设定扫描范围为com.itheima,排除掉controller包中的bean

                      @Configuration
                      @ComponentScan(value="com.itheima",
                      	excludeFilters=@ComponentScan.Filter(
                      		type = FilterType.ANNOTATION,
                      		classes = Controller.class
                      	)
                      )
                      public class SpringConfig {
                      }
                      
                      • excludeFilters属性:设置扫描加载bean时,排除的过滤规则
                      • type属性:设置排除规则,当前使用按照bean定义时的注解类型进行排除
                        • ANNOTATION:按照注解排除
                        • ASSIGNABLE_TYPE:按照指定的类型过滤
                        • ASPECTJ:按照Aspectj表达式排除,基本上不会用
                        • REGEX:按照正则表达式排除
                        • CUSTOM:按照自定义规则排除

                          大家只需要知道第一种ANNOTATION即可

                          • classes属性:设置排除的具体注解类,当前设置排除@Controller定义的bean

                            如何测试controller类已经被排除掉了

                            public class App{
                            public static void main (String[] args){
                            AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
                            		System.out.println(ctx.getBean(UserController.class));
                            	}
                            }
                            

                            如果被排除了,该方法执行就会报bean未被定义的错误

                            【Spring教程26】Spring框架实战:从零开始学习SpringMVC 之 bean加载控制,在这里插入图片描述,第6张

                            出现问题的原因是,

                            • Spring配置类扫描的包是com.itheima
                            • SpringMVC的配置类,SpringMvcConfig上有一个@Configuration注解,也会被Spring扫描到
                            • SpringMvcConfig上又有一个@ComponentScan,把controller类又给扫描进来了
                            • 所以如果不把@ComponentScan注释掉,Spring配置类将Controller排除,但是因为扫描到SpringMVC的配置类,又将其加载回来,演示的效果就出不来
                            • 解决方案,也简单,把SpringMVC的配置类移出Spring配置类的扫描范围即可。
                            • 最后一个问题,有了Spring的配置类,要想在tomcat服务器启动将其加载,我们需要修改ServletContainersInitConfig

                              1 public class ServletContainersInitConfig extends
                              AbstractDispatcherServletInitializer {
                              2 protected WebApplicationContext createServletApplicationContext() {
                              3 AnnotationConfigWebApplicationContext ctx = new
                              AnnotationConfigWebApplicationContext();
                              4 ctx.register(SpringMvcConfig.class);
                              5 return ctx;
                              6 }
                              7 protected String[] getServletMappings() {
                              8 return new String[]{"/"};
                              9 }
                              10 protected WebApplicationContext createRootApplicationContext() {
                              11 AnnotationConfigWebApplicationContext ctx = new
                              AnnotationConfigWebApplicationContext();
                              12 ctx.register(SpringConfig.class);
                              13 return ctx;
                              14 }
                              15 }
                              

                              对于上述的配置方式,Spring还提供了一种更简单的配置方式,可以不用再去创建AnnotationConfigWebApplicationContext对象,不用手动register对应的配置类,如何实现?

                              public class ServletContainersInitConfig extends
                              AbstractAnnotationConfigDispatcherServletInitializer {
                              protected Class[] getRootConfigClasses() {
                              return new Class[]{SpringConfig.class};
                              }
                              protected Class[] getServletConfigClasses() {
                              return new Class[]{SpringMvcConfig.class};
                              }
                              protected String[] getServletMappings() {
                              return new String[]{"/"};
                              }
                              }
                              

                              5 知识点1:@ComponentScan

                              名称@ComponentScan
                              类型类注解
                              位置类定义上方
                              作用设置spring配置类扫描路径,用于加载使用注解格式定义的bean
                              相关属性excludeFilters:排除扫描路径中加载的bean,需要指定类别(type)和具体项(classes)includeFilters:加载指定的bean,需要指定类别(type)和具体项(classes)