学了将近两个月的spring后,最近又在学习springBoot,发现springBoot可真是太好用了啊,于是就把自己的理解以及收集的资料记录下来,写了这个博客,来帮助大家学习如何使用springBoot。
其实作为一个spring的框架,spring的底层也是IOC和DI机制,至于是如何具体实现的,我下面会做一下说明(下面很多都是我从网上的资料参考的,如果有不全或错误的地方,希望大家能给予补充和修改)
使用spring的第一步当然是导入jar包了,不过和spring导入jar包的方式是完全不同的,spring需要一个一个的导入jia包,springBoot只需要导入一个依赖,就能自动加载所有相关的包了,下面我们先来看看写一个helloworld的pom.xml吧。
<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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.yc.springBoot8</groupId>
<artifactId>testSpringBoot8</artifactId>
<packaging>war</packaging>
<version>0.0.1-SNAPSHOT</version>
<name>testSpringBoot8 Maven Webapp</name>
<url>http://maven.apache.org</url>
<properties>
<java.version>1.8</java.version>
</properties>
<!-- 官方配置好的一些信息,可以自己配 -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.4.RELEASE</version>
</parent>
<!-- web项目的依赖 -->
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
<build>
<finalName>testSpringBoot8</finalName>
</build>
</project>
其中,<parent>里面的是一些官方包装好的配置,包含以下这些内容:
1、使用java6编译级别
2、使用utf-8编码
3、实现了通用的测试框架 (JUnit, Hamcrest, Mockito).
4、智能资源过滤
5、智能的插件配置(exec plugin, surefire, Git commit ID, shade).
作为一个初学者,完全可以使用官方给的这些配置,如果你要不用也是可以自己配的。我唯一改的是java的编译版本,因为我用的是jdk8,只要添加一个<java.vwesion>就行了。
下面我们就来看看导入了一个web包依赖后,到底导入了哪些jar包吧:
点开这个spring-boot-starter-web后我们可以看到里面没有任何包,只有一些配置信息,打开里面的pom.xml,里面的内容是:
<?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>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starters</artifactId>
<version>1.5.4.RELEASE</version>
</parent>
<artifactId>spring-boot-starter-web</artifactId>
<name>Spring Boot Web Starter</name>
<description>Starter for building web, including RESTful, applications using Spring
MVC. Uses Tomcat as the default embedded container</description>
<url>http://projects.spring.io/spring-boot/</url>
<organization>
<name>Pivotal Software, Inc.</name>
<url>http://www.spring.io</url>
</organization>
<properties>
<main.basedir>${basedir}/../..</main.basedir>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
</dependency>
</dependencies>
</project>
这个pom.xml里面就有很多jar包的配置,没错,这些都是会自动导入我们项目的jar包,springBoot就是通过这样的方式来自动导入jar包的。
导完包后就要开始写代码了。
任何一个Spring Boot项目,都会有一个启动类作为主程序入口,我写的启动类是:Application.class,启动类上要有@SpringBootApplication注解。
package com.yc;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
//启动类
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
@SpringBootApplication注解主要包含以下三个注解
其中最重要的是@EnableAutoConfiguration,
@EnableAutoConfiguration是借助@Import的帮助,将所有符合自动配置条件的bean定义加载到IoC容器
底层:从classpath中搜寻所有的META-INF/spring.factories配置文件,并将其中org.springframework.boot.autoconfigure.EnableutoConfiguration对应的配置项通过反射(Java Refletion)实例化为对应的标注了@Configuration的JavaConfig形式的IOC容器配置类,然后汇总为一个并加载到IOC容器。
@SpringBootConfiguration(内部为@Configuration):标注当前类是配置类,并会将当前类内声明的一个或多个以@Bean注解标记的方法的实例纳入到srring容器中,并且实例名就是方法名。
底层:当读取到@Configuration以后,就会自动的读取这个类里面的方法,如果发现这个方法上面有@Bean注解的话,就取到这个方法的方法名,根据方法名激活这个方法,得到一个返回值,然后将方法名作为id,返回值作为值,生成一个Bean存入Bean容器中,IOC完成。
@ComponentScan告诉Spring哪个packages的用注解的类会被spring自动扫描并且装入bean容器中,一般将该启动类放到根包路径下,因为它会默认扫描该包路径下的子包。所以包的结构最好写成这样:
SpringApplication的run方法的主要流程大体可以归纳如下:(这些都是我搬运来的,有兴趣的了解一下,没兴趣的直接跳过,与使用SpringBoot无关)
1、创建和配置环境
根据初始化的配置创建environment的类型,包括配置要使用的PropertySource以及Profile。
启动监听器的environmentPrepared方法,调用所有监听器来监听。
如果SpringApplication的showBanner属性被设置为true,则打印banner。
2、创建ApplicationContext
根据用户是否明确设置了applicationContextClass类型以及初始化阶段的推断结果,决定该为当前SpringBoot应用创建什么类型的ApplicationContext并创建完成,然后根据条件决定是否添加ShutdownHook,决定是否使用自定义的BeanNameGenerator,决定是否使用自定义的ResourceLoader,当然,最重要的,将之前准备好的Environment设置给创建好的ApplicationContext使用。
3、加载资源,就是在初始化过程中source包含的类
4、context 重新刷新
调用ApplicationContext的refresh()方法,完成IOC容器可用的最后一道工序。
5、配置spring boot特有的单例bean 如commandline相关
6、监听器实现所有finished操作
遍历执行SpringApplicationRunListener的finished()方法。
至此,Spring boot的启动过程就完成了。
这一系列的步骤都在SpringApplication.class的源码中有对应的代码。
如果你只是想学一下简单配置的话无视上面那段吧。
在你运行了Application.class以后,一个spring容器(Application Context)就建立好了,在建立容器的同时,这个类也偷偷摸摸干了一些其他的事,比如它会扫描当前类上的依赖,然后它就发现了spring-webmvc在类路径上(问题来了,这个东东是哪来的?其实它是我们在pom.xml中配置的spring-boot-starter-web传递引入的,仔细看的同学一定会发现上面pom.xml中有哦),因此Spring Boot判断出这个项目是一个web应用,并启动一个内嵌的Servlet容器(默认是Tomcat)用于处理HTTP请求。
如果你之前学过sprng mvc的话,就应该知道我们应该建一个controller来做http请求的分发的处理工作,没学过也无所谓,反正我下面会讲。。。
package com.yc.controllers;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
@RequestMapping("/hello")
public String hello(){
return "spring boot, hello world!";
}
}
上面的HelloController就是一个controller了,它的作用就是处理url为hello的http请求并将”spring boot, hello world!”显示在网页上了。
一个controller中一般有以下注解
@Controller:表示这个类是一个用来处理http请求的controller,只能作用在类上
@RequestMapping:配置url映射,既可以作用在类上也可以作用在方法上面,类级注释的url会附加到方法级注释的url上
@PathVariable :其用来获取url 中的动态参数。
@RequestParam:将请求参数绑定到控制器的方法参数
@RequestBody:将HTTP请求体的值绑定到方法参数上,一般用来将请求体中的JSON字符串绑定到相应的bean上
@ResponseBody:这个注释可以放在方法上面,并指示返回类型应该直接写入HTTP响应体,一般用来返回json数据和xml,一旦使用了这个注解,就不会再走视图处理器,而是直接将数据写入到输入流中。
@RestController:@RequestBody和@Controller结合体
现在@Controller已经很少使用了,一般都是使用@RestController,前台将json数据传过来,controller接受到数据以后,通过@RequestBody注解将数据绑定到Bean或者方法参数上,处理数据后,通过@ResponseBody再将处理的结果转成json数据传给后台,以达到解耦的目的。
当然,虽然大多使用的是@RestController,但是@Controller也有它特有的作用,一个类使用@Controller注解时,并且这个类中方法没有@ResponseBody注解时,就会有不同大返回类型,我简单点的介绍两种常用的。如果返回的是一个”String”类型,那么就会通过视图解析器,跳转到一个jsp或者html或者其他界面上,跳转到哪由配置决定(视图解析器和它的配置下面会讲)。如果是返回的是”ModelAndView”类型的话,ModelAndView主要有两个方法,setViewName()方法可以设置返回的视图的名称,addObject()可以设置需要返回的值。至于其它的返回值想了解的可以看spring的官方文档我就不一一解释了。如果这个这个方法上面有了@ResponseBody注解的话,那就不好意思了,不管返回什么,都会被直接写入输入流了。
如果你完成了上面几步,只要先运行Application.java,并在浏览器里输入http://localhost:8080/hello,你就会在屏幕看到”spring boot, hello world!”,controller会接受到hello这个http请求,然后将返回值”spring boot, hello world!”直接写入了输出流,所以才会直接显示在屏幕上。大功告成,一个hellowrld就写完了。
今天就写到这了,至于如何整合mybatis,数据库连接池等一些东西,过两天再写。