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

环境:Spring5.3.26

创新互联建站长期为上1000+客户提供的网站建设服务,团队从业经验10年,关注不同地域、不同群体,并针对不同对象提供差异化的产品和服务;打造开放共赢平台,与合作伙伴共同营造健康的互联网生态环境。为十堰企业提供专业的网站设计、成都网站制作十堰网站改版等技术服务。拥有10余年丰富建站经验和众多成功案例,为您定制开发。

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中配置:




    
        org.springframework.web.context.ContextLoaderListener
    


    
        contextConfigLocation
        /WEB-INF/root-context.xml
    


    
        app1
        org.springframework.web.servlet.DispatcherServlet
        
            contextConfigLocation
            /WEB-INF/app1-context.xml
        
        1
    


    
        app1
        /app1/*
    


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中注册


  DemoServlet
  com.pack.servlet.DemoServlet


  DemoServlet
  /demo

方式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> 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 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 ;
}

再次方法正常:

完毕!!!

网页题目:SpringMVC通过注解完成运行配置,原理你都会吗?
文章分享:http://www.shufengxianlan.com/qtweb/news17/278267.html

网站建设、网络推广公司-创新互联,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等

广告

声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联