1.什么是springboot?
是简化Spring应用开发的一个框架;整个Spring技术栈的一个大整合;J2EE开发的一站式解决方案;
2.springboot入门
1)创建一个maven的工程(jar),导入依赖:
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.1.RELEASE</version> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies>
2)新建主程序,用来启动springboot:
@SpringBootApplication // @SpringBootApplication 来标注一个主程序类,说明这是一个Spring Boot应用 public class Test { public static void main(String[] args) { SpringApplication.run(Test.class,args);//启动springboot } }
3)在主程序的同包下编写一个controller类,进行测试:
@RestController public class MyController { @RequestMapping("/get") public String get(){ return "hello world!"; } }
4)运行主程序。启动成功后会在控制台输入
5)在浏览器测试。在浏览器输入localhost:8080/get.do,即可输出hello world!。此时已经入门了。需要注意的就是第二步的注解@SpringBootApplication必须要写。
6)修改tomcat的端口。在资源目录新建一个application.properties的配置文件,添加下面一行代码,即可修改tomcat的端口,注意这个文件名是固定的:
server.port=8888
7)读取配置文件的信息
我们可以在application.properties中定义自己的配置,然后来读取
(1)在application.properties中添加:
url=http://www.baidu.com
(2)在controller类中添加获取配置的方法
@Autowired private Environment env; //包:import org.springframework.core.env.Environment; @RequestMapping("getUrl") public String getUrl(){ return env.getProperty("url"); }
启动springboot,在浏览器输入http://localhost:8080/getUrl 就会在浏览器显示http://www.baidu.com。
8)热部署(不常用)
当修改程序后,不需要重启springboot,就可以更新。添加以下依赖,那么热部署就可以实现了。
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> </dependency>
9)注解深究
(1)打开SpringBoootApplication注解的类,可用看到一些注解:
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan
@SpringBootConfiguration:是Spring Boot的配置类;标注在某个类上,表示这是一个Spring Boot的配置类。
@EnableAutoConfiguration:开启允许自动配置。这样spring会帮我们自动配置。
@ComponentScan:完成包扫描,是扫描启动类所在的包以及下面的包。
(2)进入@EnableAutoConfiguration类,有如下部分注解:
@AutoConfigurationPackage @Import({EnableAutoConfigurationImportSelector.class}) public @interface EnableAutoConfiguration {
@AutoConfigurationPackage:自动配置包
@Import(AutoConfigurationPackages.Registrar.class):是Spring的底层注解@Import,给容器中导入一个组件;导入的组件由AutoConfigurationPackages.Registrar.class将主配置类(@SpringBootApplication标注的类)的所在包及下面所有子包里面的所有组件扫描到Spring容器。
(3)给容器中导入组件
EnableAutoConfigurationImportSelector:它是导入哪些组件的选择器,将所有需要导入的组件以全类名的方式返回,这些组件就会被添加到容器中。它会给容器中导入非常多的自动配置类(xxxAutoConfiguration)。就是给容器中导入这个场景需要的所有组件,并配置好这些组件。
Spring Boot在启动的时候从类路径下的META-INF/spring.factories中获取EnableAutoConfiguration指定的值,将这些值作为自动配置类导入到容器中,自动配置类就生效,帮我们进行自动配置工作。
10)不使用spring-boot-starter-parent
如果需要使用自己的parent,那么就需要对依赖进行管理,添加如下代码到pom.xml:
<dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>2.0.4</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
此时就不需要继承spring-boot-starter-parent了,但还有一些需要配置,配置java的版本:
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.1</version> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin>
至于格式编码,这里是使用maven创建的,需要配置,如果是按照下面的快速方法创建,就不需要配置:
<properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> </properties>
3.使用Spring Initializer快速创建springboot项目
新建一个项目,选择spring initializer来创建:
点击下一步,填写项目组和项目名称,再点击下一步,根据需要选择需要的组件,然后完成即可。这里就选择spring web。
创建成功后会发现它已经帮我们创建好了主程序代码,我们只需要在里面进行其他的开发即可。
1)定制banner
springboot启动时会打印一个banner,就是spring的艺术字,这个是可以自定义的。在资源目录下创建一个banner.txt,在里面写入的文本就会在项目启动的时候打印出来。
A.若设置艺术字,可以到下面的网站去生成艺术字,然后复制到txt文件中即可。网址:
http://www.network-science.de/ascii/ http://www.kammerl.de/ascii/AsciiSignature.php http://www.patorjk.com/software/taag
B.不过这个banner也是可以设置关闭的,修改mian方法:
public static void main(String[] args) { SpringApplicationBuilder builder=new SpringApplicationBuilder(DemoApplication.class); builder.bannerMode(Banner.Mode.OFF).run(args); // SpringApplication.run(DemoApplication.class, args); }
C.若要显示SpringBoot的版本信息,则可以在里面添加下面的代码
${spring-boot.version}
${spring-boot.formatted-version}
第二行是对第一行进行格式化后显示的版本信息,如图
2)tomcat常规配置
在applicatopn.properties中加:
#配置项目的端口号 server.port=8081 #配置项目出错时跳转的页面 server.error.path=/error #配置session的生效时间,30m表示30分钟 server.servlet.session.timeout=30m #配置项目的名称,配置后需在访问路径中加项目名称,若不配置则默认是/ server.servlet.context-path=/demo #配置tomcat的编码 server.tomcat.uri-encoding=UTF-8 #配置tomcat的最大线程数 server.tomcat.max-connections=1000 #配置tomcat运行日志和临时文件的目录 server.tomcat.basedir=/home/tmp
对于applicatopn.properties配置文件,可以存放在四个位置,分别是项目的根目录下的config文件夹中、项目根目录下、资源目录的config文件夹中、资源目录下。springboot的加载优先级是:上面四个位置依次从高到低,然后加载到Spring Environment中。yml的优先级同上。
3)jetty配置
Jetty 是一个开源的servlet容器,它为基于Java的web容器,例如为JSP和servlet提供运行环境。使用和tomcat类似,这里就去除tomcat,添加jetty进行配置:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <!--去除默认的tomcat,添加jetty依赖--> <exclusions> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jetty</artifactId> </dependency>
undertow是红帽公司开源的java服务器,配置和jetty一样,在此略。
4.Spring Boot的配置文件
虽然springboot已经帮我们写好了很多的配置,但是有些配置需要使用我们自己的,就可以进行配置。springboot使用全局的配置文件。文件名是固定的,为application.properties或application.yml。两者的功能是类似的,只是内容的格式不一样,但是properties 的优先级要高于yml。
yml原名叫yaml,现在简称为yml。使用yml的方式文件名必须是application.yml,properties的形式在这里不介绍了。对于properties的文件,要转换成yml文件,需要把"."变成树形结构
4.1yml内容形式
(1)k: v。键值对的形式,中间必须有空格。也可以使用缩进的方式控制层级关系,清楚明了,大小写敏感。
server: port: 8888
(2)给(对象、map)变量赋值。字符串不需要加双引号:
person: name: 张三 age: 20
(3)也可以使用行内式,如下:
person: {name: 张三,age: 20}
4.2将数据注入bean
@Component @ConfigurationProperties(prefix = "person") public class Test { private String name; private int age; }
@ConfigurationProperties 表示 告诉 SpringBoot 将本类中的所有属性和配置文件中相关的配置进行绑定。prefix = "person" 表示 将配置文件中 key 为 person的下面所有的属性与本类属性进行一一映射注入值,如果配置文件中不存在 "person" 的 key,则不会为 POJO 注入值,属性值仍然为默认值。
4.3获取属性值
@Resource private PersonTest personTest; @Test public void test1() { System.out.println(personTest); }
4.4其他类型赋值
(1)给数组(list,set)赋值
animal: - dog - cat - pig
也可以使用行内式,如下:
animal: [cat,dog,pig]
4.5读取配置文件内容示例
application.yml的内容如下:
# 项目相关配置
student:
# 项目名称
name: Student
#文件路径
path: c:/student
创建项目配置的实体类,如下:
package com.kanq.exchange.domain; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; /* * 读取项目相关配置 * */ @Component @ConfigurationProperties(prefix = "student") public class SystemConfig { //项目名称 private String name; //文件路径 private static String path; public String getName() { return name; } public void setName(String name) { this.name = name; } public static String getPath() { return path; } public void setPath(String path) { this.path = path; } //返回文件路径 public static String getFilePath() { return getPath(); } }
获取路径:
package com.kanq.exchange.action; import com.kanq.exchange.domain.SystemConfig; import org.springframework.stereotype.Controller; @Controller public class StuController { //获取路径 public void getPath(){ String path=SystemConfig.getFilePath(); } }
5.使用配置文件给对象注入值
新建一个springboot的工程,使用spring initializer创建。
1)配置文件application.yml:
person: name: 张三 age: 20 map: key: v1 brith: 2019/5/5 list: - name: 测试1 - name: 测试2 dog: name: 小三 age: 1
2)实体类
类Dog:
public class Dog { private String name; private int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "Dog{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
类Student:
public class Student { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Student{" + "name='" + name + '\'' + '}'; } }
类Person:
@Component @ConfigurationProperties(prefix = "person") public class Person { private String name; private int gae; private Date brith; private Map map; private List<Student> list; private Dog dog; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getGae() { return gae; } public void setGae(int gae) { this.gae = gae; } public Date getBrith() { return brith; } public void setBrith(Date brith) { this.brith = brith; } public Map getMap() { return map; } public void setMap(Map map) { this.map = map; } public List<Student> getList() { return list; } public void setList(List<Student> list) { this.list = list; } public Dog getDog() { return dog; } public void setDog(Dog dog) { this.dog = dog; } @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", gae=" + gae + ", brith=" + brith + ", map=" + map + ", list=" + list + ", dog=" + dog + '}'; } }
3)导入配置文件处理器依赖,配置文件进行绑定就会有提示
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
4)处理乱码。properties配置文件在idea中可能会乱码,需要进行处理:
5)测试。在测试类中修改:
@Autowired private Person person; @Test public void contextLoads() { System.out.println(person); }
运行测试类,会在控制台打印person的内容。
6)配置文件的占位符
(1)随机数
${random.int},${random.value}。。。
(2)指定默认值。占位符获取之前配置的值,如果没有可以使用:默认值。下面是用.properties的配置演示的:
person.last‐name=张三${random.uuid} person.age=${random.int} person.birth=2017/12/15 person.map.k1=v1 person.map.k2=14 person.list=a,b,c person.dog.name=${person.hello:hello}_dog person.dog.age=15
6.@Bean的使用
springboot通常使用@Bean来注入对象,在方法上加这个注解,把此方法的返回值添加到spring容器中,也可以在这个类中把其他类交给spring管理。
@Configuration public class Hello { @Bean public Hello getHello(){ return new Hello(); } public void say(){ System.out.println("hello"); } }
这样也可以把Hello这个对象交给spring来管理,也是通过@Autowired来获取。
7.profile
不同的时期配置可能不同,可以在配置文件中定义不同的环境来做不同的配置。
7.1使用properties方式:
1)创建测试的环境配置文件application-dev.properties,以配置端口号为例:
server.port=8888
2)创建debug的环境配置文件application-debug.properties
server.port=9999
3)创建配置文件application.properties,指定激活的配置文件,这里激活dev的环境:
spring.profiles.active=dev
7.2使用yml方式:
yml方式是在同一个配置文件中编写多个环境块,用---分隔
#在一个文件中进行配置 #指定激活哪个配置 spring: profiles: active: bug --- server: port: 6666 #指定环境的名字 spring: profiles: test --- server: port: 5555 #指定环境的名字 spring: profiles: bug
也可以通过命令行的方式来指定运行那个环境,运行方式如下:
--spring.profiles.active=test
点击ok,然后再运行,会发现运行的是test的环境,而不是配置文件中的bug,原因是在外部的配置大于在内部的配置。
8.日志
1)日志框架
市面上的日志框架:JUL、JCL、Jboss-logging、logback、log4j、log4j2、slf4j....
日志门面(日志的抽象层)API | 日志实现 |
JCL、SLF4j、Jboss-logging |
Log4j、JUL、Log4j2、Logback |
SpringBoot的底层是Spring框架,Spring框架默认是用JCL;SpringBoot选用 SLF4j和logback。
2)SLF4j的使用
在测试类中新建一个方法,用来测试日志。(这里默认已经创建了springboot的工程)
@Test public void logTest(){ Logger logger = LoggerFactory.getLogger(SpringbootDemoApplicationTests.class); logger.trace("trace"); logger.debug("debug"); logger.info("info"); logger.warn("warn"); logger.error("error"); }
使用properties方式配置日志级别,在application.properties加下面一行代码,运行测试类发现只打印warn以上级别的信息:
#要配置到包,指定某一个包的日志级别
logging.level.com=warn
使用yml方式配置日志级别,在application.yml加下面的代码,运行测试类发现只打印trace以上级别的信息:
spring: profiles: active: pro --- logging: level: {com: trace} spring: profiles: pro --- logging: level: {com: error} spring: profiles: release
其他问题:使用不同的框架,就会产生不同的日志框架,让系统中所有的日志都统一到slf4j? 在api和实现层的中间添加不同的适配层即可,具体来说,先将系统中其他日志框架先排除出去,再用中间包来替换原有的日志框架,最后导入slf4j其他的实现。
3)日志输出到文件
path:后接目录,会把日志文件放在项目所在的目录的根目录下,默认文件名是spring.log。
file:后接文件名,会把日志文件放在项目下。如果两个同时使用,则file生效。
logging:
level: {com: trace}
path: abc/log
这里日志文件存放位置是:springboot-demo1\abc\log\spring.log。其中springboot-demo1是项目名。
logging:
level: {com: trace}
file: log.log
这里日志文件存放位置是:springboot-demo1\log.log。其中springboot-demo1是项目名。
4)为日志文件指定配置
如果有自己的配置文件,就引入进来,但是必须以logback-spring.xml为名或logback.xml。
如果名字是logback.xml,那么它直接就被日志框架识别了;如果名字是logback-spring.xml,那么日志框架就不直接加载日志的配置项,由SpringBoot解析日志配置,可以使用SpringBoot的高级Profile功能。
新建一个配置文件,名为logback.xml,测试:
<?xml version="1.0" encoding="UTF-8"?> <!-- scan:当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true。 scanPeriod:设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒当scan为true时,此属性生效。默认的时间间隔为1分钟。 debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。 --> <configuration scan="false" scanPeriod="60 seconds" debug="false"> <!-- 定义日志的根目录 --> <property name="LOG_HOME" value="/app/log" /> <!-- 定义日志文件名称 --> <property name="appName" value="atguigu-springboot"></property> <!-- ch.qos.logback.core.ConsoleAppender 表示控制台输出 --> <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender"> <!-- 日志输出格式: %d表示日期时间, %thread表示线程名, %-5level:级别从左显示5个字符宽度 %logger{50} 表示logger名字最长50个字符,否则按照句点分割。 %msg:日志消息, %n是换行符 --> <layout class="ch.qos.logback.classic.PatternLayout"> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern> </layout> </appender> <!-- 滚动记录文件,先将日志记录到指定文件,当符合某个条件时,将日志记录到其他文件 --> <appender name="appLogAppender" class="ch.qos.logback.core.rolling.RollingFileAppender"> <!-- 指定日志文件的名称 --> <file>${LOG_HOME}/${appName}.log</file> <!-- 当发生滚动时,决定 RollingFileAppender 的行为,涉及文件移动和重命名 TimeBasedRollingPolicy: 最常用的滚动策略,它根据时间来制定滚动策略,既负责滚动也负责出发滚动。 --> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <!-- 滚动时产生的文件的存放位置及文件名称 %d{yyyy-MM-dd}:按天进行日志滚动 %i:当文件大小超过maxFileSize时,按照i进行文件滚动 --> <fileNamePattern>${LOG_HOME}/${appName}-%d{yyyy-MM-dd}-%i.log</fileNamePattern> <!-- 可选节点,控制保留的归档文件的最大数量,超出数量就删除旧文件。假设设置每天滚动, 且maxHistory是365,则只保存最近365天的文件,删除之前的旧文件。注意,删除旧文件是, 那些为了归档而创建的目录也会被删除。 --> <MaxHistory>365</MaxHistory> <!-- 当日志文件超过maxFileSize指定的大小是,根据上面提到的%i进行日志文件滚动 注意此处配置SizeBasedTriggeringPolicy是无法实现按文件大小进行滚动的,必须配置timeBasedFileNamingAndTriggeringPolicy --> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <maxFileSize>100MB</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> </rollingPolicy> <!-- 日志输出格式: --> <layout class="ch.qos.logback.classic.PatternLayout"> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [ %thread ] - [ %-5level ] [ %logger{50} : %line ] - %msg%n</pattern> </layout> </appender> <!-- logger主要用于存放日志对象,也可以定义日志类型、级别 name:表示匹配的logger类型前缀,也就是包的前半部分 level:要记录的日志级别,包括 TRACE < DEBUG < INFO < WARN < ERROR additivity:作用在于children-logger是否使用 rootLogger配置的appender进行输出, false:表示只用当前logger的appender-ref,true: 表示当前logger的appender-ref和rootLogger的appender-ref都有效 --> <!-- hibernate logger --> <logger name="com" level="debug" /> <!-- Spring framework logger --> <logger name="org.springframework" level="debug" additivity="false"></logger> <!-- root与logger是父子关系,没有特别定义则默认为root,任何一个类只会和一个logger对应, 要么是定义的logger,要么是root,判断的关键在于找到这个logger,然后判断这个logger的appender和level。 --> <root level="info"> <appender-ref ref="stdout" /> <appender-ref ref="appLogAppender" /> </root> </configuration>
将文件名修改为logback-spring.xml,添加两行代码,添加多个配置,不同的配置在不同的环境下生效:
<springProfile name="staging"> <!--指定配置在某个环境下生效--> ..... </springProfile>
配置举例:
<appender name="stdout" class="ch.qos.logback.core.ConsoleAppender"> <layout class="ch.qos.logback.classic.PatternLayout"> <springProfile name="dev"> <pattern>%d{yyyy‐MM‐dd HH:mm:ss.SSS} ‐‐‐‐> [%thread] ‐‐‐> %‐5level %logger{50} ‐ %msg%n</pattern> </springProfile> <springProfile name="!dev"> <pattern>%d{yyyy‐MM‐dd HH:mm:ss.SSS} ==== [%thread] ==== %‐5level %logger{50} ‐ %msg%n</pattern> </springProfile> </layout> </appender>
指定级别,然后测试:
<root level="info"> <appender-ref ref="stdout" /> <appender-ref ref="appLogAppender" /> </root>
只要使用springboot依赖了不被springboot管理的框架,一定要排除日志依赖,同时引入对应的适配层。
9.SpringBoot与SpringMvc的区别
SrpingBoot是一个快速开发的框架,原理是利用maven依赖整合第三方框架;去除xml配置,采用注解的形式;内置了很多的容器(如tomcat服务器)。
SpringMvc是spring的一个框架,在SpringBoot中使用SPringMvc。
10.SpringBoot其他知识
1)SpringBoot启动流程
第一步:new SpringApplication
第二步:调用run方法
2)WebApplicationType的三种
第一种:NONE,不嵌入web服务器,通过外部tomcat服务器运行
第二种:SERVLET,需要使用web服务器运行
第三种:REACTIVE,使用响应式web启动