服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - Java教程 - Spring MVC通过注解完成运行配置,原理你都会吗?

Spring MVC通过注解完成运行配置,原理你都会吗?

2023-05-10 15:05Springboot实战案例锦集 Java教程

SpringMVC使用相信大家都会使用,别人项目工程搭建后,你只需负责写Controller即可,那你是否想过自己能否把环境搭建出来呢?而且还不借助网络;本篇教大家如何通过注解快速搭建SpringMVC运行环境。

环境:Spring5.3.26

SpringMVC使用相信大家都会使用,别人项目工程搭建后,你只需负责写Controller即可,那你是否想过自己能否把环境搭建出来呢?而且还不借助网络;本篇教大家如何通过注解快速搭建SpringMVC运行环境。

传统SpringMVC配置

本节:回顾传统SpringMVC的基本配置原理。

DispatcherServlet需要一个WebApplicationContext(一个普通ApplicationContext的扩展)用于它自己的配置。WebApplicationContext有一个链接到ServletContext和它所关联的Servlet。它还绑定到ServletContext,这样应用程序就可以在需要访问WebApplicationContext时使用RequestContextUtils上的静态方法来查找它。

对于许多应用程序来说,只有一个WebApplicationContext就足够简单了。也可以有一个上下文层次结构,其中一个根WebApplicationContext在多个DispatcherServlet(或其他Servlet)实例之间共享,每个实例都有自己的子WebApplicationContext配置。有关上下文层次结构特性的更多信息,请参阅ApplicationContext的附加功能。

根WebApplicationContext通常包含基础设施bean,例如需要跨多个Servlet实例共享的数据存储库和业务服务。这些bean被有效地继承,并且可以在特定于Servlet的子WebApplicationContext中被重写(即重新声明),该子WebApplicationContext通常包含给定Servlet的本地bean。下图显示了这种关系:

Spring MVC通过注解完成运行配置,原理你都会吗?

web.xml中配置:

  1. <web-app> 
  2.  
  3.  
  4.     <listener> 
  5.         <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class
  6.     </listener> 
  7.  
  8.  
  9.     <context-param> 
  10.         <param-name>contextConfigLocation</param-name> 
  11.         <param-value>/WEB-INF/root-context.xml</param-value> 
  12.     </context-param> 
  13.  
  14.  
  15.     <servlet> 
  16.         <servlet-name>app1</servlet-name> 
  17.         <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class
  18.         <init-param> 
  19.             <param-name>contextConfigLocation</param-name> 
  20.             <param-value>/WEB-INF/app1-context.xml</param-value> 
  21.         </init-param> 
  22.         <load-on-startup>1</load-on-startup> 
  23.     </servlet> 
  24.  
  25.  
  26.     <servlet-mapping> 
  27.         <servlet-name>app1</servlet-name> 
  28.         <url-pattern>/app1/*</url-pattern> 
  29.     </servlet-mapping> 
  30.  
  31.  
  32. </web-app> 

ContextLoaderListener:该监听器用来创建Root 容器,该容器就是用来配置基础的Bean,如DAO,Service等。

DispatcherServlet:对应一个web 容器,也就是子容器。该容器用来配置Controller。在Controller中会应用到Service,那么该子容器就会从父容器中查找相应的Bean。如下父子关系配置:

  1. public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware { 
  2.   protected WebApplicationContext initWebApplicationContext() { 
  3.     // 获取父容器,该父容器是在ContextLoaderListener监听器中创建并保存到ServletContext中 
  4.     WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(getServletContext()); 
  5.     WebApplicationContext wac = null
  6.  
  7.  
  8.     if (this.webApplicationContext != null) { 
  9.       wac = this.webApplicationContext; 
  10.         if (wac instanceof ConfigurableWebApplicationContext) { 
  11.           ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac; 
  12.           if (!cwac.isActive()) { 
  13.             if (cwac.getParent() == null) { 
  14.               cwac.setParent(rootContext); 
  15.             } 
  16.             configureAndRefreshWebApplicationContext(cwac); 
  17.          } 
  18.       } 
  19.     } 
  20.     if (wac == null) { 
  21.       // 创建子容器并设置父容器 
  22.       wac = createWebApplicationContext(rootContext); 
  23.     } 
  24.     return wac; 
  25.   } 

以上就是SpringMVC的基本配置。

Servlet注册

既然是基于注解的方式配置SpringMVC,那么我们需要先了解Servlet的注册方式有哪些。

方式1:

web.xml中注册

  1. <servlet> 
  2.   <servlet-name>DemoServlet</servlet-name> 
  3.   <servlet-class>com.pack.servlet.DemoServlet</servlet-class
  4. </servlet> 
  5. <servlet-mapping> 
  6.   <servlet-name>DemoServlet</servlet-name> 
  7.   <url-pattern>/demo</url-pattern> 
  8. </servlet-mapping> 

方式2:

基于注解方式

  1. @WebServlet(name = "demoServlet", urlPatterns = "/demo"
  2. @WebServlet(value = {"/demo","/demo1"}) 
  3. @WebServlet(value = "/demo"
  4. @WebServlet("/demo"
  5. public class DemoServlet extends HttpServlet { 
  6.   // ... 

方式3:

通过SPI技术,这也是今天要使用的方式

Servlet3.0以上的版本开始,可以通过SPI方式注册Servlet,Filter,Listener三大组件。

第一步:在项目中建立如下文件

  1. META-INF/service/javax.servlet.ServletContainerInitializer 

文件名:javax.servlet.ServletContainerInitializer

第二步:自定义类实现ServletContainerInitializer

  1. @HandlesTypes({CustomHandler.class}) 
  2. public class CustomContainerInitializer implements ServletContainerInitializer { 
  3.   // 这里的set集合就是当前环境中所有CustomHandler的子类 
  4.   @Override 
  5.   public void onStartup(Set<Class<?>> set, ServletContext servletContext) throws ServletException { 
  6.     if (set!=null&&set.size()>0){ 
  7.       set.stream().forEach(cls->{ 
  8.         try { 
  9.           CustomHandler o = (CustomHandler)cls.newInstance(); 
  10.           o.onStartup(); 
  11.         } catch (Exception e) { 
  12.           e.printStackTrace(); 
  13.         } 
  14.       }); 
  15.     } 
  16.     //注入Servlet 
  17.     ServletRegistration.Dynamic userServlet = servletContext.addServlet("DemoServlet", DemoServlet.class); 
  18.     userServlet.addMapping("/demo"); 
  19.   } 

SpringMVC注解配置

接下来就是要使用上面介绍的Servlet注册方式的第三种方式来实现SpringMVC的注册。

在Spring中已经提供了相应的实现:

在spring-web包中:

Spring MVC通过注解完成运行配置,原理你都会吗?

 

内容:

  1. org.springframework.web.SpringServletContainerInitializer 
  1. @HandlesTypes(WebApplicationInitializer.class
  2. public class SpringServletContainerInitializer implements ServletContainerInitializer { 

这里我们只需要实现WebApplicationInitializer接口即可,不过Spring已经为我们定义好了该接口的抽象模版,我们只需继承该抽象类即可:

  1. public class SpringMVCConfig extends AbstractAnnotationConfigDispatcherServletInitializer { 
  2.  
  3.  
  4.   @Override 
  5.   protected Class<?>[] getRootConfigClasses() { 
  6.     return new Class<?>[] {RootConfig.class} ; 
  7.   } 
  8.  
  9.  
  10.   @Override 
  11.   protected Class<?>[] getServletConfigClasses() { 
  12.     return new Class<?>[] {WebConfig.class} ; 
  13.   } 
  14.  
  15.  
  16.   @Override 
  17.   protected String[] getServletMappings() { 
  18.     return new String[] {"/"} ; 
  19.   } 
  20.  
  21.  

RootConfig.java

  1. @Configuration 
  2. public class RootConfig { 

WebConfig.java

  1. @Configuration 
  2. @ComponentScan(basePackages = {"com.pack.controller"}) 
  3. public class WebConfig { 
  4.    

测试controller

  1. @RestController 
  2. @RequestMapping("/demo"
  3. public class DemoController { 
  4.  
  5.  
  6.   @GetMapping(""
  7.   public Object index() { 
  8.     Map<String, Object> result = new HashMap<>() ; 
  9.     result.put("code", 0) ; 
  10.     result.put("data""你好") ; 
  11.     return result ; 
  12.   } 
  13.    

测试:

只是通过如上配置,SpringMVC环境基本上是可以使用了,但是我们看上面Controller接口,是基于REST full,所以当你访问该接口时会出现如下错误:

Spring MVC通过注解完成运行配置,原理你都会吗?

这是因为默认情况下RequestMappingHandlerAdapter无法处理,服务器端无法提供与 Accept-Charset 以及 Accept-Language 消息头指定的值相匹配的响应。

这时候就需要为其配置相应的消息转换器:

  1. @Bean 
  2. public RequestMappingHandlerAdapter requestMappingHandlerAdapter() { 
  3.   RequestMappingHandlerAdapter adapter = new RequestMappingHandlerAdapter() ; 
  4.   adapter.getMessageConverters().add(new MappingJackson2HttpMessageConverter()) ; 
  5.   return adapter ; 

再次方法正常:

Spring MVC通过注解完成运行配置,原理你都会吗?

完毕!!!

原文地址:https://mp.weixin.qq.com/s/uQB-eDTuiXL7ODqfBgH2qg

延伸 · 阅读

精彩推荐