Недавно я изучил принцип Springboot 😋 довольно полезно, теперь позвольте мне поделиться тем, как использовать Springboot~
Хотите разблокировать больше новых поз? Пожалуйста, посетитемой блог
Что такое Спрингбут
В отличие от того, что я понимаю в книге, я думаю, что Springboot является отличной средой быстрого построения.Он интегрирует множество сторонних инструментов, добавляя зависимости через наследование maven, что позволяет избежать различных проблемных конфигураций.Есть различные встроенные контейнеры для упрощения веб-проектов. Он также может избежать вмешательства зависимостей.Он имеет встроенные контейнеры tomcat и jetty и использует java-приложение для запуска программы вместо традиционного способа запуска войны в контейнерах, таких как tomcat.
Отличие от JFinal
JFinal — это фреймворк web + orm, созданный китайцами.JFinal, преимуществами являются быстрая разработка, меньше кода, легкость в освоении, мощность, легкость и простота расширения. Суть в предельной простоте. У него нет поддержки коммерческих структур, поэтому публичность не на месте и мало кто об этом знает.
Самым большим преимуществом Springboot по сравнению с JFinal является то, что он поддерживает множество функций, что может быть очень удобно для интеграции различных фреймворков Spring, таких как springframework, spring-mvc, spring-security, spring-data-jpa, spring-cache и т. д. , Автоматическая настройка и экология относительно хороши, многие продукты имеют некоторую поддержку Springboot.
Отличие от Springcloud
Можно понять, что Springboot содержит Springcloud, а Springcloud — это просто компонент Springboot.
Springcloud предоставляет довольно полную микросервисную архитектуру. Микросервисная архитектура по сути является распределенной архитектурой, а это значит, что исходный проект нужно разбить на небольшие проекты, а затем использовать какой-то механизм для их объединения, например управление сервисом, коммуникационную структуру и т. д. инфраструктуру.
Разница между SpringBoot и SpringMVC
Веб-компоненты SpringBoot по умолчанию интегрированы с инфраструктурой SpringMVC.
быстрый в использовании
Если хотите посмотреть вниз, обратите внимание👇
- Для Springboot 2.x требуется среда JDK 1.8 и выше. Кроме того, Springboot 2.x совместим только с Spring Framework 5.0 и выше.
- Соответствующим инструментом сборки зависимостей, предоставляемым для Springboot 2.x, является Maven, для которого требуется версия 3.2 и выше. Для использования Gradle требуется версия 1.12 и выше.
- Рекомендуется использовать IntelliJ IDEA IntelliJ IDEA (далее IDEA)
создать проект
Я не использовал Eclipse в течение длительного времени.Вы должны знать, что Eclipse создается путем создания проекта maven и введения зависимостей Springboot.
Ниже я поделюсь методом создания Springboot с помощью IDEA.
Это очень просто, вы можете создать Springboot в этом интерфейсе. Затем добавьте некоторые компоненты.
Готово!
написать демо
Здесь я использую проект шипа, который я написал в качестве эталонного каштана.Убить их всех
Создайте пакет контроллера и напишите образец столбца.
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/ в браузере, чтобы запустить его!
SpringApplication.run
Springboot идентифицирует его как класс запуска и использует его для запуска проекта Springboot.
Основное объяснение аннотации
@RestController
Добавление RestController к вышеперечисленному означает, что все методы контроллера изменены для возврата в формате JSON, а интерфейс Restful может быть написан напрямую. эквивалентно@Controller
+@ResponseBody
это осознание
@SpringBootApplication
Используется при запуске Springboot, эквивалентно@ComponentScan
+@EnableAutoConfiguration
+@Configuration
@ComponentScan("cn.tengshe789.controller")
Контроллер сканирует диапазон пакетов.
@EnableAutoConfiguration
Это позволяет Spring Boot автоматически настраивать Spring Framework на основе зависимостей, объявленных нашим приложением. Это означает, что spring-boot-starter-web, добавленный при создании проекта, добавляет Tomcat и Spring MVC, поэтому автоматическая настройка предполагает, что вы разрабатываете веб-приложение и соответствующим образом настроили Spring.
конфигурационный файл
properties
правило:
1. Использование заглавных букв в имени более стандартизировано.
2. = Не используйте пробелы с обеих сторон
3. Не ставьте точку с запятой после написания пары имя-значение
специальные параметры
name=tengshe789
Конфигурация с несколькими средами
spring.profiles.active=pre
application-dev.properties:开发环境
application-test.properties:测试环境
application-prod.properties:生产环境
Изменить номер порта
server.port=8888
server.context-path=/tengshe789
yaml
правило:
- Используйте отступ пробела для обозначения слоев.Для отступа между разными уровнями можно использовать разное количество пробелов, но элементы одного и того же слоя должны быть выровнены по левому краю, то есть количество пробелов перед ними одинаково (табуляция не может быть используется, и количество пробелов, соответствующих каждой системной вкладке, может быть разным, что приводит к путанице уровней)
- '#' означает комментарии, только однострочные комментарии, от начала # до конца строки
- Дефис, за которым следует пробел (тире и пробел), указывает на список
- Используйте двоеточия и пробелы для представления пар ключ-значение ключ: значение
- Простые данные (скаляры, скалярные данные) можно заключать без кавычек, включая строковые данные. Данные, заключенные в одинарные или двойные кавычки, обрабатываются как строковые данные, а escape-символы в стиле C используются в одинарных или двойных кавычках.
server:
port: 8080
context-path: /springboot
xml
Springboot официально не рекомендует xml, слегка
веб-разработка
Проект с использованием Springboot, по всей вероятности, используется для веб-разработки. Сначала давайте посмотрим, как Springboot может быстро разрабатывать веб-приложения.
Как получить доступ к статическим ресурсам
Пожалуйста, создайте статическую папку в каталоге ресурсов и поместите туда статический ресурс.
Каталог: 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. Конечно, этот путь также можно изменить.Как его изменить, можно запросить и изменить в свойствах конфигурации каждого механизма шаблонов.
Лист тимьяна (тимус)
Здесь я все еще использую проект seckill, который я написал в качестве эталонного каштана.Убить их всех
POM
<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/, новый суффикс веб-страницы *.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>
Фримаркер
POM
<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/, новый суффикс веб-страницы *.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>
JSP
Не рекомендуется интегрировать JSP со Springboot.Если хотите, то он должен быть типа war, иначе страница не будет найдена.И не храните JSP-страницу в ресурсах// jsp недоступен
POM
<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/, новый суффикс веб-страницы — *.jsp.
@Controller
public class IndexController {
@RequestMapping("/index")
public String index() {
return "index";
}
}
стойка регистрации
немного 😝
Потоковое программирование
Чтобы понять WebFlux, сначала поймите, что такое реактивное реактивное (реактивное, асинхронное, ориентированное на поток) программирование, это новый стиль программирования, который характеризуется асинхронным или параллельным, управляемым событиями, механизмом push PUSH и производным от режима наблюдателя. Реактивные приложения (реактивные приложения) позволяют разработчикам создавать управляемые событиями, масштабируемые, эластичные реактивные системы: обеспечивая высокочувствительное взаимодействие с пользователем в режиме реального времени, масштабируемость и эластичную поддержку стека приложений, готовые к развертыванию в многоядерных и облачных вычислительных архитектурах.
Spring Webflux
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 (неблокирующий 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 Web MVC -> Spring Data
- Spring WebFlux -> Spring Data Reactive
Если вы используете Spring Data Reactive, исходное управление транзакциями Spring для Spring Data (JDBC и т. д.) не будет работать. Поскольку исходное управление транзакциями Spring (Spring Data JPA) основано на ThreadLocal для передачи транзакций, его сущность основана на модели блокирующего ввода-вывода, а не асинхронной.
А вот Reactive обязательно должен быть асинхронным, и ThreadLocal в разных потоках значения точно не получит. Естественно, мы должны думать о том, как использовать реактивное программирование для достижения транзакций.Одним из способов является метод обратного вызова, который всегда передаетсяconn :newTransaction(conn ->{})
Поскольку каждая операция базы данных также является асинхронной, соединение не может быть передано ThreadLocal в реактивном программировании и может быть передано только в параметре. Хотя будут определенные вторжения строк кода. Кроме того, сопрограммы kotlin также можно использовать для достижения прозрачного управления транзакциями, то есть поместить conn в локальные переменные сопрограммы. Тогда Spring Data Reactive Repositories не поддерживает MySQL, а также не поддерживает транзакции MySQL, что мне делать?
Ответ заключается в том, что этот вопрос на самом деле связан с первым вопросом. Почему не поддерживается MySQL, то есть не поддерживается JDBC. Вы можете видеть, что JDBC принадлежит Spring Data. Таким образом, вы можете подождать, пока репозитории Spring Data Reactive Repositories обновят модель ввода-вывода для поддержки MySQL. Выше также можно упомянуть, как использовать реактивное программирование для поддержки транзакций.
Если приложение может использовать только транзакции данных, которые не сильно зависят от данных, и по-прежнему использовать 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 для определения HTTP-маршрутов RESTful.
Пожалуйста, обратитесь кРазговор о Spring Boot 2.x
@Async
Когда вам нужно выполнить асинхронный метод, добавьте его в метод@Async
После этого нижний слой использует технологию многопоточности. начать плюс нужно@EnableAsync
доступ к данным
Интеграция шаблона Jdbc
Для этого требуется, чтобы версия spring-boot-starter-parent была выше 1.5.
POM
<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
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);
}
}
Интеграция Mybatis
Здесь я использую проект шипа, который я написал в качестве эталонного каштана.Убить их всех
POM
<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
За кулисами
Создайте Дао (код 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
public class GoodsService {
@Autowired
GoodsDao goodsDao;
/*
* 展示商品列表
*/
public List<GoodsVo> listGoodsVo() {
return goodsDao.listGoodsVo();
}
}
Встроенный в Mybatis плагин подкачки PageHelper
PageHelper — это простой в использовании бесплатный сторонний плагин физического пейджинга Mybatis с открытым исходным кодом.
POM
<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;
}
}
Интеграция SpringJPA
spring-data-jpa три шага:
- Объявите интерфейс уровня сохраняемости, который наследует репозиторий (или подинтерфейс репозитория, который определяет некоторые общие методы добавления, удаления, изменения и пейджинга).
- Объявите необходимые бизнес-методы в интерфейсе. Spring Data сгенерирует код реализации на основе заданной стратегии.
- Добавьте строку объявления в файл конфигурации Spring, чтобы позволить Spring создать прокси-объект для объявленного интерфейса. настроенjpa:repositoriesПосле этого, когда Spring инициализирует контейнер, он просканирует каталог пакета и его подкаталоги, указанные базовым пакетом, создаст прокси-объекты для интерфейсов, которые наследуют репозиторий или его подинтерфейсы, и зарегистрирует прокси-объекты как Spring Beans, чтобы бизнес-уровень могут автоматически инкапсулированные свойства использовать объект напрямую.
Подробности:Официальный сайт JPA
POM
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
конфигурационный файл
Springboot по умолчанию использует спящий режим как реализацию 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
код
Domain
@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
будет отсканировано и загружено весной,
@Id
Аннотация к первичному ключу
@Column name="call_phone"
Относится к имени поля базы данных, соответствующему полю, если оно совпадает, его не нужно определять. Интервал подчеркивания базы данных рассматривается в коде так же, как и метод верблюжьего регистра.Например, поле базы данных create_time эквивалентно createTime в классе Java, поэтому его не нужно аннотировать с помощью @Column.
Слой Дао
На этом этапе вам нужно унаследовать интерфейс репозитория~
public interface UserDao extends JpaRepository<User, Integer> {
}
Controller
@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.
Dao
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")
управление транзакциями
Как управлять вещами, просто, смотреть вниз.
декларативная сделка
Найдите класс реализации сервиса, добавьте@Transactional
Просто отметьте это@Transactional
Аннотация отorg.springframework.transaction.annotation
пакет , не изjavax.transaction
. и@Transactional
Не только на методы, но и на классы. При аннотации к классу это означает, что все общедоступные методы класса являются транзакционными. Если используются как уровень класса, так и уровень метода@Transactional
аннотации, использование аннотаций на уровне класса переопределит аннотации на уровне метода.
Примечание. Springboot предоставляет@EnableTransactionManagement
Аннотация к классу конфигурации для включения поддержки декларативных транзакций. аннотация@EnableTransactionManagement
По умолчанию она включена, если вы хотите отключить управление транзакциями, вы должны изменить эту аннотацию на false при входе в программу.
Распределенное управление транзакциями
Что такое распределенная транзакция?Например, когда мы выполняем бизнес-логику, у нас есть два шага для работы с источником данных A и источником данных B. Когда мы выполняем изменения данных в источнике данных A, возникает исключение времени выполнения, когда B источник данных выполняется. , то мы должны откатить операцию источника данных B и откатить операцию источника данных A. Такая ситуация часто возникает в платежном бизнесе.Например, бизнес по покупке билетов в конце не платит, и все предыдущие операции приходится откатывать.Если предыдущие операции распределены по нескольким источникам данных, то это типичная распределенная транзакция откат
Поймите, что такое распределенная транзакция, тогда решение распределенной транзакции в java - это JTA (т.е. Java Transaction API).
Springboot официально предоставляетAtomikos,Bitronix,Narayanaизменеджер транзакций класса
менеджер по транзакциям класса Атомикос
POM
<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
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()));
}
}
Cron-выражения@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
Quartz
POM
<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, чтобы вторая задача была отложена позже, а вторая задача выполнялась только после завершения первой задачи.
управление журналом
log4j
POM
<!-- 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);
Унифицированная обработка журналов веб-запросов с использованием АОП
POM
<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);
}
}
ломбок плагин
очень простой способ
POM
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.0</version>
</dependency>
код
добавлен класс@Slf4j
Просто аннотируйте. Использование заключается в непосредственном вводе глобальной переменной журнала.
Другое использование Ломбока
@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
перехватчик
Перехватчики используются в АОП (аспектно-ориентированном программировании) для перехвата метода или поля перед доступом к ним, а затем добавления определенных операций до или после него. Перехват — это стратегия реализации АОП.
(1) Перехватчики основаны на механизме отражения Java, а фильтры основаны на обратных вызовах функций.
(2) Перехватчик не зависит от контейнера сервлета, а фильтр зависит от контейнера сервлета.
(3) Перехватчики могут работать только с запросами контроллера, тогда как фильтры могут работать почти со всеми запросами.
(4) В жизненном цикле контроллера перехватчик можно вызывать несколько раз, а фильтр можно вызывать только один раз при инициализации контейнера.
Есть разница между фильтром и перехватчиком.Подробности, их порядок выполнения: сначала фильтр, затем перехватчик
-> Сценарии применения фильтра: установка кодированных символов, фильтрация символов надписи
-> Сценарий приложения 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("/*");
};
};
}
}
Создайте перехватчик фиктивного входа в систему, чтобы проверить, имеет ли запрос параметр токена.
@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
EhCache
POM
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
Создайте новый файл ehcache.xml
<?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
: Если объект постоянно действителен, после установки тайм-аут не будет работать.
timeToIdleSeconds
: Установите допустимое время простоя (единица измерения: секунды) объекта до истечения срока его действия. только если внутренний=falseОбъект не используется постоянно, необязательный атрибут, значение по умолчанию равно 0, то есть время простоя бесконечно.
timeToLiveSeconds
: Установите допустимое время (единица измерения: секунды), в течение которого объект будет жить до истечения срока его действия. Максимальное время находится между временем создания и временем истечения срока действия. только если внутренний=falseИспользуется, когда объект не является постоянно действительным.По умолчанию 0. То есть время существования объекта бесконечно.
overflowToDisk
: когда количество объектов в памяти достигает maxElementsInMemory, Ehcache записывает объекты на диск.
diskSpoolBufferSizeMB
: Этот параметр задает размер области кеша DiskStore (дискового кеша). По умолчанию 30 МБ. У каждого кэша должен быть свой буфер.
maxElementsOnDisk
: максимальное количество кэшей жесткого диска.
diskPersistent
: сохраняется ли дисковое хранилище между перезапусками виртуальной машины.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
Просто
Redis
Подключиться с помощью собственного диска
Подключиться с помощью RedisTemplate
POM
<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);
}
}
Dao
@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.
@CachePut
, укажите ключ и синхронизируйте обновленный результат с redis
@CacheEvict
, указать ключ, удалить кешированные данные, allEntries=true, кеш будет очищен сразу после вызова метода
Подключиться с помощью джедаев
Следует отметить, что Redis не поддерживает Jedis после версии 5.0.
POM
<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, может видеть изменения в памяти сервера (память кучи, потоки, управление журналами) и может определять, доступен ли адрес подключения конфигурации службы (имитация доступа, отложенная загрузка). иметь один экземпляр и несколько экземпляров, вы можете подсчитать, сколько @RequestMapping SpringMVC имеет
Actuator
Actuator — это дополнительная функция весенней загрузки, которая помогает вам отслеживать и управлять вашим приложением в производственной среде.
Вы можете использовать различные HTTP-запросы для мониторинга, аудита и сбора данных о работе приложения.
Минусы: Нет визуального интерфейса.
В springboot 2.0 конечная точка Actuator теперь по умолчанию сопоставляется с /application, например, конечная точка /info теперь /application/info. Но вы можете использовать management.context-path, чтобы переопределить это значение по умолчанию.
POM
<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/beans | Отображает полный список всех компонентов Spring в приложении. |
/actuator/configprops | Отображает всю информацию о конфигурации. |
/actuator/env | Перечислите все переменные среды. |
/actuator/mappings | Отображает кураторский список URL-адресов для всех @RequestMappings. |
/actuator/health | Отображение информации о работоспособности приложения вверх означает успех вниз отказ |
/actuator/info | Просмотр информации о пользовательском приложении |
Центр мониторинга распределенных микросервисов с пользовательским интерфейсом администратора
Нижний уровень Admin-UI использует привод для реализации интерфейса информации мониторинга.
POM
<!--服务端-->
<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>
файл конфигурации application.yml
//服务端
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
Annotation для автоматического получения информации о конфигурации приложения, но это также приведет к некоторым побочным эффектам для приложения. После использования этой аннотации она вызовет автоконфигурацию (auto-configuration) и сканирование компонентов (component scan), что аналогично использованию@Configuration
,@EnableAutoConfiguration
и@ComponentScan
Три аннотации имеют одинаковый эффект. Хотя это упрощает разработку, это также будет иметь три последствия:
1. Это приведет к увеличению времени запуска проекта. Влияние особенно заметно при запуске большого приложения или при запуске приложения, которое будет выполнять много интеграционного тестирования.
2. Будут загружены некоторые ненужные избыточные экземпляры (бины).
3. Это увеличит потребление процессора.
Для трех вышеперечисленных случаев мы можем удалить аннотации @SpringBootApplication и @ComponentScan, чтобы отключить автоматическое сканирование компонентов, а затем явно настроить их на нужных нам bean-компонентах.
Настройка параметров SpringBoot JVM
различные параметры
имя параметра | значение | По умолчанию | |
---|---|---|---|
-Xms | начальный размер кучи | 1/64 физической памяти ( | По умолчанию (параметр MinHeapFreeRatio можно настроить), когда свободная память кучи меньше 40%, JVM будет увеличивать кучу до максимального предела -Xmx. |
-Xmx | максимальный размер кучи | 1/4 физической памяти ( | По умолчанию (параметр MaxHeapFreeRatio можно настроить), когда свободная память кучи больше 70%, JVM уменьшит кучу до минимального предела -Xms |
-Xmn | Размер молодого поколения (1.4 или позже) | Примечание: Размер здесь (eden + 2 места для выживших) отличается от нового поколения, показанного в jmap -heap. Размер всей кучи = размер молодого поколения + размер старого поколения + размер постоянного поколения.После увеличения молодого поколения размер старого поколения будет уменьшен.Это значение оказывает большое влияние на производительность системы, и Sun официально рекомендует ставить до 3 для всей кучи. /8 | |
-XX:NewSize | Установить размер молодого поколения (для 1.3/1.4) | ||
-XX:MaxNewSize | Максимум молодого поколения (для 1.3/1.4) | ||
-XX:PermSize | Установите начальное значение постоянной генерации (perm gen) | 1/64 физической памяти | |
-XX:MaxPermSize | Установить максимальное постоянное поколение | 1/4 физической памяти | |
-Xss | размер стека на поток | После JDK5.0 размер стека каждого потока составляет 1 М. Ранее размер стека каждого потока составлял 256 КБ. Размер памяти, необходимый для большего количества потоков приложений, можно регулировать. При той же физической памяти уменьшение этого значения может привести к созданию большего количества потоков. .Однако операционная система по-прежнему имеет ограничение на количество потоков в процессе, которое не может генерироваться бесконечно.Значение опыта обычно составляет около 3000~5000 для небольших приложений.Если стек не очень глубокий, 128 КБ должно быть достаточно. для больших приложений рекомендуется использовать 256k. Этот параметр сильно влияет на производительность и требует тщательного тестирования. (Принципиальный) Объяснение параметра threadstacksize очень похожее.Официальный документ вроде не объясняет.На форуме есть такое предложение: ""-Xss переводится в флаг ВМ с именем 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 | Отношение молодого поколения (включая Эдем и два региона Выживших) к старому поколению (исключая постоянное поколение) | -XX:NewRatio=4 означает, что соотношение между молодым поколением и старым поколением составляет 1:4, а на молодое поколение приходится 1/5 всего стека, при установке Xms=Xmx и Xmn этот параметр не необходимо установить. | |
-XX:SurvivorRatio | Отношение размера области Эдема к площади Выжившего | Если установлено значение 8, соотношение двух областей Выживших к одной области Эдема составляет 2:8, а на одну область Выживших приходится 1/10 всего молодого поколения. | |
-XX:LargePageSizeInBytes | Размер страницы памяти нельзя ставить слишком большим, это повлияет на размер перми | =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 | Unit byte Новое поколение недопустимо при использовании Parallel Scavenge GC.Другая ситуация, которая непосредственно выделяется в старом поколении, — это большой объект массива, и в массиве нет внешних объектов ссылки. |
-XX:TLABWasteTargetPercent | TLAB в процентах от округа Эдем | 1% | |
-XX:+CollectGen0First | Запускать ли YGC в FullGC | false |
Стратегия настройки
- Начальная память кучи такая же, как максимальная куча
- Уменьшить количество сборок мусора
Внутренний тюнинг
Введите -XX:+PrintGCDetails, чтобы отобразить переработанную информацию в консоли.
Внешний тюнинг
Войдите в каталог соответствующей банки и введите ее в CMDjava -server -Xms32m -Xmx32m -jar springboot.jar
Используйте инструмент java visual vm
Используйте инструмент Java-консоли
Изменить контейнер сервлетов с Tomcat на Undertow
Undertow — это гибкий, высокопроизводительный веб-сервер, разработанный на Java, который обеспечивает как блокирующие, так и неблокирующие механизмы на основе NIO. Undertow — это продукт Red Hat с открытым исходным кодом, который является веб-сервером по умолчанию для JBoss. 👇
POM
Сначала удалите конфигурацию 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>
Затем добавьте отлив:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-undertow</artifactId>
</dependency>
Оптимизация Tomcat
см. 👉Spring Boot Memory Performance
горячее развертывание
Горячее развертывание заключается в автоматическом внедрении новых развертываний без остановки приложения.
принцип
Используйте загрузчик классов classroad для обнаружения файлов байт-кода, а затем перезагрузите их в память jvm.
Шаг 1. Обнаружение локального.class
Изменения файла (номер версии, время модификации отличается)
Шаг 2. Автоматический мониторинг и развертывание
Сценарии применения
При локальной разработке среда выполнения может быть улучшена
Dev-tools
spring-boot-devtools — это модуль для разработчиков, самая важная функция которого — автоматическое применение изменений кода к последнему приложению.
POM
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
<scope>true</scope>
</dependency>
принцип
- Devtools будет отслеживать изменения файлов в пути к классам и немедленно перезапускать приложение (во время сохранения), из-за используемого механизма виртуальной машины перезапуск выполняется очень быстро.
- Devtools может обеспечить развертывание горячей страницы (то есть страница вступит в силу сразу после модификации, чего можно добиться, настроив spring.thymeleaf.cache=false непосредственно в файле application.properties (примечание: разные конфигурации шаблонов отличаются)
выпуск пакета
Упаковка баночного типа
1. Используйте mvn clean package для упаковки
2. Используйте имя пакета java –jar
Упаковка военного типа
1. Используйте пакет mvn celan для упаковки
2. Используйте имя пакета java –jar
Работа внешнего Tomcat
1. Используйте пакет mvn celan для упаковки
2. Поместите военный пакет в веб-приложения tomcat и запустите его.
Примечание: Springboot2.0 имеет встроенный tomcat8.5.25, для запуска рекомендуется использовать внешнюю версию Tomcat9.0, в противном случае версия с ошибкой несовместима.
POM
<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>
использованная литература
Плагин подкачки SpringBoot PageHelper
Spring For All Community Spring Официальный перевод учебника
SpringBoot использует кеш Redis
Простое использование Spring Boot Admin
Оптимизация производительности Spring Boot
Спасибо всем выше~!
Рекламная пауза: Хотите узнать больше о новых крутых позах? Пожалуйста, посетитемой блог