好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

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

环境: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。下图显示了这种关系:

web.xml中配置:

<web-app>          <listener>          <listener- class >org.springframework.web.context.ContextLoaderListener</listener- class >      </listener>          <context-param>          <param-name>contextConfigLocation</param-name>          <param-value>/WEB-INF/root-context.xml</param-value>      </context-param>          <servlet>          <servlet-name>app1</servlet-name>          <servlet- class >org.springframework.web.servlet.DispatcherServlet</servlet- class >          <init-param>              <param-name>contextConfigLocation</param-name>              <param-value>/WEB-INF/app1-context.xml</param-value>          </init-param>          <load-on-startup>1</load-on-startup>      </servlet>          <servlet-mapping>          <servlet-name>app1</servlet-name>          <url-pattern>/app1/*</url-pattern>      </servlet-mapping>      </web-app> 

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

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

public   abstract   class  FrameworkServlet  extends  HttpServletBean  implements  ApplicationContextAware {     protected  WebApplicationContext initWebApplicationContext() {       // 获取父容器,该父容器是在ContextLoaderListener监听器中创建并保存到ServletContext中       WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(getServletContext());      WebApplicationContext wac =  null ;           if  ( this .webApplicationContext !=  null ) {        wac =  this .webApplicationContext;           if  (wac  instanceof  ConfigurableWebApplicationContext) {            ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;             if  (!cwac.isActive()) {               if  (cwac.getParent() ==  null ) {                cwac.setParent(rootContext);              }              configureAndRefreshWebApplicationContext(cwac);           }        }      }       if  (wac ==  null ) {         // 创建子容器并设置父容器         wac = createWebApplicationContext(rootContext);      }       return  wac;    }  } 

以上就是SpringMVC的基本配置。

Servlet注册

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

方式1:

web.xml中注册

<servlet>    <servlet-name>DemoServlet</servlet-name>    <servlet- class >com.pack.servlet.DemoServlet</servlet- class >  </servlet>  <servlet-mapping>    <servlet-name>DemoServlet</servlet-name>    <url-pattern>/demo</url-pattern>  </servlet-mapping> 

方式2:

基于注解方式

@WebServlet(name =  "demoServlet" , urlPatterns =  "/demo" )  @WebServlet(value = { "/demo" , "/demo1" })  @WebServlet(value =  "/demo" )  @WebServlet( "/demo" )  public   class  DemoServlet  extends  HttpServlet {     // ...   } 

方式3:

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

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

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

META-INF/service/javax.servlet.ServletContainerInitializer 

文件名:javax.servlet.ServletContainerInitializer

第二步:自定义类实现ServletContainerInitializer

@HandlesTypes({CustomHandler. class })  public   class  CustomContainerInitializer  implements  ServletContainerInitializer {     // 这里的set集合就是当前环境中所有CustomHandler的子类     @Override     public   void  onStartup(Set<Class<?>> set, ServletContext servletContext)  throws  ServletException {       if  (set!= null &&set.size()>0){        set.stream().forEach(cls->{           try  {            CustomHandler o = (CustomHandler)cls.newInstance();            o.onStartup();          }  catch  (Exception e) {            e.printStackTrace();          }        });      }       //注入Servlet       ServletRegistration.Dynamic userServlet = servletContext.addServlet( "DemoServlet" , DemoServlet. class );      userServlet.addMapping( "/demo" );    }  } 

SpringMVC注解配置

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

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

在spring-web包中:

 

内容:

org.springframework.web.SpringServletContainerInitializer 

@HandlesTypes(WebApplicationInitializer. class )  public   class  SpringServletContainerInitializer  implements  ServletContainerInitializer {  } 

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

public   class  SpringMVCConfig  extends  AbstractAnnotationConfigDispatcherServletInitializer {        @Override     protected  Class<?>[] getRootConfigClasses() {       return   new  Class<?>[] {RootConfig. class } ;    }        @Override     protected  Class<?>[] getServletConfigClasses() {       return   new  Class<?>[] {WebConfig. class } ;    }        @Override     protected  String[] getServletMappings() {       return   new  String[] { "/" } ;    }      } 

RootConfig.java

@Configuration  public   class  RootConfig {  } 

WebConfig.java

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

测试controller

@RestController  @RequestMapping( "/demo" )  public   class  DemoController {        @GetMapping( "" )     public  Object index() {      Map<String, Object> result =  new  HashMap<>() ;      result.put( "code" , 0) ;      result.put( "data" ,  "你好" ) ;       return  result ;    }      } 

测试:

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

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

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

@Bean  public  RequestMappingHandlerAdapter requestMappingHandlerAdapter() {    RequestMappingHandlerAdapter adapter =  new  RequestMappingHandlerAdapter() ;    adapter.getMessageConverters().add( new  MappingJackson2HttpMessageConverter()) ;     return  adapter ;  } 

再次方法正常:

完毕!!!

原文地址:https://mp.weixin.qq测试数据/s/uQB-eDTuiXL7ODqfBgH2qg

查看更多关于Spring MVC通过注解完成运行配置,原理你都会吗?的详细内容...

  阅读:17次