SpringBoot的pom文件、容器、組件使用及說明
一、pom文件、配置文件
1、pom文件
<?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">
<!-- pom模型版本 -->
<modelVersion>4.0.0</modelVersion>
<!-- 項目信息 -->
<groupId>demo</groupId><!-- 項目唯一標(biāo)識 -->
<artifactId>springboot</artifactId><!-- 項目名 -->
<version>0.0.1-SNAPSHOT</version><!-- 版本 -->
<packaging>jar</packaging><!-- 打包方式 (pom,war,jar) -->
<name>springboot</name><!-- 項目的名稱, Maven 產(chǎn)生的文檔用 -->
<description>Demo project for Spring Boot</description><!-- 項目的描述, Maven 產(chǎn)生的文檔用 -->
<!-- 父級項目 -->
<parent>
<artifactId>spring-boot-starter-parent</artifactId> <!-- 被繼承的父項目的構(gòu)件標(biāo)識符 -->
<groupId>org.springframework.boot</groupId> <!-- 被繼承的父項目的全球唯一標(biāo)識符 -->
<version>1.5.7.RELEASE</version> <!-- 被繼承的父項目的版本 -->
<!-- 父項目的pom.xml文件的相對路徑。相對路徑允許你選擇一個不同的路徑。默認(rèn)值是../pom.xml。
Maven首先在構(gòu)建當(dāng)前項目的地方尋找父項目的pom,其次在文件系統(tǒng)的這個位置(relativePath位置),
然后在本地倉庫,最后在遠(yuǎn)程倉庫尋找父項目的pom。 -->
<relativePath/> <!-- lookup parent from repository -->
</parent>
<!-- 模塊(有時稱作子項目) 被構(gòu)建成項目的一部分。列出的每個模塊元素是指向該模塊的目錄的相對路徑 -->
<modules>
<!-- 子項目相對路徑 -->
<module></module>
</modules>
<!-- 屬性設(shè)置 -->
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><!-- 編譯字符編碼為utf-8 -->
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><!-- 輸出字符編碼為UTF-8 -->
<java.version>1.8</java.version><!-- jdK版本 -->
</properties>
<!-- 依賴關(guān)系 -->
<dependencies>
<!-- 測試 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- mysql(數(shù)據(jù)庫) -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
<!-- 編譯 -->
<build>
<!-- 插件 -->
<plugins>
<!-- maven插件 -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>2、配置文件
SpringBoot 支持以下幾種類型的配置文件:
- application.properties:基于屬性鍵值對的配置文件,使用簡單的 key=value 格式,可讀性較高。
- application.yml:基于 YAML 格式的配置文件,使用縮進(jìn)和冒號表示屬性的層次結(jié)構(gòu),可讀性更好。
- application.yaml:與 application.yml 相同,只是文件擴(kuò)展名不同。
優(yōu)先級從高到低
properties -> yml -> yaml
bootstrap.yml配置文件
在 SpringCloud 的項目中常用到 bootstrap.yml配置文件,用于應(yīng)用程序上下文的引導(dǎo)階段,在 application.yml 之前加載。
二、Spring的流程
1、Spring的啟動

2、Spring中bean的生命周期
(1).Spring對bean進(jìn)行實例化;
(2).Spring將值和bean的引用注入到bean對應(yīng)的屬性中;
(3).bean實現(xiàn)了BeanNameAware接口,Spring將bean的ID傳遞給setBean-Name()方法;
(4).bean實現(xiàn)了BeanFactoryAware接口,Spring將調(diào)用setBeanFactory()方法,將BeanFactory容器實例傳入;
(5).bean實現(xiàn)了ApplicationContextAware接口,Spring將調(diào)用setApplicationContext()方法,將bean所在的應(yīng)用上下文的引用傳入進(jìn)來;
(6).bean實現(xiàn)了BeanPostProcessor接口,Spring將調(diào)用它們的postProcessBeforeInitialization()方法;
(7).bean實現(xiàn)了InitializingBean接口,Spring將調(diào)用它們的after-PropertiesSet()方法。類似地,
(8).bean使用initmethod聲明了初始化方法,該方法也會被調(diào)用;
(9).bean實現(xiàn)了BeanPostProcessor接口,Spring將調(diào)用它們的post-ProcessAfterInitialization()方法;
(10).bean已經(jīng)準(zhǔn)備就緒,可以被應(yīng)用程序使用了,它們將一直駐留在應(yīng)用上下文中,直到該應(yīng)用上下文被銷毀;
(11).bean實現(xiàn)了DisposableBean接口,Spring將調(diào)用它的destroy()接口方法。同樣,如果bean使用destroy-method聲明了銷毀方法,該方法也會被調(diào)用。
三、內(nèi)置容器
SpringBoot提供了四種Web容器,分別為Tomcat,Jetty,Undertow,Netty。
1、Tomcat(默認(rèn))
Tomcat在8.0之前默認(rèn)采?的I/O?式為BIO,之后改為NIO,適合處理少數(shù)非常繁忙的鏈接。

1.Tomcat組成、架構(gòu)
(1)Tomcat中只有一個Server,一個Server可以有多個Service,一個Service可以有多個 Connector(鏈接) 和一個 Container(容器);
(2)Server 掌管著整個Tomcat的生死大權(quán);
(4)Service 是對外提供服務(wù)的;
(5)Connector 用于接受請求并將請求封裝成Request和Response來具體處理;
(6)Container 用于封裝和管理Servlet,以及具體處理request請求;

2.Tomcat性能調(diào)優(yōu)
- namePrefix: 線程前綴
- maxThreads: 最大線程數(shù),默認(rèn)設(shè)置 200,一般建議在 500 ~ 1000,根據(jù)硬件設(shè)施和業(yè)務(wù)來判斷
- minSpareThreads: 核心線程數(shù),默認(rèn)設(shè)置 25
- prestartminSpareThreads: 在 Tomcat 初始化的時候就初始化核心線程
- maxQueueSize: 最大的等待隊列數(shù),超過則拒絕請求 ,默認(rèn) Integer.MAX_VALUE
- maxIdleTime: 線程空閑時間,超過該時間,線程會被銷毀,單位毫秒。
3.Tomcat熱加載實
調(diào)用 Context 容器的 reload 方法,先stop Context容器,再start Context容器。具體的實現(xiàn):
1)停止和銷毀 Context 容器及其所有子容器,子容器其實就是 Wrapper,也就是說 Wrapper 里面 Servlet 實例也被銷毀了。
2)停止和銷毀 Context 容器關(guān)聯(lián)的 Listener 和 Filter。
3)停止和銷毀 Context 下的 Pipeline 和各種 Valve。
4)停止和銷毀 Context 的類加載器,以及類加載器加載的類文件資源。
5)啟動 Context 容器,在這個過程中會重新創(chuàng)建前面四步被銷毀的資源。
- Context 容器對應(yīng)一個類加載器,類加載器在銷毀的過程中會把它加載的所有類也全部銷毀。
- Context 容器在啟動過程中,會創(chuàng)建一個新的類加載器來加載新的類文件。
4.Tomcat熱部署
熱部署跟熱加載的本質(zhì)區(qū)別是,熱部署會重新部署 Web 應(yīng)用,原來的 Context 對象會整個被銷毀掉,因此這個 Context 所關(guān)聯(lián)的一切資源都會被銷毀,包括 Session。
Host 容器并沒有在 backgroundProcess 方法中實現(xiàn)周期性檢測的任務(wù),而是通過監(jiān)聽器 HostConfig 來實現(xiàn)的(HostConfig#lifecycleEvent)
HostConfig 會檢查 webapps 目錄下的所有 Web 應(yīng)用:如果原來 Web 應(yīng)用目錄被刪掉了,就把相應(yīng) Context 容器整個銷毀掉。是否有新的 Web 應(yīng)用目錄放進(jìn)來了,或者有新的 WAR 包放進(jìn)來了,就部署相應(yīng)的 Web 應(yīng)用。
因此 HostConfig 做的事情都是比較“宏觀”的,它不會去檢查具體類文件或者資源文件是否有變化,而是檢查 Web 應(yīng)用目錄級別的變化。
2、Jetty
開源的webserver/servlet容器,是基于 NIO模型。
通過Handler實現(xiàn)擴(kuò)展簡單。Jetty和Tomcat性能方面差異不大,Jetty可以同時處理大量連接而且可以長時間保持連接,適合于web聊天應(yīng)用等。

1.替換默認(rèn)的Tomcat容器
<dependencies>
<dependency>
<groupid>org.springframework.boot</groupid>
<artifactid>spring-boot-starter-web</artifactid>
<exclusions>
<!-- 去除Tomcat容器 -->
<exclusion>
<groupid>org.springframework.boot</groupid>
<artifactid>spring-boot-starter-tomcat</artifactid>
</exclusion>
</exclusions>
</dependency>
<!-- 增加Jetty容器 -->
<dependency>
<groupid>org.springframework.boot</groupid>
<artifactid>spring-boot-starter-jetty</artifactid>
</dependency>
</dependencies>2.重要參數(shù)
是否打開Jetty日志(默認(rèn)關(guān)閉):server.jetty.accesslog.enabled
- 訪問日志所在目錄:server.jetty.accesslog.dir
- 最大線程數(shù):server.jetty.threads.max
- 最小線程數(shù):server.jetty.threads.min
- 最大隊列容量:server.jetty.threads.max-queue-capacity
- 線程最大空閑時間:server.jetty.threads.idle-timeout
3、Undertow
輕量級:Undertow 是非常小的,只有不到1MB。在內(nèi)嵌模式下,運行時只占heap空間的4MB左右。
支持 Servlet 3.1
Web Socket:支持 Web Socket (包括JSR-356)
長連接:默認(rèn)情況下,Undertow 通過添加keep-alive 的response header來支持長連接。它通過重用連接信息(connection details)來改善長連接的性能。
1.替換默認(rèn)的Tomcat容器
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<!-- 去除 Tomcat 容器 -->
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- 添加 Undertow 容器 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-undertow</artifactId>
</dependency>2.重要參數(shù)
# Undertow 日志存放目錄 server.undertow.accesslog.dir= # 是否啟動日志 server.undertow.accesslog.enabled=false # 日志格式 server.undertow.accesslog.pattern=common # 日志文件名前綴 server.undertow.accesslog.prefix=access_log # 日志文件名后綴 server.undertow.accesslog.suffix=log # HTTP POST請求最大的大小 server.undertow.max-http-post-size=0 # 設(shè)置IO線程數(shù), 它主要執(zhí)行非阻塞的任務(wù),它們會負(fù)責(zé)多個連接, 默認(rèn)設(shè)置每個CPU核心一個線程 # 不要設(shè)置過大,如果過大,啟動項目會報錯:打開文件數(shù)過多 server.undertow.io-threads=12 # 阻塞任務(wù)線程池, 當(dāng)執(zhí)行類似servlet請求阻塞IO操作, undertow會從這個線程池中取得線程 # 它的值設(shè)置取決于系統(tǒng)線程執(zhí)行任務(wù)的阻塞系數(shù),默認(rèn)值是IO線程數(shù)*8 server.undertow.worker-threads=20 # 以下的配置會影響buffer,這些buffer會用于服務(wù)器連接的IO操作,有點類似netty的池化內(nèi)存管理 # 每塊buffer的空間大小,越小的空間被利用越充分,不要設(shè)置太大,以免影響其他應(yīng)用,合適即可 server.undertow.buffer-size=1024 # 每個區(qū)分配的buffer數(shù)量 , 所以pool的大小是buffer-size * buffers-per-region server.undertow.buffers-per-region=1024 # 是否分配的直接內(nèi)存 server.undertow.direct-buffers=true
4、Netty
1、SpringBoot整合Netty(服務(wù)端)
1.配置
<!-- netty -->
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.36.Final</version>
</dependency># netty 配置 netty: # boss線程數(shù)量 boss: 4 # worker線程數(shù)量 worker: 2 # 連接超時時間 timeout: 6000 # 服務(wù)器主端口 port: 17000 # 服務(wù)器備用端口 portSalve: 18026 # 服務(wù)器地址 host: 127.0.0.1
2.編寫netty處理器
/**
* Socket攔截器,用于處理客戶端的行為
**/
@Slf4j
public class SocketHandler extends ChannelInboundHandlerAdapter {
public static final ChannelGroup clients = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
/**
* 讀取到客戶端發(fā)來的消息
*/
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
// 由于我們配置的是 字節(jié)數(shù)組 編解碼器,所以這里取到的用戶發(fā)來的數(shù)據(jù)是 byte數(shù)組
byte[] data = (byte[]) msg;
log.info("收到消息: " + new String(data));
// 給其他人轉(zhuǎn)發(fā)消息
for (Channel client : clients) {
if (!client.equals(ctx.channel())) {
client.writeAndFlush(data);
}
}
}
@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
log.info("新的客戶端鏈接:" + ctx.channel().id().asShortText());
clients.add(ctx.channel());
}
@Override
public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
clients.remove(ctx.channel());
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.channel().close();
clients.remove(ctx.channel());
}
}3.編寫netty初始化器
/**
* Socket 初始化器,每一個Channel進(jìn)來都會調(diào)用這里的 InitChannel 方法
**/
@Component
public class SocketInitializer extends ChannelInitializer<SocketChannel> {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
ChannelPipeline pipeline = socketChannel.pipeline();
// 添加對byte數(shù)組的編解碼,netty提供了很多編解碼器,你們可以根據(jù)需要選擇
pipeline.addLast(new ByteArrayDecoder());
pipeline.addLast(new ByteArrayEncoder());
// 添加上自己的處理器
pipeline.addLast(new SocketHandler());
}
}4.編寫netty服務(wù)
@Slf4j
@Component
public class SocketServer {
@Resource
private SocketInitializer socketInitializer;
@Getter
private ServerBootstrap serverBootstrap;
/**
* netty服務(wù)監(jiān)聽端口
*/
@Value("${netty.port:17000}")
private int port;
/**
* 主線程組數(shù)量
*/
@Value("${netty.boss:4}")
private int bossThread;
/**
* 啟動netty服務(wù)器
*/
public void start() {
this.init();
this.serverBootstrap.bind(this.port);
log.info("Netty started on port: {} (TCP) with boss thread {}", this.port, this.bossThread);
}
/**
* 初始化netty配置
*/
private void init() {
// 創(chuàng)建兩個線程組,bossGroup為接收請求的線程組,一般1-2個就行
NioEventLoopGroup bossGroup = new NioEventLoopGroup(this.bossThread);
// 實際工作的線程組
NioEventLoopGroup workerGroup = new NioEventLoopGroup();
this.serverBootstrap = new ServerBootstrap();
this.serverBootstrap.group(bossGroup, workerGroup) // 兩個線程組加入進(jìn)來
.channel(NioServerSocketChannel.class) // 配置為nio類型
.childHandler(this.socketInitializer); // 加入自己的初始化器
}
}5.啟動netty
/**
* 監(jiān)聽Spring容器啟動完成,完成后啟動Netty服務(wù)器
**/
@Component
public class NettyStartListener implements ApplicationRunner {
@Resource
private SocketServer socketServer;
@Override
public void run(ApplicationArguments args) throws Exception {
this.socketServer.start();
}
}2、Netty客戶端
客戶端用NIO來編寫,在實際工作中客戶端可能是 WebSocket、Socket,以 Socket 為例。
1.編寫客戶端線程
public class ClientThread implements Runnable{
private final Selector selector;
public ClientThread(Selector selector) {
this.selector = selector;
}
@Override
public void run() {
try {
for (; ; ) {
int channels = selector.select();
if (channels == 0) {
continue;
}
Set<SelectionKey> selectionKeySet = selector.selectedKeys();
Iterator<SelectionKey> keyIterator = selectionKeySet.iterator();
while (keyIterator.hasNext()) {
SelectionKey selectionKey = keyIterator.next();
// 移除集合當(dāng)前得selectionKey,避免重復(fù)處理
keyIterator.remove();
if (selectionKey.isReadable()) {
this.handleRead(selector, selectionKey);
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
// 處理可讀狀態(tài)
private void handleRead(Selector selector, SelectionKey selectionKey) throws IOException {
SocketChannel channel = (SocketChannel) selectionKey.channel();
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
StringBuilder message = new StringBuilder();
if (channel.read(byteBuffer) > 0) {
byteBuffer.flip();
message.append(StandardCharsets.UTF_8.decode(byteBuffer));
}
// 再次注冊到選擇器上,繼續(xù)監(jiān)聽可讀狀態(tài)
channel.register(selector, SelectionKey.OP_READ);
System.out.println(message);
}
}2.客戶端邏輯
public class ChatClient {
public void start(String name) throws IOException {
SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", 8088));
socketChannel.configureBlocking(false);
Selector selector = Selector.open();
socketChannel.register(selector, SelectionKey.OP_READ);
// 監(jiān)聽服務(wù)端發(fā)來得消息
new Thread(new ClientThread(selector)).start();
// 監(jiān)聽用戶輸入
Scanner scanner = new Scanner(System.in);
while (scanner.hasNextLine()) {
String message = scanner.nextLine();
if (StringUtils.hasText(message)) {
socketChannel.write(StandardCharsets.UTF_8.encode(name + ": " + message));
}
}
}
}3.客戶端
public class Client1 {
public static void main(String[] args) throws IOException {
new ChatClient().start("李四");
}
}
public class Client2 {
public static void main(String[] args) throws IOException {
new ChatClient().start("張三");
}
}三、重要組件
- Spring Core:Spring的核心組件,提供IOC、AOP等基礎(chǔ)功能,是Spring全家桶的基礎(chǔ)。
- Spring Boot:一個基于Spring Framework的快速開發(fā)框架,可以快速創(chuàng)建獨立的、生產(chǎn)級別的Spring應(yīng)用程序。
- Spring Cloud:一個用于構(gòu)建分布式應(yīng)用程序的框架,提供了諸如服務(wù)發(fā)現(xiàn)、配置管理、負(fù)載均衡等功能。
- Spring Data:用于簡化數(shù)據(jù)訪問層開發(fā)的框架,提供了一系列數(shù)據(jù)訪問模板和持久化技術(shù)的集成。
- Spring Security:一個用于處理應(yīng)用程序安全的框架,提供了認(rèn)證、授權(quán)、安全防護(hù)等功能。
- Spring Integration:Spring Integration是一個用于構(gòu)建企業(yè)級集成解決方案的框架,支持將不同的應(yīng)用程序和服務(wù)集成到一起。它提供了許多組件和模式,如消息通道、消息端點、消息路由器、過濾器等。
- Spring Batch:Spring Batch是一個用于處理大量數(shù)據(jù)和批處理作業(yè)的框架。它提供了各種工具和組件,如任務(wù)啟動器、作業(yè)倉庫、作業(yè)執(zhí)行器、步驟處理器、讀寫器等。
- Spring Web Services:Spring Web Services是一個用于構(gòu)建基于SOAP協(xié)議的Web服務(wù)的框架。它提供了各種組件和工具,如消息處理器、綁定器、端點等,使得構(gòu)建Web服務(wù)更加容易。
總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
RedisTemplate中opsForValue和opsForList方法的使用詳解
這篇文章主要介紹了RedisTemplate中opsForValue和opsForList方法的使用詳解,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-08-08
詳解Spring Security中獲取當(dāng)前登錄用戶的詳細(xì)信息的幾種方法
本文主要介紹了詳解Spring Security中獲取當(dāng)前登錄用戶的詳細(xì)信息的幾種方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-05-05
TransmittableThreadLocal解決線程間上下文傳遞煩惱
這篇文章主要為大家介紹了TransmittableThreadLocal解決線程間上下文傳遞煩惱詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-11-11
Spring/SpringBoot?@RequestParam注解無法讀取application/json格式數(shù)據(jù)問題
RequestParam用于將指定的請求參數(shù)賦值給方法中的形參,可以接受簡單類型屬性,也可以接受對象類型,一般用于GET請求,下面這篇文章主要給大家介紹了關(guān)于Spring/SpringBoot?@RequestParam注解無法讀取application/json格式數(shù)據(jù)問題解決的相關(guān)資料,需要的朋友可以參考下2022-10-10

