• [SpringMVC]bean加载控制


    👩🏻‍🚀博客主页:⚠️十八岁讨厌编程⚠️
    📖所属专栏:SpringMVC专栏💤
    🌌写文目的:记录学习中的知识点
    🛕目前已更新内容涵盖:🔥【前端】、🔥【后端】、🔥【人工智能】、🔥【数据分析】、🔥【网络爬虫】、🔥【数据结构与算法】、🔥【PS】、🔥【计算机数学】等几个大方面

    如果这篇文章对你有帮助,欢迎❤️关注、👍🏻点赞、🤞🏻收藏、👏🏻留言,看到我会积极回复。
    在这里插入图片描述


    在这里插入图片描述

    🏳️‍🌈bean加载控制

    🍸问题分析

    我们先来看下目前我们的项目目录结构:
    在这里插入图片描述

    • 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的配置类SpringConfig中使用注解@ComponentScan,当时扫描的范围中其实是已经包含了controller,如:
    在这里插入图片描述
    从包结构来看的话,Spring已经多把SpringMVC的controller类也给扫描到,所以针对这个问题该如何解决,就是咱们接下来要学习的内容。

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

    🍸思路分析

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

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

    具体该如何排除:

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

    🍸环境准备

    • 创建一个Web的Maven项目

    • pom.xml添加Spring依赖

      
      
      <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0modelVersion>
      
        <groupId>com.itheimagroupId>
        <artifactId>springmvc_02_bean_loadartifactId>
        <version>1.0-SNAPSHOTversion>
        <packaging>warpackaging>
      
        <dependencies>
          <dependency>
            <groupId>javax.servletgroupId>
            <artifactId>javax.servlet-apiartifactId>
            <version>3.1.0version>
            <scope>providedscope>
          dependency>
          <dependency>
            <groupId>org.springframeworkgroupId>
            <artifactId>spring-webmvcartifactId>
            <version>5.2.10.RELEASEversion>
          dependency>
          <dependency>
            <groupId>com.alibabagroupId>
            <artifactId>druidartifactId>
            <version>1.1.16version>
          dependency>
      
          <dependency>
            <groupId>org.mybatisgroupId>
            <artifactId>mybatisartifactId>
            <version>3.5.6version>
          dependency>
      
          <dependency>
            <groupId>mysqlgroupId>
            <artifactId>mysql-connector-javaartifactId>
            <version>5.1.47version>
          dependency>
      
          <dependency>
            <groupId>org.springframeworkgroupId>
            <artifactId>spring-jdbcartifactId>
            <version>5.2.10.RELEASEversion>
          dependency>
      
          <dependency>
            <groupId>org.mybatisgroupId>
            <artifactId>mybatis-springartifactId>
            <version>1.3.0version>
          dependency>
        dependencies>
      
        <build>
          <plugins>
            <plugin>
              <groupId>org.apache.tomcat.mavengroupId>
              <artifactId>tomcat7-maven-pluginartifactId>
              <version>2.1version>
              <configuration>
                <port>80port>
                <path>/path>
              configuration>
            plugin>
          plugins>
        build>
      project>
      
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40
      • 41
      • 42
      • 43
      • 44
      • 45
      • 46
      • 47
      • 48
      • 49
      • 50
      • 51
      • 52
      • 53
      • 54
      • 55
      • 56
      • 57
      • 58
      • 59
      • 60
      • 61
      • 62
      • 63
      • 64
      • 65
      • 66
      • 67
      • 68
      • 69
    • 创建对应的配置类

      public class ServletContainersInitConfig extends AbstractDispatcherServletInitializer {
          protected WebApplicationContext createServletApplicationContext() {
              AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
              ctx.register(SpringMvcConfig.class);
              return ctx;
          }
          protected String[] getServletMappings() {
              return new String[]{"/"};
          }
          protected WebApplicationContext createRootApplicationContext() {
            return null;
          }
      }
      
      @Configuration
      @ComponentScan("com.itheima.controller")
      public class SpringMvcConfig {
      }
      
      @Configuration
      @ComponentScan("com.itheima")
      public class SpringConfig {
      }
      
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
    • 编写Controller,Service,Dao,Domain类

      @Controller
      public class UserController {
      
          @RequestMapping("/save")
          @ResponseBody
          public String save(){
              System.out.println("user save ...");
              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略
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32

    最终创建好的项目结构如下:
    在这里插入图片描述

    🍸设置bean加载控制

    💊方法一

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

    @Configuration
    @ComponentScan({"com.nefu.service","com.nefu.dao"})
    public class SpringConfig {
    }
    
    • 1
    • 2
    • 3
    • 4

    注意:

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

    💊方法二

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

    @Configuration
    @ComponentScan(value="com.nefu",
        excludeFilters=@ComponentScan.Filter(
        	type = FilterType.ANNOTATION,
            classes = Controller.class
        )
    )
    public class SpringConfig {
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    这个地方要注意一点,你在写这个Controller.class的时候可能有多个类符合要求:
    在这里插入图片描述
    这里导的是第一个,如果导错了程序会报错!

    • excludeFilters属性:设置扫描加载bean时,排除的过滤规则

      在这里插入图片描述
      我们可以看见两个过滤方法:
      excludeFilters代表去除
      includeFilters代表包含

    • 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));
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

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

    注意:测试的时候,需要把SpringMvcConfig配置类上的@ComponentScan注解注释掉,否则不会报错

    这是因为:Spring配置类扫描的包是com.nefu,SpringMVC的配置类,SpringMvcConfig上有一个@Configuration注解,也会被Spring扫描到,SpringMvcConfig上又有一个@ComponentScan,把controller类又给扫描进来了。所以如果不把@ComponentScan注释掉,Spring配置类将Controller排除,但是因为扫描到SpringMVC的配置类,又将其加载回来,演示的效果就出不来。

    解决方案,也简单,把SpringMVC的配置类移出Spring配置类的扫描范围即可。

    最后一个问题,有了Spring的配置类,要想在tomcat服务器启动将其加载,我们需要修改ServletContainersInitConfig
    public class ServletContainersInitConfig extends AbstractDispatcherServletInitializer {
        protected WebApplicationContext createServletApplicationContext() {
            AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
            ctx.register(SpringMvcConfig.class);
            return ctx;
        }
        protected String[] getServletMappings() {
            return new String[]{"/"};
        }
        protected WebApplicationContext createRootApplicationContext() {
          AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
            ctx.register(SpringConfig.class);
            return ctx;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

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

    我们打开AnnotationConfigWebApplicationContext发现,在他的下面还有一个子类AbstractAnnotationConfigDispatcherServletInitializer在这里插入图片描述
    借助它我们就可以简化配置类:

    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[]{"/"};
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    🏳️‍🌈总结

    名称@ComponentScan
    类型类注解
    位置类定义上方
    作用设置spring配置类扫描路径,用于加载使用注解格式定义的bean
    相关属性excludeFilters:排除扫描路径中加载的bean,需要指定类别(type)和具体项(classes)
    includeFilters:加载指定的bean,需要指定类别(type)和具体项(classes)
  • 相关阅读:
    成功上岸,刚转行自学Python的小姑娘,每个月入1W+......
    5G引领未来,抖音小店身处风口,能否再次掀起无货源创业热潮?
    【EI会议征稿】2023年第二届信号处理、计算机网络与通信国际学术会议(SPCNC2023)
    710. 黑名单中的随机数
    Spring BeanDefinition详解
    热点key限流(3)
    比 eval 和 iframe 更强的新一代 JavaScript 沙箱
    Nginx内存池:重置函数和小块内存回收方案
    【计算机网络实验】TCP和UDP传输过程仿真与分析
    想搞清楚API网关到底是什么?请看这篇
  • 原文地址:https://blog.csdn.net/zyb18507175502/article/details/125847360