软件编程
位置:首页>> 软件编程>> java编程>> SpringMVC bean加载控制的实现分析

SpringMVC bean加载控制的实现分析

作者:tanglin_030907031026  发布时间:2023-08-08 18:46:19 

标签:SpringMVC,bean,加载控制

一、问题分析

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

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

SpringMVC 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即可,如

@configuration
@componentscan ("com.itheima.contro1ler")
public class springMvcconfig {
}

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

@componentscan (value="com.itheima")
public class springconfig {
}

从包结构来看的话,Spring已经多把SpringMVC的controller类也给扫描到,所以针对这个问题该如何解决,就是咱们接下来要学习的内容。

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

二、思路分析

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

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

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

  • 方式一:Spring加载的bean设定扫描范围为com.itheima,排除掉controller包中的bean

  • 方式二:Spring加载的bean设定扫描范围为精准范围,例如service包、dao包等

  • 方式三:不区分Spring与SpringMVC的环境,加载到同一个环境中[了解即可]

三、环境准备

创建一个Web的Maven项目

pom.xml添加Spring依赖

<?xml version="1.0" encoding="UTF-8"?>
<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.0</modelVersion>
 <groupId>com.itheima</groupId>
 <artifactId>springmvc_02_bean_load</artifactId>
 <version>1.0-SNAPSHOT</version>
 <packaging>war</packaging>
 <dependencies>
   <dependency>
     <groupId>javax.servlet</groupId>
     <artifactId>javax.servlet-api</artifactId>
     <version>3.1.0</version>
     <scope>provided</scope>
   </dependency>
   <dependency>
     <groupId>org.springframework</groupId>
     <artifactId>spring-webmvc</artifactId>
     <version>5.2.10.RELEASE</version>
   </dependency>
   <dependency>
     <groupId>com.alibaba</groupId>
     <artifactId>druid</artifactId>
     <version>1.1.16</version>
   </dependency>
   <dependency>
     <groupId>org.mybatis</groupId>
     <artifactId>mybatis</artifactId>
     <version>3.5.6</version>
   </dependency>
   <dependency>
     <groupId>mysql</groupId>
     <artifactId>mysql-connector-java</artifactId>
     <version>5.1.47</version>
   </dependency>
   <dependency>
     <groupId>org.springframework</groupId>
     <artifactId>spring-jdbc</artifactId>
     <version>5.2.10.RELEASE</version>
   </dependency>
   <dependency>
     <groupId>org.mybatis</groupId>
     <artifactId>mybatis-spring</artifactId>
     <version>1.3.0</version>
   </dependency>
 </dependencies>
 <build>
   <plugins>
     <plugin>
       <groupId>org.apache.tomcat.maven</groupId>
       <artifactId>tomcat7-maven-plugin</artifactId>
       <version>2.1</version>
       <configuration>
         <port>80</port>
         <path>/</path>
       </configuration>
     </plugin>
   </plugins>
 </build>
</project>

创建对应的配置类

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 {
}

编写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略
}

最终创建好的项目结构如下:

SpringMVC bean加载控制的实现分析

四、设置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未被定义的错误

SpringMVC bean加载控制的实现分析

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

出现问题的原因是,

  • Spring配置类扫描的包是com.itheima

  • 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;
   }
}

对于上述的配置方式,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[]{"/"};
   }
}

知识点:@ComponentScan 

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

来源:https://blog.csdn.net/qq_61313896/article/details/128857504

0
投稿

猜你喜欢

手机版 软件编程 asp之家 www.aspxhome.com