最近再研究springboot的原理😋很有收穫,如今讓我分享一下springboot如何使用吧~javascript
想要解鎖更多新姿式?請訪問個人博客php
和書上理解的不一樣,我認爲Springboot是一個優秀的快速搭建框架,他經過maven繼承方式添加依賴來整合不少第三方工具,能夠避免各類麻煩的配置,有各類內嵌容器簡化Web項目,還能避免依賴的干擾,它內置tomcat,jetty容器,使用的是java app運行程序,而不是傳統的用把war放在tomcat等容器中運行html
JFinal是國人出品的一個web + orm 框架 ,JFinal,優勢是開發迅速、代碼量少、學習簡單、功能強大、輕量級、易擴展。核心就是極致簡潔。他沒有商業機構的支持,因此宣傳不到位,少有人知。java
Springboot相比與JFinal最大的優勢就是支持的功能很是多,能夠很是方便的將spring的各類框架如springframework , spring-mvc, spring-security, spring-data-jpa, spring-cache等等集成起來進行自動化配置 ,並且生態 比較好,不少產品都對Springboot作出必定支持。node
能夠這麼理解,Springboot裏面包含了Springcloud,Springcloud只是Springboot裏面的一個組件而已。mysql
Springcloud提供了至關完整的微服務架構。而微服務架構,本質來講就是分佈式架構,意味着你要將原來是一個總體的項目拆分紅一個個的小型項目,而後利用某種機制將其聯合起來,例如服務治理、通訊框架等基礎設施。react
SpringBoot的Web組件,默認集成的是SpringMVC框架。jquery
要往下看的話,注意了👇git
我已經很久沒用Eclipse了,要知道Eclipse是建立一個maven項目在引入Springboot依賴建立的。github
下面我分享一下用IDEA建立Springboot的方法。
很簡單,在這個界面裏面就能夠建立Springboot了。接下來在添加一些組件。
大功告成!
這裏用我寫的一個秒殺項目做爲參考栗子。秒殺商城
建立一個conntroller包,編寫一個樣列。
package cn.tengshe789.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/demo")
public class SampleController {
@RequestMapping("/hello")
public String index() {
return "Hello World";
}
}
複製代碼
接下來在他同級包或者上一級的包內,建立一個主方法MainApplication
。方法內容;
@SpringBootApplication
@EnableAsync
//@ComponentScan("cn.tengshe789.controller")
//@EnableAutoConfiguration
public class MainApplication {
public static void main(String[] args) {
SpringApplication.run(MainApplication.class, args);
}
}
複製代碼
在瀏覽器輸入http://127.0.0.1:8080/demo/hello/,就能夠啓動了!
Springboot將他標識爲啓動類,用它啓動Springboot項目
在上加上RestController 表示修飾該Controller全部的方法返回JSON格式,直接能夠編寫Restful接口。就至關於@Controller
+@ResponseBody
這種實現
用在啓動Springboot中,至關於@ComponentScan
+@EnableAutoConfiguration
+@Configuration
控制器掃包範圍。
他讓 Spring Boot 根據咱應用所聲明的依賴來對 Spring 框架進行自動配置。意思是,建立項目時添加的spring-boot-starter-web添加了Tomcat和Spring MVC,因此auto-configuration將假定你正在開發一個web應用並相應地對Spring進行設置。
規則:
一、名用大寫比較規範
二、=兩邊別打空格
三、名值對寫完後別打分號
name=tengshe789
複製代碼
spring.profiles.active=pre
application-dev.properties:開發環境
application-test.properties:測試環境
application-prod.properties:生產環境
複製代碼
server.port=8888
server.context-path=/tengshe789
複製代碼
規則:
server:
port: 8080
context-path: /springboot
複製代碼
Springboot官方不推薦xml,略
一個項目用Springboot,十有八九就是用於Web開發。首先讓咱們看看Springboot怎麼快速開發Web把
請在resources目錄下建立static文件夾,在該位置放置一個靜態資源。
目錄:src/main/resources/static
啓動程序後,嘗試訪問http://localhost:8080/img.xxx/。就能夠訪問了。
在以前的快速使用的示例中,咱們都是經過添加@RestController
來處理請求,因此返回的內容爲json
對象。那麼若是須要渲染html頁面的時候,要如何實現呢?
Springboot依然能夠實現動態HTML,而且提供了多種模板引擎的默認配置支持,Springboot官方文檔有以下推薦的模板引擎:
· Thymeleaf
· FreeMarker
· Velocity
· Groovy
· Mustache
Springboot官方建議避免使用JSP,若必定要使用JSP將沒法實現Spring Boot的多種特性。
在Springboot中,默認的模板配置路徑都時:src/main/resources/templates。固然也能夠修改這個路徑,具體如何修改,可在各模板引擎的配置屬性中查詢並修改。
這裏仍是用我寫的一個秒殺項目做爲參考栗子。秒殺商城
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
複製代碼
在application.properties
中添加:
#thymeleaf
spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.suffix=.html
spring.thymeleaf.cache=false
spring.thymeleaf.servlet.content-type=text/html
spring.thymeleaf.enabled=true
spring.thymeleaf.encoding=UTF-8
# 一代填 spring.thymeleaf.mode=HTML5
spring.thymeleaf.mode=HTML
複製代碼
在src/main/resources/建立一個templates文件夾,新網頁後綴爲*.html
@RequestMapping("/to_list")
public String list(Model model,MiaoshaUser user) {
model.addAttribute("user", user);
//查詢商品列表
List<GoodsVo> goodsList = goodsService.listGoodsVo();
model.addAttribute("goodsList", goodsList);
return "goods_list";
}
複製代碼
這裏注意Thymeleaf語法,Thymeleaf很像HTML,不一樣之處在標籤加了一個th前綴
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>商品列表</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<!-- jquery -->
<script type="text/javascript" th:src="@{/js/jquery.min.js}"></script>
</head>
<body>
<div class="panel panel-default" >
<div class="panel-heading">秒殺商品列表</div>
<table class="table" id="goodslist">
<tr><td>商品名稱</td><td>商品圖片</td><td>商品原價</td><td>秒殺價</td><td>庫存數量</td><td>詳情</td></tr>
<tr th:each="goods,goodsStat : ${goodsList}">
<td th:text="${goods.goodsName}"></td>
<td ><img th:src="@{${goods.goodsImg}}" width="100" height="100" /></td>
<td th:text="${goods.goodsPrice}"></td>
<td th:text="${goods.miaoshaPrice}"></td>
<td th:text="${goods.stockCount}"></td>
<td><a th:href="'/goods_detail.htm?goodsId='+${goods.id}">詳情</a></td>
</tr>
</table>
</div>
</body>
</html>
複製代碼
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
複製代碼
在application.properties
中添加:
#Freemarker
spring.freemarker.allow-request-override=false
spring.freemarker.cache=true
spring.freemarker.check-template-location=true
spring.freemarker.charset=UTF-8
spring.freemarker.content-type=text/html
spring.freemarker.expose-request-attributes=false
spring.freemarker.expose-session-attributes=false
spring.freemarker.expose-spring-macro-helpers=false
#spring.freemarker.prefix=
#spring.freemarker.request-context-attribute=
#spring.freemarker.settings.*=
spring.freemarker.suffix=.ftl
spring.freemarker.template-loader-path=classpath:/templates/
#comma-separated list
#spring.freemarker.view-names= # whitelist of view names that can be resolved
複製代碼
在src/main/resources/建立一個templates文件夾,新網頁後綴爲*.ftl
@RequestMapping("/freemarkerIndex")
public String index(Map<String, Object> result) {
result.put("nickname", "tEngSHe789");
result.put("old", "18");
result.put("my Blog", "HTTPS://blog.tengshe789.tech/");
List<String> listResult = new ArrayList<String>();
listResult.add("guanyu");
listResult.add("zhugeliang");
result.put("listResult", listResult);
return "index";
}
複製代碼
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8" />
<title>首頁</title>
</head>
<body>
${nickname}
<#if old=="18">
太假了吧哥們
<#elseif old=="21">
你是真的21歲
<#else>
其餘
</#if>
<#list userlist as user>
${user}
</#list>
</body>
</html>
複製代碼
不建議用Springboot整合JSP,要的話必定要爲war類型,不然會找不到頁面.,並且不要把JSP頁面存放在resources// jsp 不能被訪問到
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.4.RELEASE</version>
</parent>
<dependencies>
<!-- SpringBoot web 核心組件 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</dependency>
<!-- SpringBoot 外部tomcat支持 -->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
</dependency>
</dependencies>
複製代碼
在application.properties
中添加:
spring.mvc.view.prefix=/WEB-INF/jsp/
spring.mvc.view.suffix=.jsp
複製代碼
在src/main/resources/建立一個templates文件夾,新網頁後綴爲*.jsp
@Controller
public class IndexController {
@RequestMapping("/index")
public String index() {
return "index";
}
}
複製代碼
略略略😝
要了解 WebFlux ,首先了解下什麼是Reactive響應式(反應式、異步、面向流)編程 ,他是一種新的編程風格,其特色是異步或併發、事件驅動、推送PUSH機制以及觀察者模式的衍生。reactive應用(響應式應用)容許開發人員構建事件驅動(event-driven),可擴展性,彈性的反應系統:提供高度敏感的實時的用戶體驗感受,可伸縮性和彈性的應用程序棧的支持,隨時能夠部署在多核和雲計算架構。
Spring Boot Webflux 就是基於 Reactor 實現的。Spring Boot 2.0 包括一個新的 spring-webflux 模塊。該模塊包含對響應式 HTTP 和 WebSocket 客戶端的支持,以及對 REST,HTML 和 WebSocket 交互等程序的支持。通常來講,Spring MVC 用於同步處理,Spring Webflux 用於異步處理。
Spring Boot Webflux 有兩種編程模型實現,一種相似 Spring MVC 註解方式,另外一種是使用其功能性端點方式。
WebFlux 支持的容器有 Tomcat、Jetty(Non-Blocking IO API) ,也能夠像 Netty 和 Undertow 的自己就支持異步容器。在容器中 Spring WebFlux 會將輸入流適配成 Mono 或者 Flux 格式進行統一處理。
@RestController
public class PersonController {
private final PersonRepository repository;
public PersonController(PersonRepository repository) {
this.repository = repository;
}
@PostMapping("/person")
Mono<Void> create(@RequestBody Publisher<Person> personStream) {
return this.repository.save(personStream).then();
}
@GetMapping("/person")
Flux<Person> list() {
return this.repository.findAll();
}
@GetMapping("/person/{id}")
Mono<Person> findById(@PathVariable String id) {
return this.repository.findOne(id);
}
}
複製代碼
Spring Boot 2.0 這裏有兩條不一樣的線分別是:
若是使用 Spring Data Reactive ,原來的 Spring 針對 Spring Data (JDBC等)的事務管理會不起做用。由於原來的 Spring 事務管理(Spring Data JPA)都是基於 ThreadLocal 傳遞事務的,其本質是基於 阻塞 IO 模型,不是異步的。
但 Reactive 是要求異步的,不一樣線程裏面 ThreadLocal 確定取不到值了。天然,咱們得想一想如何在使用 Reactive 編程是作到事務,有一種方式是 回調 方式,一直傳遞 conn :newTransaction(conn ->{})
由於每次操做數據庫也是異步的,因此 connection 在 Reactive 編程中沒法靠 ThreadLocal 傳遞了,只能放在參數上面傳遞。雖然會有必定的代碼侵入行。進一步,也能夠 kotlin 協程,去作到透明的事務管理,即把 conn 放到 協程的局部變量中去。 那 Spring Data Reactive Repositories 不支持 MySQL,進一步也不支持 MySQL 事務,怎麼辦?
答案是,這個問題其實和第一個問題也相關。 爲啥不支持 MySQL,即 JDBC 不支持。你們能夠看到 JDBC 是所屬 Spring Data 的。因此能夠等待 Spring Data Reactive Repositories 升級 IO 模型,去支持 MySQL。也能夠和上面也講到了,如何使用 Reactive 編程支持事務。
若是應用只能使用不強依賴數據事務,依舊使用 MySQL ,可使用下面的實現,代碼以下:
public interface CityService {
/** * 獲取城市信息列表 * * @return */
List<City> findAllCity();
/** * 根據城市 ID,查詢城市信息 * * @param id * @return */
City findCityById(Long id);
/** * 新增城市信息 * * @param city * @return */
Long saveCity(City city);
/** * 更新城市信息 * * @param city * @return */
Long updateCity(City city);
/** * 根據城市 ID,刪除城市信息 * * @param id * @return */
Long deleteCity(Long id);
}
複製代碼
具體案例在我參考博主的 Github
建立一個 Route 類來定義 RESTful HTTP 路由
複製代碼
須要執行異步方法時,在方法上加上@Async
以後,底層使用多線程技術 。啓動加上須要@EnableAsync
使用這個須要spring-boot-starter-parent版本要在1.5以上
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
複製代碼
在application.properties
中添加:
# jdbc模板
spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
複製代碼
建立一個Service
@Service
public class UserServiceImpl implements UserService {
@Autowired
private JdbcTemplate jdbcTemplate;
public void createUser(String name, Integer age) {
jdbcTemplate.update("insert into users values(null,?,?);", name, age);
}
}
複製代碼
這裏用我寫的一個秒殺項目做爲參考栗子。秒殺商城
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.2</version>
</dependency>
複製代碼
在application.properties
中添加:
#mybatis
mybatis.type-aliases-package=cn.tengshe789.domain
mybatis.configuration.map-underscore-to-camel-case=true
mybatis.configuration.default-fetch-size=100
mybatis.configuration.default-statement-timeout=3000
mybatis.mapperLocations = classpath:cn/tengshe789/dao/*.xml
複製代碼
建立一個Dao(Mapper 代碼)
@Mapper
@Component
public interface GoodsDao {
@Select("select g.*,mg.stock_count, mg.start_date, mg.end_date,mg.miaosha_price from miaosha_goods mg left join goods g on mg.goods_id = g.id")
public List<GoodsVo> listGoodsVo();
}
複製代碼
建立service
@Service
public class GoodsService {
@Autowired
GoodsDao goodsDao;
/* * 展現商品列表 */
public List<GoodsVo> listGoodsVo() {
return goodsDao.listGoodsVo();
}
}
複製代碼
PageHelper 是一款好用的開源免費的 Mybatis 第三方物理分頁插件
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.2.5</version>
</dependency>
複製代碼
在application.properties
中添加:
# 配置日誌
logging.level.cn.tengshe789.dao=DEBUG
# Pagehelper
pagehelper.helperDialect=mysql
pagehelper.reasonable=true
pagehelper.supportMethodsArguments=true
pagehelper.params=count=countSql
pagehelper.page-size-zero=true
複製代碼
或者在application.yml
中添加:
# 與mybatis整合
mybatis:
config-location: classpath:mybatis.xml
mapper-locations:
- classpath:cn/tengshe789/dao/*.xml
# 分頁配置
pagehelper:
helper-dialect: mysql
reasonable: true
support-methods-arguments: true
params: count=countSql
複製代碼
@Data
public class User {
private Integer id;
private String name;
}
複製代碼
public interface UserDao {
@Select("SELECT * FROM USERS ")
List<User> findUserList();
}
複製代碼
@Service
public class UserService {
@Autowired
private UserMapper userDao;
/** * page 當前頁數<br> * size 當前展現的數據<br> */
public PageInfo<User> findUserList(int page, int size) {
// 開啓分頁插件,放在查詢語句上面
PageHelper.startPage(page, size);
List<User> listUser = userDao.findUserList();
// 封裝分頁以後的數據
PageInfo<User> pageInfoUser = new PageInfo<User>(listUser);
return pageInfoUser;
}
}
複製代碼
spring-data-jpa三個步驟:
詳情:JPA官方網站
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
複製代碼
Springboot 默認使用hibernate做爲JPA的實現 。須要在application.properties
中添加:
# hibernate
spring.datasource.url=jdbc:mysql://localhost:3306/test?useSSL=false
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.tomcat.max-active=100
spring.datasource.tomcat.max-idle=200
spring.datasource.tomcat.initialSize=20
spring.jpa.database-platform=org.hibernate.dialect.MySQL5Dialect
複製代碼
@Data
@Entity(name = "users")
public class UserEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column(name = "name")
private String name;
@Column(name = "age")
private Integer age;
}
複製代碼
註解的意思:
@Entity
會被spring掃描並加載,
@Id
註解在主鍵上
@Column name="call_phone"
指該字段對應的數據庫的字段名,若是相同就不須要定義。數據庫下劃線間隔和代碼中的駝峯法視爲相同,如數據庫字段create_time等價於Java類中的createTime,所以不須要用@Column註解。
此時須要繼承Repository接口~
public interface UserDao extends JpaRepository<User, Integer> {
}
複製代碼
@RestController
public class IndexController {
@Autowired
private UserDao userDao;
@RequestMapping("/jpaFindUser")
public Object jpaIndex(User user) {
Optional<User> userOptional = userDao.findById(user.getId());
User result = userOptional.get();
return reusltUser == null ? "沒有查詢到數據" : result;
}
}
複製代碼
不少公司都會使用多數據庫,一個數據庫存放共同的配置或文件,另外一個數據庫是放垂直業務的數據。因此說須要一個項目中有多個數據源
這玩意原理很簡單,根據不一樣包名,加載不一樣數據源。
在application.properties
中添加:
# datasource1
spring.datasource.test1.driver-class-name = com.mysql.jdbc.Driver
spring.datasource.test1.jdbc-url =jdbc:mysql://localhost:3306/test01?useUnicode=true&characterEncoding=utf-8
spring.datasource.test1.username = root
spring.datasource.test1.password = 123456
# datasource2
spring.datasource.test2.driver-class-name = com.mysql.jdbc.Driver
spring.datasource.test2.jdbc-url =jdbc:mysql://localhost:3306/test02?useUnicode=true&characterEncoding=utf-8
spring.datasource.test2.username = root
spring.datasource.test2.password = 123456
複製代碼
數據庫1的
//DataSource01
@Configuration // 註冊到springboot容器中
@MapperScan(basePackages = "tech.tengshe789.test01", sqlSessionFactoryRef = "test1SqlSessionFactory")
public class DataSource1Config {
/** * @methodDesc: 功能描述:(配置test1數據庫) * @author: tEngSHe789 */
@Bean(name = "test1DataSource")
@ConfigurationProperties(prefix = "spring.datasource.test1")
@Primary
public DataSource testDataSource() {
return DataSourceBuilder.create().build();
}
/** * @methodDesc: 功能描述:(test1 sql會話工廠) */
@Bean(name = "test1SqlSessionFactory")
@Primary
public SqlSessionFactory testSqlSessionFactory(@Qualifier("test1DataSource") DataSource dataSource) throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource);
//加載mapper(不須要)
bean.setMapperLocations(
new PathMatchingResourcePatternResolver().getResources("classpath:mybatis/mapper/test1/*.xml"));
return bean.getObject();
}
/** * * @methodDesc: 功能描述:(test1 事物管理) */
@Bean(name = "test1TransactionManager")
@Primary
public DataSourceTransactionManager testTransactionManager(@Qualifier("test1DataSource") DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
@Bean(name = "test1SqlSessionTemplate")
@Primary
public SqlSessionTemplate testSqlSessionTemplate( @Qualifier("test1SqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
return new SqlSessionTemplate(sqlSessionFactory);
}
}
複製代碼
數據庫2的同理。
public interface User1Dao {
@Insert("insert into users values(null,#{name},#{age});")
public int addUser(@Param("name") String name, @Param("age") Integer age);
}
複製代碼
在多數據源的狀況下,使用@Transactional
註解時,應該指定事務管理者@Transactional(transactionManager = "test1TransactionManager")
怎麼進行事物管理呢,簡單,往下看。
找到service實現類,加上@Transactional
註解就行,此@Transactional
註解來自org.springframework.transaction.annotation
包 ,不是來自javax.transaction
。並且@Transactional
不只能夠註解在方法上,也能夠註解在類上。當註解在類上的時候意味着此類的全部public方法都是開啓事務的。若是類級別和方法級別同時使用了@Transactional
註解,則使用在類級別的註解會重載方法級別的註解。
注意:Springboot提供了一個@EnableTransactionManagement
註解在配置類上來開啓聲明式事務的支持。註解@EnableTransactionManagement
是默認打開的,想要關閉事務管理,想要在程序入口將這個註解改成false
啥是分佈式事務呢,好比咱們在執行一個業務邏輯的時候有兩步分別操做A數據源和B數據源,當咱們在A數據源執行數據更改後,在B數據源執行時出現運行時異常,那麼咱們必需要讓B數據源的操做回滾,並回滾對A數據源的操做。這種狀況在支付業務時經常出現,好比買票業務在最後支付失敗,那以前的操做必須所有回滾,若是以前的操做分佈在多個數據源中,那麼這就是典型的分佈式事務回滾
瞭解了什麼是分佈式事務,那分佈式事務在java的解決方案就是JTA(即Java Transaction API)。
springboot官方提供了 Atomikos , Bitronix ,Narayana 的類事務管理器
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jta-atomikos</artifactId>
</dependency>
複製代碼
# Mysql 1
mysql.datasource.test1.url = jdbc:mysql://localhost:3306/test01?useUnicode=true&characterEncoding=utf-8
mysql.datasource.test1.username = root
mysql.datasource.test1.password = 123456
mysql.datasource.test1.minPoolSize = 3
mysql.datasource.test1.maxPoolSize = 25
mysql.datasource.test1.maxLifetime = 20000
mysql.datasource.test1.borrowConnectionTimeout = 30
mysql.datasource.test1.loginTimeout = 30
mysql.datasource.test1.maintenanceInterval = 60
mysql.datasource.test1.maxIdleTime = 60
# Mysql 2
mysql.datasource.test2.url =jdbc:mysql://localhost:3306/test02?useUnicode=true&characterEncoding=utf-8
mysql.datasource.test2.username =root
mysql.datasource.test2.password =123456
mysql.datasource.test2.minPoolSize = 3
mysql.datasource.test2.maxPoolSize = 25
mysql.datasource.test2.maxLifetime = 20000
mysql.datasource.test2.borrowConnectionTimeout = 30
mysql.datasource.test2.loginTimeout = 30
mysql.datasource.test2.maintenanceInterval = 60
mysql.datasource.test2.maxIdleTime = 60
複製代碼
如下是讀取數據庫1的配置文件
@Data
@ConfigurationProperties(prefix = "mysql.datasource.test1")
public class DBConfig1 {
private String url;
private String username;
private String password;
private int minPoolSize;
private int maxPoolSize;
private int maxLifetime;
private int borrowConnectionTimeout;
private int loginTimeout;
private int maintenanceInterval;
private int maxIdleTime;
private String testQuery;
}
複製代碼
讀取數據庫2的配置文件略
數據源1:
@Configuration
// basePackages 最好分開配置 若是放在同一個文件夾可能會報錯
@MapperScan(basePackages = "tech.tengshe789.test01", sqlSessionTemplateRef = "testSqlSessionTemplate")
public class MyBatisConfig1 {
// 配置數據源
@Primary
@Bean(name = "testDataSource")
public DataSource testDataSource(DBConfig1 testConfig) throws SQLException {
MysqlXADataSource mysqlXaDataSource = new MysqlXADataSource();
mysqlXaDataSource.setUrl(testConfig.getUrl());
mysqlXaDataSource.setPinGlobalTxToPhysicalConnection(true);
mysqlXaDataSource.setPassword(testConfig.getPassword());
mysqlXaDataSource.setUser(testConfig.getUsername());
mysqlXaDataSource.setPinGlobalTxToPhysicalConnection(true);
AtomikosDataSourceBean xaDataSource = new AtomikosDataSourceBean();
xaDataSource.setXaDataSource(mysqlXaDataSource);
xaDataSource.setUniqueResourceName("testDataSource");
xaDataSource.setMinPoolSize(testConfig.getMinPoolSize());
xaDataSource.setMaxPoolSize(testConfig.getMaxPoolSize());
xaDataSource.setMaxLifetime(testConfig.getMaxLifetime());
xaDataSource.setBorrowConnectionTimeout(testConfig.getBorrowConnectionTimeout());
xaDataSource.setLoginTimeout(testConfig.getLoginTimeout());
xaDataSource.setMaintenanceInterval(testConfig.getMaintenanceInterval());
xaDataSource.setMaxIdleTime(testConfig.getMaxIdleTime());
xaDataSource.setTestQuery(testConfig.getTestQuery());
return xaDataSource;
}
@Primary
@Bean(name = "testSqlSessionFactory")
public SqlSessionFactory testSqlSessionFactory(@Qualifier("testDataSource") DataSource dataSource) throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource);
return bean.getObject();
}
@Primary
@Bean(name = "testSqlSessionTemplate")
public SqlSessionTemplate testSqlSessionTemplate( @Qualifier("testSqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
return new SqlSessionTemplate(sqlSessionFactory);
}
}
複製代碼
數據庫2略
@EnableConfigurationProperties(value = { DBConfig1.class, DBConfig2.class })
@SpringBootApplication
public class MainApplication {
public static void main(String[] args) {
SpringApplication.run(MainApplication.class, args);
}
}
複製代碼
在作項目時有時候會有定時器任務的功能,好比某某時間應該作什麼,多少秒應該怎麼樣之類的。
spring支持多種定時任務的實現。咱們來介紹下使用Quartz 和Scheduler
Spring Schedule 實現定時任務有兩種方式 1. 使用XML配置定時任務, 2. 使用 @Scheduled 註解。
固定等待時間 @Scheduled(fixedDelay = 時間間隔 )
固定間隔時間 @Scheduled(fixedRate = 時間間隔 )
@Component
public class ScheduleJobs {
public final static long SECOND = 1 * 1000;
FastDateFormat fdf = FastDateFormat.getInstance("yyyy-MM-dd HH:mm:ss");
@Scheduled(fixedDelay = SECOND * 2)
public void fixedDelayJob() throws InterruptedException {
TimeUnit.SECONDS.sleep(2);
System.out.println("[FixedDelayJob Execute]"+fdf.format(new Date()));
}
}
複製代碼
Corn表達式 @Scheduled(cron = Corn表達式)
@Component
public class ScheduleJobs {
public final static long SECOND = 1 * 1000;
FastDateFormat fdf = FastDateFormat.getInstance("yyyy-MM-dd HH:mm:ss");
@Scheduled(cron = "0/4 * * * * ?")
public void cronJob() {
System.out.println("[CronJob Execute]"+fdf.format(new Date()));
}
}
複製代碼
要在主方法上加上@EnableScheduling
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz-starter</artifactId>
</dependency>
複製代碼
# spring boot 2.x 已集成Quartz,無需本身配置
spring.quartz.job-store-type=jdbc
spring.quartz.properties.org.quartz.scheduler.instanceName=clusteredScheduler
spring.quartz.properties.org.quartz.scheduler.instanceId=AUTO
spring.quartz.properties.org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTX
spring.quartz.properties.org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegate
spring.quartz.properties.org.quartz.jobStore.tablePrefix=QRTZ_
spring.quartz.properties.org.quartz.jobStore.isClustered=true
spring.quartz.properties.org.quartz.jobStore.clusterCheckinInterval=10000
spring.quartz.properties.org.quartz.jobStore.useProperties=false
spring.quartz.properties.org.quartz.threadPool.class=org.quartz.simpl.SimpleThreadPool
spring.quartz.properties.org.quartz.threadPool.threadCount=10
spring.quartz.properties.org.quartz.threadPool.threadPriority=5
spring.quartz.properties.org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread=true
複製代碼
@Configuration
public class QuartzConfig {
@Bean
public JobDetail uploadTaskDetail() {
return JobBuilder.newJob(UploadTask.class).withIdentity("uploadTask").storeDurably().build();
}
@Bean
public Trigger uploadTaskTrigger() {
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule("*/5 * * * * ?");
return TriggerBuilder.newTrigger().forJob(uploadTaskDetail())
.withIdentity("uploadTask")
.withSchedule(scheduleBuilder)
.build();
}
}
複製代碼
建立一個配置類,分別制定具體任務類和觸發的規則
@Configuration
@DisallowConcurrentExecution
public class UploadTask extends QuartzJobBean {
@Resource
private TencentYunService tencentYunService;
@Override
protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
System.out.println("任務開始");
try {
Thread.sleep(6000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("任務結束");
}
}
複製代碼
@DisallowConcurrentExecution
禁止併發執行
併發執行方面,系統默認爲true,即第一個任務還未執行完整,第二個任務若是到了執行時間,則會立馬開啓新線程執行任務,這樣若是咱們是從數據庫讀取信息,兩次重複讀取可能出現重複執行任務的狀況,因此咱們須要將這個值設置爲false,這樣第二個任務會日後推遲,只有在第一個任務執行完成後纔會執行第二個任務
<!-- spring boot start -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<exclusions>
<!-- 排除自帶的logback依賴 -->
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- springboot-log4j -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j</artifactId>
<version>1.3.8.RELEASE</version>
</dependency>
複製代碼
文件名稱log4j.properties
#log4j.rootLogger=CONSOLE,info,error,DEBUG
log4j.rootLogger=info,error,CONSOLE,DEBUG
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%d{yyyy-MM-dd-HH-mm} [%t] [%c] [%p] - %m%n
log4j.logger.info=info
log4j.appender.info=org.apache.log4j.DailyRollingFileAppender
log4j.appender.info.layout=org.apache.log4j.PatternLayout
log4j.appender.info.layout.ConversionPattern=%d{yyyy-MM-dd-HH-mm} [%t] [%c] [%p] - %m%n
log4j.appender.info.datePattern='.'yyyy-MM-dd
log4j.appender.info.Threshold = info
log4j.appender.info.append=true
#log4j.appender.info.File=/home/admin/pms-api-services/logs/info/api_services_info
log4j.appender.info.File=/Users/dddd/Documents/testspace/pms-api-services/logs/info/api_services_info
log4j.logger.error=error
log4j.appender.error=org.apache.log4j.DailyRollingFileAppender
log4j.appender.error.layout=org.apache.log4j.PatternLayout
log4j.appender.error.layout.ConversionPattern=%d{yyyy-MM-dd-HH-mm} [%t] [%c] [%p] - %m%n
log4j.appender.error.datePattern='.'yyyy-MM-dd
log4j.appender.error.Threshold = error
log4j.appender.error.append=true
#log4j.appender.error.File=/home/admin/pms-api-services/logs/error/api_services_error
log4j.appender.error.File=/Users/dddd/Documents/testspace/pms-api-services/logs/error/api_services_error
log4j.logger.DEBUG=DEBUG
log4j.appender.DEBUG=org.apache.log4j.DailyRollingFileAppender
log4j.appender.DEBUG.layout=org.apache.log4j.PatternLayout
log4j.appender.DEBUG.layout.ConversionPattern=%d{yyyy-MM-dd-HH-mm} [%t] [%c] [%p] - %m%n
log4j.appender.DEBUG.datePattern='.'yyyy-MM-dd
log4j.appender.DEBUG.Threshold = DEBUG
log4j.appender.DEBUG.append=true
#log4j.appender.DEBUG.File=/home/admin/pms-api-services/logs/debug/api_services_debug
log4j.appender.DEBUG.File=/Users/dddd/Documents/testspace/pms-api-services/logs/debug/api_services_debug
複製代碼
private static final Logger logger = LoggerFactory.getLogger(IndexController.class);
複製代碼
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
複製代碼
@Aspect
@Component
public class WebLogAspect {
private static final Logger logger = LoggerFactory.getLogger(WebLogAspect.class);
@Pointcut("execution(public * tech.tengshe789.controller.*.*(..))")
public void webLog() {
}
@Before("webLog()")
public void doBefore(JoinPoint joinPoint) throws Throwable {
// 接收到請求,記錄請求內容
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
// 記錄下請求內容
logger.info("URL : " + request.getRequestURL().toString());
logger.info("HTTP_METHOD : " + request.getMethod());
logger.info("IP : " + request.getRemoteAddr());
Enumeration<String> enu = request.getParameterNames();
while (enu.hasMoreElements()) {
String name = (String) enu.nextElement();
logger.info("name:{},value:{}", name, request.getParameter(name));
}
}
@AfterReturning(returning = "ret", pointcut = "webLog()")
public void doAfterReturning(Object ret) throws Throwable {
// 處理完請求,返回內容
logger.info("RESPONSE : " + ret);
}
}
複製代碼
很是簡單的辦法
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.0</version>
</dependency>
複製代碼
類中添加@Slf4j
註解便可。使用是直接輸入log全局變量
@Data 標籤,生成getter/setter toString()等方法
@NonNull : 讓你不在擔心而且愛上NullPointerException
@CleanUp : 自動資源管理:不用再在finally中添加資源的close方法
@Setter/@Getter : 自動生成set和get方法
@ToString : 自動生成toString方法
@EqualsAndHashcode : 從對象的字段中生成hashCode和equals的實現
@NoArgsConstructor/@RequiredArgsConstructor/@AllArgsConstructor
自動生成構造方法
@Data : 自動生成set/get方法,toString方法,equals方法,hashCode方法,不帶參數的構造方法
@Value : 用於註解final類
@Builder : 產生複雜的構建器api類
@SneakyThrows : 異常處理(謹慎使用)
@Synchronized : 同步方法安全的轉化
@Getter(lazy=true) :
@Log : 支持各類logger對象,使用時用對應的註解,如:@Log4
複製代碼
攔截器,在AOP(Aspect-Oriented Programming)中用於在某個方法或字段被訪問以前,進行攔截,而後在以前或以後加入某些操做。攔截是AOP的一種實現策略。
(1)攔截器是基於java的反射機制的,而過濾器是基於函數回調。
(2)攔截器不依賴於servlet容器,而過濾器依賴於servlet容器。
(3)攔截器只能對Controller請求起做用,而過濾器則能夠對幾乎全部的請求起做用。
(4)在Controller的生命週期中,攔截器能夠屢次被調用,而過濾器只能在容器初始化時被調用一次。
過濾器(filter)和攔截器(interceptor)是有區別的,詳情 ,他們的執行順序: 先filter 後 interceptor
->過濾器應用場景:設置編碼字符、過濾銘感字符
->攔截器應用場景:攔截未登錄用戶、審計日誌
註冊攔截器
@Configuration
public class WebAppConfig {
@Autowired
private LoginIntercept loginIntercept;
@Bean
public WebMvcConfigurer WebMvcConfigurer() {
return new WebMvcConfigurer() {
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(loginIntercept).addPathPatterns("/*");
};
};
}
}
複製代碼
建立模擬登陸攔截器,驗證請求是否有token參數
@Slf4j
@Component
public class LoginIntercept implements HandlerInterceptor {
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
log.info("開始攔截登陸請求....");
String token = request.getParameter("token");
if (StringUtils.isEmpty(token)) {
response.getWriter().println("not found token");
return false;
}
return true;
}
}
複製代碼
在 Spring Boot中,經過@EnableCaching
註解自動化配置合適的緩存管理器(CacheManager),Spring Boot根據下面的順序去偵測緩存提供者: Generic , JCache (JSR-107), EhCache 2.x ,Hazelcast , Infinispan ,Redis ,Guava , Simple
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
複製代碼
<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd" updateCheck="false">
<diskStore path="java.io.tmpdir/Tmp_EhCache" />
<!-- 默認配置 -->
<defaultCache maxElementsInMemory="5000" eternal="false" timeToIdleSeconds="120" timeToLiveSeconds="120" memoryStoreEvictionPolicy="LRU" overflowToDisk="false" />
<cache name="baseCache" maxElementsInMemory="10000" maxElementsOnDisk="100000" />
</ehcache>
複製代碼
配置信息介紹
name
:緩存名稱。
maxElementsInMemory
:緩存最大個數。
eternal
:對象是否永久有效,一但設置了,timeout將不起做用。
timeToIdleSeconds
:設置對象在失效前的容許閒置時間(單位:秒)。僅當eternal=false對象不是永久有效時使用,可選屬性,默認值是0,也就是可閒置時間無窮大。
timeToLiveSeconds
:設置對象在失效前容許存活時間(單位:秒)。最大時間介於建立時間和失效時間之間。僅當eternal=false對象不是永久有效時使用,默認是0.,也就是對象存活時間無窮大。
overflowToDisk
:當內存中對象數量達到maxElementsInMemory時,Ehcache將會對象寫到磁盤中。
diskSpoolBufferSizeMB
:這個參數設置DiskStore(磁盤緩存)的緩存區大小。默認是30MB。每一個Cache都應該有本身的一個緩衝區。
maxElementsOnDisk
:硬盤最大緩存個數。
diskPersistent
:是否緩存虛擬機重啓期數據 Whether the disk store persists between restarts of the Virtual Machine. The default value is false.
diskExpiryThreadIntervalSeconds
:磁盤失效線程運行時間間隔,默認是120秒。
memoryStoreEvictionPolicy
:當達到maxElementsInMemory限制時,Ehcache將會根據指定的策略去清理內存。默認策略是LRU(最近最少使用)。你能夠設置爲FIFO(先進先出)或是LFU(較少使用)。
clearOnFlush
:內存數量最大時是否清除。
@CacheConfig(cacheNames = "baseCache")
public interface UserDao {
@Select("select * from users where name=#{name}")
@Cacheable
UserEntity findName(@Param("name") String name);
}
複製代碼
@Autowired
private CacheManager cacheManager;
@RequestMapping("/remoKey")
public void remoKey() {
cacheManager.getCache("baseCache").clear();
}
複製代碼
主方法啓動時加上@EnableCaching
便可
使用RedisTemplate 鏈接
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
複製代碼
單機
#redis
# Redis數據庫索引(默認爲0)
spring.redis.database=0
# Redis服務器地址
spring.redis.host=127.0.0.1
# Redis服務器鏈接端口
spring.redis.port=6379
# Redis服務器鏈接密碼(默認爲空)
spring.redis.password=
# 鏈接池最大鏈接數(使用負值表示沒有限制)
spring.redis.pool.max-active=8
# 鏈接池最大阻塞等待時間(使用負值表示沒有限制)
spring.redis.pool.max-wait=-1
# 鏈接池中的最大空閒鏈接
spring.redis.pool.max-idle=8
# 鏈接池中的最小空閒鏈接
spring.redis.pool.min-idle=0
# 鏈接超時時間(毫秒)
spring.redis.timeout=0
複製代碼
集羣或哨兵模式
#Matser的ip地址
redis.hostName=192.168.177.128
#端口號
redis.port=6382
#若是有密碼
redis.password=
#客戶端超時時間單位是毫秒 默認是2000
redis.timeout=10000
#最大空閒數
redis.maxIdle=300
#鏈接池的最大數據庫鏈接數。設爲0表示無限制,若是是jedis 2.4之後用redis.maxTotal
#redis.maxActive=600
#控制一個pool可分配多少個jedis實例,用來替換上面的redis.maxActive,若是是jedis 2.4之後用該屬性
redis.maxTotal=1000
#最大創建鏈接等待時間。若是超過此時間將接到異常。設爲-1表示無限制。
redis.maxWaitMillis=1000
#鏈接的最小空閒時間 默認1800000毫秒(30分鐘)
redis.minEvictableIdleTimeMillis=300000
#每次釋放鏈接的最大數目,默認3
redis.numTestsPerEvictionRun=1024
#逐出掃描的時間間隔(毫秒) 若是爲負數,則不運行逐出線程, 默認-1
redis.timeBetweenEvictionRunsMillis=30000
#是否在從池中取出鏈接前進行檢驗,若是檢驗失敗,則從池中去除鏈接並嘗試取出另外一個
redis.testOnBorrow=true
#在空閒時檢查有效性, 默認false
redis.testWhileIdle=true
#redis集羣配置
spring.redis.cluster.nodes=192.168.177.128:7001,192.168.177.128:7002,192.168.177.128:7003,192.168.177.128:7004,192.168.177.128:7005,192.168.177.128:7006
spring.redis.cluster.max-redirects=3
#哨兵模式
#redis.sentinel.host1=192.168.177.128
#redis.sentinel.port1=26379
#redis.sentinel.host2=172.20.1.231
#redis.sentinel.port2=26379
複製代碼
@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport{
@Value("${spring.redis.host}")
private String host;
@Value("${spring.redis.port}")
private int port;
@Value("${spring.redis.timeout}")
private int timeout;
//自定義緩存key生成策略
// @Bean
// public KeyGenerator keyGenerator() {
// return new KeyGenerator(){
// @Override
// public Object generate(Object target, java.lang.reflect.Method method, Object... params) {
// StringBuffer sb = new StringBuffer();
// sb.append(target.getClass().getName());
// sb.append(method.getName());
// for(Object obj:params){
// sb.append(obj.toString());
// }
// return sb.toString();
// }
// };
// }
//緩存管理器
@Bean
public CacheManager cacheManager(@SuppressWarnings("rawtypes") RedisTemplate redisTemplate) {
RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate);
//設置緩存過時時間
cacheManager.setDefaultExpiration(10000);
return cacheManager;
}
@Bean
public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory factory){
StringRedisTemplate template = new StringRedisTemplate(factory);
setSerializer(template);//設置序列化工具
template.afterPropertiesSet();
return template;
}
private void setSerializer(StringRedisTemplate template){
@SuppressWarnings({ "rawtypes", "unchecked" })
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
template.setValueSerializer(jackson2JsonRedisSerializer);
}
}
複製代碼
@Mapper
@CacheConfig(cacheNames = "users")
public interface UserMapper {
@Insert("insert into user(name,age) values(#{name},#{age})")
int addUser(@Param("name")String name,@Param("age")String age);
@Select("select * from user where id =#{id}")
@Cacheable(key ="#p0")
User findById(@Param("id") String id);
@CachePut(key = "#p0")
@Update("update user set name=#{name} where id=#{id}")
void updataById(@Param("id")String id,@Param("name")String name);
//若是指定爲 true,則方法調用後將當即清空全部緩存
@CacheEvict(key ="#p0",allEntries=true)
@Delete("delete from user where id=#{id}")
void deleteById(@Param("id")String id);
}
複製代碼
@Cacheable
將查詢結果緩存到redis中,(key="#p0")指定傳入的第一個參數做爲redis的key。
@CachePut
,指定key,將更新的結果同步到redis中
@CacheEvict
,指定key,刪除緩存數據,allEntries=true,方法調用後將當即清除緩存
要注意,redis在5.0版本之後不支持Jedis
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
複製代碼
@Data
@Component
@ConfigurationProperties(prefix="redis")
public class RedisConfig {
private String host;
private int port;
private int timeout;//秒
private String password;
private int poolMaxTotal;
private int poolMaxIdle;
private int poolMaxWait;//秒
}
複製代碼
@Service
public class RedisPoolFactory {
@Autowired
RedisConfig redisConfig;
@Bean
public JedisPool edisPoolFactory() {
JedisPoolConfig poolConfig = new JedisPoolConfig();
poolConfig.setMaxIdle(redisConfig.getPoolMaxIdle());
poolConfig.setMaxTotal(redisConfig.getPoolMaxTotal());
poolConfig.setMaxWaitMillis(redisConfig.getPoolMaxWait() * 1000);
JedisPool jp = new JedisPool(poolConfig, redisConfig.getHost(), redisConfig.getPort(),
redisConfig.getTimeout()*1000, redisConfig.getPassword(), 0);
return jp;
}
}
複製代碼
Springboot監控中心是幹什麼的呢?他是針對微服務的 服務狀態、Http請求資源進行監控,能夠看到服務器內存變化(堆內存、線程、日誌管理),能夠檢測服務配置鏈接地址是否可用(模擬訪問,懶加載),能夠統計有多少Bean有什麼單例多例,能夠統計SpringMVC有多少@RequestMapping
Actuator是spring boot的一個附加功能,可幫助你在應用程序生產環境時監視和管理應用程序。
可使用HTTP的各類請求來監管,審計,收集應用的運行狀況.返回的是json
缺點:沒有可視化界面。
在springboot2.0中,Actuator的端點(endpoint)如今默認映射到/application,好比,/info 端點如今就是在/application/info。但你可使用management.context-path來覆蓋此默認值。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
複製代碼
# Actuator 經過下面的配置啓用全部的監控端點,默認狀況下,這些端點是禁用的;
management:
endpoints:
web:
exposure:
include: "*"
spring:
profiles:
active: prod
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/test
username: root
password: 123456
複製代碼
經過actuator/+端點名就能夠獲取相應的信息。
路徑 | 做用 |
---|---|
/actuator/beans | 顯示應用程序中全部Spring bean的完整列表。 |
/actuator/configprops | 顯示全部配置信息。 |
/actuator/env | 陳列全部的環境變量。 |
/actuator/mappings | 顯示全部@RequestMapping的url整理列表。 |
/actuator/health | 顯示應用程序運行情況信息 up表示成功 down失敗 |
/actuator/info | 查看自定義應用信息 |
Admin-UI底層使用actuator,實現監控信息 的界面
<!--服務端-->
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-server</artifactId>
<version>2.0.0</version>
</dependency>
<!--客戶端-->
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-client</artifactId>
<version>2.0.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.jolokia</groupId>
<artifactId>jolokia-core</artifactId>
</dependency>
<dependency>
<groupId>com.googlecode.json-simple</groupId>
<artifactId>json-simple</artifactId>
<version>1.1</version>
複製代碼
//服務端
spring:
application:
name: spring-boot-admin-server
//客戶端
spring:
boot:
admin:
client:
url: http://localhost:8080
server:
port: 8081
management:
endpoints:
web:
exposure:
include: "*"
endpoint:
health:
show-details: ALWAYS
複製代碼
默認狀況下,咱們會使用 @SpringBootApplication
註解來自動獲取應用的配置信息,但這樣也會給應用帶來一些反作用。使用這個註解後,會觸發自動配置( auto-configuration )和 組件掃描 ( component scanning ),這跟使用 @Configuration
、@EnableAutoConfiguration
和 @ComponentScan
三個註解的做用是同樣的。這樣作給開發帶來方便的同時,也會有三方面的影響:
一、會致使項目啓動時間變長。當啓動一個大的應用程序,或將作大量的集成測試啓動應用程序時,影響會特別明顯。
二、會加載一些不須要的多餘的實例(beans)。
三、會增長 CPU 消耗。
針對以上三個狀況,咱們能夠移除 @SpringBootApplication 和 @ComponentScan 兩個註解來禁用組件自動掃描,而後在咱們須要的 bean 上進行顯式配置。
參數名稱 | 含義 | 默認值 | |
---|---|---|---|
-Xms | 初始堆大小 | 物理內存的1/64(<1GB) | 默認(MinHeapFreeRatio參數能夠調整)空餘堆內存小於40%時,JVM就會增大堆直到-Xmx的最大限制. |
-Xmx | 最大堆大小 | 物理內存的1/4(<1GB) | 默認(MaxHeapFreeRatio參數能夠調整)空餘堆內存大於70%時,JVM會減小堆直到 -Xms的最小限制 |
-Xmn | 年輕代大小(1.4or lator) | 注意:此處的大小是(eden+ 2 survivor space).與jmap -heap中顯示的New gen是不一樣的。 整個堆大小=年輕代大小 + 年老代大小 + 持久代大小. 增大年輕代後,將會減少年老代大小.此值對系統性能影響較大,Sun官方推薦配置爲整個堆的3/8 | |
-XX:NewSize | 設置年輕代大小(for 1.3/1.4) | ||
-XX:MaxNewSize | 年輕代最大值(for 1.3/1.4) | ||
-XX:PermSize | 設置持久代(perm gen)初始值 | 物理內存的1/64 | |
-XX:MaxPermSize | 設置持久代最大值 | 物理內存的1/4 | |
-Xss | 每一個線程的堆棧大小 | JDK5.0之後每一個線程堆棧大小爲1M,之前每一個線程堆棧大小爲256K.更具應用的線程所需內存大小進行 調整.在相同物理內存下,減少這個值能生成更多的線程.可是操做系統對一個進程內的線程數仍是有限制的,不能無限生成,經驗值在3000~5000左右 通常小的應用, 若是棧不是很深, 應該是128k夠用的 大的應用建議使用256k。這個選項對性能影響比較大,須要嚴格的測試。(校長) 和threadstacksize選項解釋很相似,官方文檔彷佛沒有解釋,在論壇中有這樣一句話:"」 -Xss is translated in a VM flag named ThreadStackSize」 通常設置這個值就能夠了。 | |
-XX:ThreadStackSize | Thread Stack Size | (0 means use default stack size) [Sparc: 512; Solaris x86: 320 (was 256 prior in 5.0 and earlier); Sparc 64 bit: 1024; Linux amd64: 1024 (was 0 in 5.0 and earlier); all others 0.] | |
-XX:NewRatio | 年輕代(包括Eden和兩個Survivor區)與年老代的比值(除去持久代) | -XX:NewRatio=4表示年輕代與年老代所佔比值爲1:4,年輕代佔整個堆棧的1/5 Xms=Xmx而且設置了Xmn的狀況下,該參數不須要進行設置。 | |
-XX:SurvivorRatio | Eden區與Survivor區的大小比值 | 設置爲8,則兩個Survivor區與一個Eden區的比值爲2:8,一個Survivor區佔整個年輕代的1/10 | |
-XX:LargePageSizeInBytes | 內存頁的大小不可設置過大, 會影響Perm的大小 | =128m | |
-XX:+UseFastAccessorMethods | 原始類型的快速優化 | ||
-XX:+DisableExplicitGC | 關閉System.gc() | 這個參數須要嚴格的測試 | |
-XX:MaxTenuringThreshold | 垃圾最大年齡 | 若是設置爲0的話,則年輕代對象不通過Survivor區,直接進入年老代. 對於年老代比較多的應用,能夠提升效率.若是將此值設置爲一個較大值,則年輕代對象會在Survivor區進行屢次複製,這樣能夠增長對象再年輕代的存活 時間,增長在年輕代即被回收的機率 該參數只有在串行GC時纔有效. | |
-XX:+AggressiveOpts | 加快編譯 | ||
-XX:+UseBiasedLocking | 鎖機制的性能改善 | ||
-Xnoclassgc | 禁用垃圾回收 | ||
-XX:SoftRefLRUPolicyMSPerMB | 每兆堆空閒空間中SoftReference的存活時間 | 1s | softly reachable objects will remain alive for some amount of time after the last time they were referenced. The default value is one second of lifetime per free megabyte in the heap |
-XX:PretenureSizeThreshold | 對象超過多大是直接在舊生代分配 | 0 | 單位字節 新生代採用Parallel Scavenge GC時無效 另外一種直接在舊生代分配的狀況是大的數組對象,且數組中無外部引用對象. |
-XX:TLABWasteTargetPercent | TLAB佔eden區的百分比 | 1% | |
-XX:+CollectGen0First | FullGC時是否先YGC | false |
輸入 -XX:+PrintGCDetails 是爲了在控制檯顯示回收的信息
進入對應jar的目錄,在CMD輸入java -server -Xms32m -Xmx32m -jar springboot.jar
Undertow 是一個採用 Java 開發的靈活的高性能 Web 服務器,提供包括阻塞和基於 NIO 的非堵塞機制。Undertow 是紅帽公司的開源產品,是 JBoss默認的 Web 服務器。👇
首先,從依賴信息裏移除 Tomcat 配置
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<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>
複製代碼
見👉Spring Boot Memory Performance
熱部署,就是在應用程序在不中止的狀況下,自動實現新的部署
使用類加載器classroad來檢測字節碼文件,而後從新加載到jvm內存中
第一步:檢測本地.class
文件變更(版本號,修改時間不同)
第二步:自動監聽,實現部署
本地開發時,能夠提升運行環境
spring-boot-devtools 是一個爲開發者服務的一個模塊,其中最重要的功能就是自動應用代碼更改到最新的App上面去
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
<scope>true</scope>
</dependency>
複製代碼
1.使用mvn clean package 打包
2.使用java –jar 包名
1.使用mvn celan package 打包
2.使用java –jar 包名
1.使用mvn celan package 打包
2.將war包 放入到tomcat webapps下運行便可。
注意:springboot2.0內置tomcat8.5.25,建議使用外部Tomcat9.0版本運行便可,不然報錯版本不兼容。
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<maimClass>com.itmayiedu.app.App</maimClass>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
複製代碼
Spring For All 社區 Spring 官方教程翻譯
感謝以上大大們~!
廣告時間:想要了解更多精彩新姿式?請訪問個人博客