02 SpringBoot核心

原理简介

随着JavaEE的不断壮大,Java的开发变得越来越复杂,这里的复杂,指的是写代码的方式。
配置文件一大堆,各种xml,properties。与其他项目进行整合集成的时候,也越来越不方便。

这个时候SpringBoot的出现,为解决上述问题提供了一个方案,可以说,是SpringBoot挽救了Java在服务端开发的陌路。

但是SpringBoot本身,是没有引入新技术的,其主要是基于Spring4中的条件注解特性,将原先需要编程人员手动操作的代码,统一集成到了内部,并且提供外部配置,同时兼顾了灵活性与简单性。

系统条件注解工具

条件注解 说明
@ConditionalOnBean 指定Bean是否存在
@ConditionalOnClass 类路径下存在指定类
@ConditionalOnCloudPlatform 是否是分布式平台
@ConditionalOnExpression 由SpEL表达式决定
@ConditionalOnJava JVM版本
@ConditionalOnJndi 在JNDI存在的条件下查找指定的位置
@ConditionalOnMissingBean 类路径缺失Bean的情况下
@ConditionalOnMissingClass 类路径缺失Class的情况下
@ConditionalOnNotWebApplication 非web环境
@ConditionalOnProperty 指定属性是否有指定的值
@ConditionalOnResource 类路径是否有指定的值
@ConditionalOnSingleCandidate 指定Bean在容器中只有一个,
或者指定首选Bean
@ConditionalOnWebApplication 当前是web环境

概述

Spring Boot解决了什么问题

Java开发越来越笨重

  • 配置多
  • 部署复杂
  • 第三方集成复杂

Spring Boot 核心功能

  • Spring Boot可以以jar包的形式独立运行,运行一个Spring Boot项目只需要通过java -jar xx.jar 来运行
  • Spring Boot可以选择内嵌Tomcat、Jetty、Undertow,无需以war包形式部署
  • Spring Boot提供starter pom来简化Maven的依赖加载
  • Spring Boot提供基于http、ssh、telnet对运行时项目的监控
  • 无代码生成和xml配置

优缺点

优点

  • 快速构建项目
  • 对主流开发框架无缝集成
  • 可独立运行项目,无需外部依赖Servlet容器
  • 运行时应用监控
  • 极大提高开发、部署效率
  • 与云计算天然集成

缺点

  • 学习资料少
  • 如果Spring,特别是Spring4基础不扎实,对Spring Boot原理会弄不清

快速构建

Spring Boot可以使用Maven和Gradle作为项目构建
部署形式可以是jar或war
JDK最低要求1.6
支持以Groovy语言开发

使用IDEA,可以很自动化的构建一个SpringBoot项目,但其本质上还是一个Maven项目

如果网络有问题的话,可以手动构建

<?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>
<groupId>org.zln.learning.spboot</groupId>
	<artifactId>spboot-demo01</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>
<name>spboot-demo01</name>
	<description>Demo project for Spring Boot</description>
<!--Spring Boot项目必须添加这个父级依赖-->
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>1.5.3.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<java.version>1.8</java.version>
	</properties>
<!--添加starter和其他需要的依赖-->
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>
<build>
		<plugins>
			<!--添加Spring Boot的编译插件-->
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>
</project>
	

上面的pom,添加的依赖并不多,但是实际上依赖很多

  • HelloWorld
package org.zln.learning.spboot;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@SpringBootApplication
@RestController
public class SpbootDemo01Application {
@RequestMapping("/")
    String index() {
        return "Hello Spring Boot";
    }
public static void main(String[] args) {
        SpringApplication.run(SpbootDemo01Application.class, args);
    }
}

代码说明

  • @SpringBootApplication
    ​ Spring Boot的核心注解,主要目的就是开启自动配置

SpringBoot基本配置

@SpringBootApplication

Spring Boot 通常有一个名为 *Application 的入口类,

入口类中的Main方法启动整个Spring Boot项目

@SpringBootApplication是SpringBoot的核心注解,从他的源码中可以看到,

它有一个@EnableAutoConfiguration注解;

@EnableAutoConfiguration让SpringBoot根据类路径中的jar,

为当前项目进行自动配置

如:添加了spring-boot-starter-web依赖,则自动添加Tomcat和Spring MVC的依赖,

然后Spring Boot会对Tomcat和SpringMVC进行自动配置

Spring Boot自动扫描与@SpringBootApplication所在的同级包及其下级包的Bean

建议入口类位置放在 groupId+arctifactId组合的包名下

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
		@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
		@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {

	/**
	 * Exclude specific auto-configuration classes such that they will never be applied.
	 * @return the classes to exclude
	 */
	@AliasFor(annotation = EnableAutoConfiguration.class, attribute = "exclude")
	Class<?>[] exclude() default {};

	/**
	 * Exclude specific auto-configuration class names such that they will never be
	 * applied.
	 * @return the class names to exclude
	 * @since 1.3.0
	 */
	@AliasFor(annotation = EnableAutoConfiguration.class, attribute = "excludeName")
	String[] excludeName() default {};

	/**
	 * Base packages to scan for annotated components. Use {@link #scanBasePackageClasses}
	 * for a type-safe alternative to String-based package names.
	 * @return base packages to scan
	 * @since 1.3.0
	 */
	@AliasFor(annotation = ComponentScan.class, attribute = "basePackages")
	String[] scanBasePackages() default {};

	/**
	 * Type-safe alternative to {@link #scanBasePackages} for specifying the packages to
	 * scan for annotated components. The package of each class specified will be scanned.
	 * <p>
	 * Consider creating a special no-op marker class or interface in each package that
	 * serves no purpose other than being referenced by this attribute.
	 * @return base packages to scan
	 * @since 1.3.0
	 */
	@AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses")
	Class<?>[] scanBasePackageClasses() default {};

}

关闭特定的自动注解

@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})

定制Banner

Banner指SpringBoot启动时候的默认图案

我们在resources下新建一个
banner.txt 文件
打开网址 http://patorjk.com/software/taag
输入我们需要的字符,将生成结果粘贴到 banner.txt 文件中即可

关闭 Banner

SpringApplication application = new SpringApplication(SpbootDemo01Application.class);
application.setBannerMode(Banner.Mode.OFF);
application.run(args);

Spring Boot 配置文件

Spring Boot
使用一个全局的配置文件,放在 src/main/resources目录或类路径的config下
名字叫做 application.properties或application.yml
全局配置文件的作用是对一些默认配置进行修改

基本的全局配置

server.port=9090
server.context-path=/helloworld

如果使用的是yml,则可以

server:
    port: 9090
    contextPath: /helloworld

starter pom

  • 官方
名称 描述
spring-boot-starter 这是Spring Boot的核心启动器,包含了自动配置、日志和YAML
spring-boot-starter-actuator 帮助监控和管理应用
spring-boot-starter-amqp 通过spring-rabbit来支持AMQP协议(Advanced Message Queuing Protocol)
spring-boot-starter-aop 支持面向方面的编程即AOP,包括spring-aop和AspectJ
spring-boot-starter-artemis 通过Apache Artemis支持JMS的API(Java Message Service API)
spring-boot-starter-batch 支持Spring Batch,包括HSQLDB数据库。
spring-boot-starter-cache 支持Spring的Cache抽象。
spring-boot-starter-cloud-connectors 支持Spring Cloud Connectors,简化了在像Cloud Foundry或Heroku这样的云平台上连接服务。
spring-boot-starter-data-elasticsearch 支持ElasticSearch搜索和分析引擎,包括spring-data-elasticsearch。
spring-boot-starter-data-gemfire 支持GemFire分布式数据存储,包括spring-data-gemfire。
spring-boot-starter-data-jpa 支持JPA(Java Persistence API),包括spring-data-jpa、spring-orm、Hibernate。
spring-boot-starter-data-mongodb 支持MongoDB数据,包括spring-data-mongodb。
spring-boot-starter-data-rest 通过spring-data-rest-webmvc,支持通过REST暴露Spring Data数据仓库。
spring-boot-starter-data-solr 支持Apache Solr搜索平台,包括spring-data-solr。
spring-boot-starter-freemarker 支持FreeMarker模板引擎。
spring-boot-starter-groovy-templates 支持Groovy模板引擎。
spring-boot-starter-hateoas 通过spring-hateoas支持基于HATEOAS的RESTful Web服务。
spring-boot-starter-hornetq 通过HornetQ支持JMS。
spring-boot-starter-integration 支持通用的spring-integration模块。
spring-boot-starter-jdbc 支持JDBC数据库。
spring-boot-starter-jersey 支持Jersey RESTful Web服务框架。
spring-boot-starter-jta-atomikos 通过Atomikos支持JTA分布式事务处理。
spring-boot-starter-jta-bitronix 通过Bitronix支持JTA分布式事务处理。
spring-boot-starter-mail 支持javax.mail模块。
spring-boot-starter-mobile 支持spring-mobile。
spring-boot-starter-mustache 支持Mustache模板引擎。
spring-boot-starter-redis 支持Redis键值存储数据库,包括spring-redis。
spring-boot-starter-security 支持spring-security。
spring-boot-starter-social-facebook 支持spring-social-facebook
spring-boot-starter-social-linkedin 支持pring-social-linkedin
spring-boot-starter-social-twitter 支持pring-social-twitter
spring-boot-starter-test 支持常规的测试依赖,包括JUnit、Hamcrest、Mockito以及spring-test模块。
spring-boot-starter-thymeleaf 支持Thymeleaf模板引擎,包括与Spring的集成。
spring-boot-starter-velocity 支持Velocity模板引擎。
spring-boot-starter-web 支持全栈式Web开发,包括Tomcat和spring-webmvc。
spring-boot-starter-websocket 支持WebSocket开发。
spring-boot-starter-ws 支持Spring Web Services。
spring-boot-starter-actuator 增加了面向产品上线相关的功能,比如测量和监控。
spring-boot-starter-remote-shell 增加了远程ssh shell的支持。
spring-boot-starter-jetty 引入了Jetty HTTP引擎(用于替换Tomcat)。
spring-boot-starter-log4j 支持Log4J日志框架。
spring-boot-starter-logging 引入了Spring Boot默认的日志框架Logback。
spring-boot-starter-tomcat 引入了Spring Boot默认的HTTP引擎Tomcat。
spring-boot-starter-undertow 引入了Undertow HTTP引擎(用于替换Tomcat)。
  • 第三方starter pom

当我们需要某方面的技术的时候,先查查有没有对应的starter,如:MyBatis

<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>1.3.0</version>
</dependency>

Spring Boot
提倡无xml配置,但有时候必须用到xml配置,

使用@ImportResource({"classpath:a.xml","classpath:b.xml"})导入即可

外部文件配置

SpringBoot允许使用propertiesyaml文件或者命令行参数作为外部配置

命令行参数

 #!/bin/sh
nohup java -Xms128m -Xmx256m -jar train-basic-0.0.1-SNAPSHOT.jar --spring.profiles.active=A-prod >/dev/null 2>&1 &

--spring.profiles.active=A-prod就是指定了一个外部参数

application.yml中的配置

对于配置在application.yml主配置文件中的参数,可以直接使用@Value()注解进行获取

当然,使用application.properties也是一样的

package org.zln.spb.demo01.web;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @Author 张柳宁
 * @Description
 * @Date Create in 2018/1/31
 * @Modified By:
 */
@RestController
@Slf4j
public class HelloController {

    @Value("${user.k1}")
    private String userK1;

    @RequestMapping("/hello")
    public String hello(){
        log.info(userK1);
        return "Hello ,世界";
    }

}

application.yml内容为

user:
  k1: 张柳宁

类型安全的配置

如果不是application配置文件,而是其他配置文件,那么就需要先指定properties文件的位置

package com.tdk.train.config;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;

/**
 * Created by nbcoolkid on 2017-11-05.
 */
@Component
@PropertySource(value = "classpath:db.properties",encoding = "utf-8")
@ConfigurationProperties(prefix = "mysql")
@Data
public class DbConfBean {
    private String url;
    private String url2;
    private String username;
    private String username2;
    private String password;
    private String password2;
}

将一个properties配置文件与JavaBean关联起来

日志配置

Spring Boot 支持Java UtilLogging、Log4J、Log4J2和LogBack作为日志框架

默认使用LogBack作为日志框架

# 配置日志文件路径
logging.file=logs/spboot-demo01.log
#配置日志级别,格式:logging.level.包名=级别
logging.level.org.springframework.web=DEBUG

如果需要对日志进行详细的配置,则

logging:
  level: info
  config: classpath:logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false" scan="true" scanPeriod="1 seconds">

    <contextName>logback</contextName>
    <property name="log.path" value="./logs/train-basic.log"/>

    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d{HH:mm:ss.SSS} %contextName [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>

    <appender name="file" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${log.path}</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${log.path}.%d{yyyy-MM-dd}.zip</fileNamePattern>
        </rollingPolicy>
        <encoder>
            <pattern>%date %level [%thread] %logger{36} [%file : %line] %msg%n
            </pattern>
        </encoder>
    </appender>

    <root level="info">
        <appender-ref ref="console"/>
        <appender-ref ref="file"/>
    </root>

</configuration>

Profile配置

Profile是Spring用来针对不同的环境提供平不同的配置支持的
全局Profile配置使用 application-{profile}.properties

通过在application.properties中设置spring.profiles.active=dev 来设置活动的Profile

SpringBoot打包出一个可执行jar

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <configuration>
                <mainClass>org.zln.ehcache.Main</mainClass>
            </configuration>
            <executions>
                <execution>
                    <goals>
                        <goal>repackage</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

即是没有这段,默认打出来的jar也是可执行的

Spring Boot运行原理

Spring Boot的自动配置,其原理是Spring 4出现的条件化Bean

三种方式查看当前项目已启用和未启用的自动配置

  • java -jar xx.jar --debug
  • 全局配置文件:debug=true
  • 运行的时候通过IDE为VM添加参数:-Ddebug

SpringBootApplication–>EnableAutoConfiguration
EnableAutoConfiguration–>Import
Import–>EnableAutoConfigurationImportSelector
EnableAutoConfigurationImportSelector–>AutoConfigurationImportSelector

扫描 META-INF/spring.factories 文件

spring-boot-autoconfigure-1.5.3.RELEASE.jar中就有

其中配置的任何一个自动注解配置类,都有条件注解

条件注解 说明
@ConditionalOnBean 当容器中存在指定Bean的条件下
@ConditionalOnClass 当类路径下有指定类的情况下
@ConditionalOnExpression 基于SpEL表达式作为判断条件
@ConditionalOnJava 基于JVM版本作为判断条件
@ConditionalOnJndi 在JNDI存在的条件下查找指定位置
@ConditionalOnMissingBean 当容器中不存在指定Bean的条件下
@ConditionalOnMissingClass 当类路径没有指定类的条件下
@ConditionalOnNotWebApplication 当前项目不是Web项目的条件下
@ConditionalOnProperty 指定属性是否有指定的值
@ConditionalOnResource 类路径是否有指定的值
@ConditionalOnSingleCandidate 当指定Bean在容器中只有一个, 或者虽然有多个但是指定首选的Bean
@ConditionalOnWebApplication 当前项目是Web项目的条件下

自定义 starter pom

当类存在的时候,自动配置这个Bean,并可将Bean的属性在application.properties文件中进行配置

  • pom
<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>
    <groupId>com.pzr</groupId>
    <artifactId>spring-boot-starter-pzrhello</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <!-- 引用依赖的父包 -->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.1.RELEASE</version>
    </parent>
    <!-- 依赖包 -->
    <dependencies>
        <!-- spring boot 自动配置需要的包 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-autoconfigure</artifactId>
        </dependency>
        <!-- spring boot需要的包 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
</dependencies>
</project>

  • 添加属性配置类
package com.pzr.spring_boot_stater_pzrhello;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
 * 属性配置类
 * @author pzr
 *
 */
@ConfigurationProperties(prefix="hello")
public class HelloServiceProperties {
    private static final String MSG = "world";
    private String msg = MSG;
    public String getMsg() {
        return msg;
    }
    public void setMsg(String msg) {
        this.msg = msg;
    }
}

代码说明:

使用@ConfigurationProperties注解来设置前缀,

在application.properties中通过hello.msg=来设置,若不设置,默认为hello.msg=world。

  • 添加判断依据类
package com.pzr.spring_boot_stater_pzrhello;
/**
 * 判断依据类
 * @author pzr
 *
 */
public class HelloService {
    private String msg;
	public String sayHello(){
        return "Hello "+msg;
    }
	public String getMsg() {
        return msg;
    }
	public void setMsg(String msg) {
        this.msg = msg;
    };
}
  • 添加自动配置类
package com.pzr.spring_boot_stater_pzrhello;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
 * 自动配置类
 * @author pzr
 *
 */
@Configuration
@EnableConfigurationProperties(HelloServiceProperties.class)
@ConditionalOnClass(HelloService.class)
@ConditionalOnProperty(prefix="hello",value="enabled",matchIfMissing=true)
public class HelloServiceAutoConfiguration {
    @Autowired
    private HelloServiceProperties helloServiceProperties;
	@Bean
    public HelloService helloService(){
        HelloService helloService = new HelloService();
        helloService.setMsg(helloServiceProperties.getMsg());
        return helloService;
    }
}

将HelloServiceAutoConfiguration配置到 src/main/resources/META-INF/spring.properties

org.springframework.boot.autoconfigure.EnableAutoConfiguration=
com.pzr.spring_boot_stater_pzrhello.HelloServiceAutoConfiguration

  1. @Configuration:使用该注解来说明该类是配置类,等价于xml中的beans
  2. @EnableConfigurationProperties(HelloServiceProperties.class):开启属性注入,对注解配置Bean的支持
  3. @ConditionalOnClass(HelloService.class):条件注解,当类路径下有指定的类的条件下。
  4. @ConditionalOnProperty(prefix=”hello”,value=”enabled”,matchIfMissing=true):条件注解,指定的属性是否有指定的值。当设置hello=enabled,如果没有设置则默认为true,即为条件符合。假如我们将matchIfMissing设置为false,则当设置hello=enabled时,条件为false,则不会将该Bean加载进容器类,当使用@Autowired注入HelloService时会报错。

猜你喜欢

转载自blog.csdn.net/m0_37208669/article/details/85231986
今日推荐