最近再研究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 官方教程翻译
感谢以上大大们~!
广告时间:想要了解更多精彩新姿式?请访问个人博客