Spring Boot原理(上):Spring MVC零配置演示和讲解(含SPI机制)

Spring Boot是零配置无xml配置文件,其中对于MVC,可以实现无web.xml文件。
那么是如何做到的呢? 本文先通过一个例子演示无web.xml的效果,然后讲解JDK中的SPI机制,以及servlet如何利用SPI机制。最后分析tomcat调用加载的过程。

一、Spring MVC 无web.xml配置

传统式对于Java Web服务,一般都需要web.xml作为Web服务的顶级配置文件。

然而对于Spring来说,且实现了Servlet 3.0既以上的容器(如Tomcat),可以无需web.xml文件,即可正常运行Web服务,达到同等效果。

1、演示如下

1、在Eclipse中新建一个动态Web工程。工程名任意,这里工程名暂定为NoXML

2、将Spring 5.X Framework 的二十几个jar和commons-logging相关的jar文件,放入NoXML\WebContent\WEB-INF\lib目录下。 同时在Eclipse设置工程引用这些jar文件。具体文件为:

commons-fileupload-1.4.jar
commons-io-2.6.jar
commons-logging-1.2.jar
spring-aop-5.2.2.RELEASE.jar
spring-aspects-5.2.2.RELEASE.jar
spring-beans-5.2.2.RELEASE.jar
spring-context-5.2.2.RELEASE.jar
spring-context-indexer-5.2.2.RELEASE.jar
spring-context-support-5.2.2.RELEASE.jar
spring-core-5.2.2.RELEASE.jar
spring-expression-5.2.2.RELEASE.jar
spring-instrument-5.2.2.RELEASE.jar
spring-jcl-5.2.2.RELEASE.jar
spring-jdbc-5.2.2.RELEASE.jar
spring-jms-5.2.2.RELEASE.jar
spring-messaging-5.2.2.RELEASE.jar
spring-orm-5.2.2.RELEASE.jar
spring-oxm-5.2.2.RELEASE.jar
spring-test-5.2.2.RELEASE.jar
spring-tx-5.2.2.RELEASE.jar
spring-web-5.2.2.RELEASE.jar
spring-webflux-5.2.2.RELEASE.jar
spring-webmvc-5.2.2.RELEASE.jar
spring-websocket-5.2.2.RELEASE.jar

3、增加一个Java类com.zyp.MyWebApplicationInitializer,代码拷贝自Spring官方文档(https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html)如下:

package com.zyp;

import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;

import javax.servlet.ServletContext;
import javax.servlet.ServletRegistration;

public class MyWebApplicationInitializer implements WebApplicationInitializer {
   

    @Override
    public void onStartup(ServletContext servletCxt) {
   

        System.err.println("------------Load Spring web application configuration");
        AnnotationConfigWebApplicationContext ac = new AnnotationConfigWebApplicationContext();
        ac.register(AppConfig.class);
        ac.refresh();

        System.err.println("------------Create and register the DispatcherServlet");
        DispatcherServlet servlet = new DispatcherServlet(ac);
        ServletRegistration.Dynamic registration = servletCxt.addServlet("app", servlet); // 第一个参数为servlet名
        registration.setLoadOnStartup(1);
        registration.addMapping("/app/*");
    }
}

4、增加一个Java配置类(Java Configuration Class)。com.zyp.AppConfig,代码如下:

package com.zyp;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Configuration
@ComponentScan(basePackages = {
   "com.zyp.controller"})
public class AppConfig {
   
    
}

4、增加一个Java Controller用于测试。com.zyp.AppConfig,为简单没有返回网页,而是输出日志查看是否被正常访问。代码如下:

package com.zyp.controller;

import java.util.ArrayList;
import java.util.List;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.CookieValue;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;

import com.zyp.domain.User;

@Controller
public class UserController {
   
	@RequestMapping(value= "/index.do")
	@ResponseBody
	public String index() {
   
	    System.out.println("index.do has been called sucessfully");
		return "index.do has been called sucessfully";	
	}
}

5、对此。无web.xml的Web工程配置完毕。 启动一个tomcat server,在tomcat server纳入本工程(本NoXML工程) 。在浏览器中访问:http://localhost:8080/NoXML/app/index.do 通过日志可以看到定义的Controller index.do成功访问,且浏览器中显示的内容为:
在这里插入图片描述

2、分析说明

替代了什么

通过上文的MyWebApplicationInitializer类,实现的效果类似于以下的web.xml。通过以上AppConfig类,实现了常用的app-context.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/app-context.xml</param-value>
    </context-param>

    <servlet>
        <servlet-name>app</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value></param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>app</servlet-name>
        <url-pattern>/app/*</url-pattern>
    </servlet-mapping>

</web-app>

以上Java代码分析

**以上无web.xml能正常运行Web,并不是因为Spring的功能,而是Servlet规范的定义。**从servlet3.0后springMVC提供了WebApplicationInitializer接口替代了Web.xml。而JavaConfig的方式替代了springmvc-config.xml。

具体说明如下:

1、AnnotationConfigWebApplicationContext ac = new AnnotationConfigWebApplicationContext()这句Java代码,实现的效果类似于web.xml中的<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>这句。 他们的效果是,加载初始化Spring的Context上下文文件。

2、在上面初始化Spring Context上下文传入参数,在web.xml文件中参数时/WEB-INF/app-context.xml, 该文件定义了具体信息,包括需要扫描的packages。而在Java代码中,使用AppConfig类(该类是Java configuration class)来定义相关信息。

3、在Java中后面的代码实现的效果,既等价于web.xml全局的DispatcherServlet定义,包括servlet-mapping。 而且在这里的Java代码中,DispatcherServlet是我们人工主动new的对象。而传统的web.xml是有容器自动new创建的。

4、通过借用以上Servlet 3.0及以上的规范,即可完全抛弃web.xml文件。 这也为Spring boot零配置打下了基础。

tomcat如何加载的

以上MyWebApplicationInitializer类,tomcat如何找到这个类,如何调用它的?。

**可能1:**由于MyWebApplicationInitializer实现了WebApplicationInitializer接口,tomcat可能通过该接口找到实现类。 但是这里的问题是WebApplicationInitializer接口是Spring的,它不是tomcat的,也不是容器规范。所以该接口tomcat是无法知道的,无法认识,也无法调用。

**可能2:**一种特殊规范,既SPI=service privider interface。这时Java本身的一个规范。 在Servlet 3.0规范后,利用了该SPI规范,实现无web.xml。既在jar包的META-INF/services/目录里同时创建一个以服务接口命名的文件(本以上例子中在spring-web-5.2.2.RELEASE.jar中),当容器装载这个jar模块时,就能通过这个规定的目录和文件,找到对应的类(这里是接口)。这时tomcat才识别到了Spring的WebApplicationInitializer接口,然后再通过反射机制找到所有实现类,最后for循环实现类,逐个进行new实例化并调用接口中的onStartup()方法,同时容器将自身Servlet的Context作为入参传入。 这就是tomcat能自动找到这个类的机制。

二、SPI机制

关于SPI,先看一个之前使用数据库,需要DriverManager获取DB连接之前,我们总是需要显示

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值