最近再研究springboot的原理��颇有收获,现在让我分享一下springboot如何使用吧~

想要解锁更多新姿势?请访问我的博客

啥是Springboot

和书上理解的不同,我认为Springboot是一个优秀的快速搭建框架,他通过maven继承方式添加依赖来整合很多第三方工具,可以避免各种麻烦的配置,有各种内嵌容器简化Web项目,还能避免依赖的干扰,它内置tomcat,jetty容器,使用的是java app运行程序,而不是传统的用把war放在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的Web组件,默认集成的是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依赖创建的。

下面我分享一下用IDEA创建Springboot的方法。

1533536250534

很简单,在这个界面里面就可以创建Springboot了。接下来在添加一些组件。

1533536423232

大功告成!

写一个DEMO

这里用我写的一个秒杀项目作为参考栗子。秒杀商城

创建一个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/,就可以启动了!

SpringApplication.run

Springboot将他标识为启动类,用它启动Springboot项目

基础注解解释

@RestController

在上加上RestController 表示修饰该Controller所有的方法返回JSON格式,直接可以编写Restful接口。就相当于@Controller+@ResponseBody这种实现

@SpringBootApplication

用在启动Springboot中,相当于@ComponentScan+@EnableAutoConfiguration+@Configuration

@ComponentScan(“cn.tengshe789.controller”)

控制器扫包范围。

@EnableAutoConfiguration

他让 Spring Boot 根据咱应用所声明的依赖来对 Spring 框架进行自动配置。意思是,创建项目时添加的spring-boot-starter-web添加了Tomcat和Spring MVC,所以auto-configuration将假定你正在开发一个web应用并相应地对Spring进行设置。

配置文件

properties

规则:

1、名用大写比较规范

2、=两边别打空格

3、名值对写完后别打分号

自定义参数

name=tengshe789

多环境配置

spring.profiles.active=preapplication-dev.properties:开发环境
application-test.properties:测试环境
application-prod.properties:生产环境

修改端口号

server.port=8888 
server.context-path=/tengshe789

yaml

规则:

  1. 使用空格 Space 缩进表示分层,不同层次之间的缩进可以使用不同的空格数目,但是同层元素一定左对齐,即前面空格数目相同(不能使用 Tab,各个系统 Tab对应的 Space 数目可能不同,导致层次混乱)
  2. ‘#’表示注释,只能单行注释,从#开始处到行尾
  3. 破折号后面跟一个空格(a dash and space)表示列表
  4. 用冒号和空格表示键值对 key: value
  5. 简单数据(scalars,标量数据)可以不使用引号括起来,包括字符串数据。用单引号或者双引号括起来的被当作字符串数据,在单引号或双引号中使用C风格的转义字符
server:port:  8080context-path: /springboot

xml

Springboot官方不推荐xml,略

Web开发

一个项目用Springboot,十有八九就是用于Web开发。首先让我们看看Springboot怎么快速开发Web把

如何访问静态资源

请在resources目录下创建static文件夹,在该位置放置一个静态资源。

目录:src/main/resources/static

1533537772267

启动程序后,尝试访问http://localhost:8080/img.xxx/。就可以访问了。

关于渲染Web页面

在之前的快速使用的示例中,我们都是通过添加@RestController来处理请求,所以返回的内容为json对象。那么如果需要渲染html页面的时候,要如何实现呢?

模板引擎方法

Springboot依然可以实现动态HTML,并且提供了多种模板引擎的默认配置支持,Springboot官方文档有如下推荐的模板引擎:

· Thymeleaf

· FreeMarker

· Velocity

· Groovy

· Mustache

Springboot官方建议避免使用JSP,若一定要使用JSP将无法实现Spring Boot的多种特性。

在Springboot中,默认的模板配置路径都时:src/main/resources/templates。当然也可以修改这个路径,具体如何修改,可在各模板引擎的配置属性中查询并修改。

Thymeleaf(胸腺)

这里还是用我写的一个秒杀项目作为参考栗子。秒杀商城

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/创建一个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>

Freemarker(自由标记)

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/创建一个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>

JSP

不建议用Springboot整合JSP,要的话一定要为war类型,否则会找不到页面.,而且不要把JSP页面存放在resources// 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/创建一个templates文件夹,新网页后缀为*.jsp

@Controller
public class IndexController {@RequestMapping("/index")public String index() {return "index";}
}

前台

略略略��

异步编程

要了解 WebFlux ,首先了解下什么是Reactive响应式(反应式)编程 ,他是一种新的编程风格,其特点是异步或并发、事件驱动、推送PUSH机制以及观察者模式的衍生。reactive应用(响应式应用)允许开发人员构建事件驱动(event-driven),可扩展性,弹性的反应系统:提供高度敏感的实时的用户体验感觉,可伸缩性和弹性的应用程序栈的支持,随时可以部署在多核和云计算架构。

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 注解方式,另一种是使用其功能性端点方式。

img

WebFlux 支持的容器有 Tomcat、Jetty(Non-Blocking IO API) ,也可以像 Netty 和 Undertow 的本身就支持异步容器。在容器中 Spring WebFlux 会将输入流适配成 Mono 或者 Flux 格式进行统一处理。

POM

官方实例

@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);}
}

Controller层

Spring Boot 2.0 这里有两条不同的线分别是:

  1. Spring Web MVC -> Spring Data
  2. Spring WebFlux -> Spring Data Reactive

如果使用 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 ,可以使用下面的实现,代码如下:

Service 层

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

路由器类 Router

创建一个 Route 类来定义 RESTful HTTP 路由

请参考聊聊 Spring Boot 2.x 那些事儿

@Async

需要执行异步方法时,在方法上加上@Async之后,底层使用多线程技术 。启动加上需要@EnableAsync

数据访问

整合JdbcTemplate

使用这个需要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

@Service
public class UserServiceImpl implements UserService {@Autowiredprivate 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

后台

创建一个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 {@AutowiredGoodsDao 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.xmlmapper-locations:- classpath:cn/tengshe789/dao/*.xml# 分页配置
pagehelper:helper-dialect: mysqlreasonable: truesupport-methods-arguments: trueparams: count=countSql

代码

实体层面
@Data
public class User {private Integer id;private String name;
}
Dao层
public interface UserDao {@Select("SELECT * FROM USERS ")List<User> findUserList();
}
Service层
@Service
public class UserService {@Autowiredprivate 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三个步骤:

  1. 声明持久层的接口,该接口继承 Repository(或Repository的子接口,其中定义了一些常用的增删改查,以及分页相关的方法)。
  2. 在接口中声明需要的业务方法。Spring Data 将根据给定的策略生成实现代码。
  3. 在 Spring 配置文件中增加一行声明,让 Spring 为声明的接口创建代理对象。配置了 后,Spring 初始化容器时将会扫描 base-package 指定的包目录及其子目录,为继承 Repository 或其子接口的接口创建代理对象,并将代理对象注册为 Spring Bean,业务层便可以通过 Spring 自动封装的特性来直接使用该对象。

详情:JPA官方网站

POM

        <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

代码

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会被spring扫描并加载,

@Id注解在主键上

@Column name="call_phone" 指该字段对应的数据库的字段名,如果相同就不需要定义。数据库下划线间隔和代码中的驼峰法视为相同,如数据库字段create_time等价于Java类中的createTime,因此不需要用@Column注解。

Dao层

此时需要继承Repository接口~

public interface UserDao extends JpaRepository<User, Integer> {
}
Controller
@RestController
public class IndexController {@Autowiredprivate 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")@Primarypublic DataSource testDataSource() {return DataSourceBuilder.create().build();}/*** @methodDesc: 功能描述:(test1 sql会话工厂)*/@Bean(name = "test1SqlSessionFactory")@Primarypublic 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")@Primarypublic DataSourceTransactionManager testTransactionManager(@Qualifier("test1DataSource") DataSource dataSource) {return new DataSourceTransactionManager(dataSource);}@Bean(name = "test1SqlSessionTemplate")@Primarypublic 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")

事物管理

怎么进行事物管理呢,简单,往下看。

声明式事务

找到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 的类事务管理器

类事务管理器Atomikos

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 = 123456mysql.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 =123456mysql.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()));}
}

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

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 {@Beanpublic JobDetail uploadTaskDetail() {return JobBuilder.newJob(UploadTask.class).withIdentity("uploadTask").storeDurably().build();}@Beanpublic Trigger uploadTaskTrigger() {CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule("*/5 * * * * ?");return TriggerBuilder.newTrigger().forJob(uploadTaskDetail()).withIdentity("uploadTask").withSchedule(scheduleBuilder).build();}
}

实现类

创建一个配置类,分别制定具体任务类和触发的规则

@Configuration
@DisallowConcurrentExecution
public class UploadTask extends QuartzJobBean {@Resourceprivate TencentYunService tencentYunService;@Overrideprotected 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);

使用AOP统一处理Web请求日志

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);}
}

lombok 插件

非常简单的办法

POM

<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.0</version>
</dependency>

代码

类中添加@Slf4j 注解即可。使用是直接输入log全局变量

Lombok的其他用法

@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 {@Autowiredprivate LoginIntercept loginIntercept;@Beanpublic 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

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:对象是否永久有效,一但设置了,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}")@CacheableUserEntity 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;}@Beanpublic 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的key。

@CachePut,指定key,将更新的结果同步到redis中

@CacheEvict,指定key,删除缓存数据,allEntries=true,方法调用后将立即清除缓存

使用Jedis连接

要注意,redis在5.0版本以后不支持Jedis

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 {@AutowiredRedisConfig redisConfig;@Beanpublic 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

Actuator是spring boot的一个附加功能,可帮助你在应用程序生产环境时监视和管理应用程序。

可以使用HTTP的各种请求来监管,审计,收集应用的运行情况.返回的是json

缺点:没有可视化界面。

在springboot2.0中,Actuator的端点(endpoint)现在默认映射到/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: proddatasource:driver-class-name: com.mysql.jdbc.Driverurl: jdbc:mysql://127.0.0.1:3306/testusername: rootpassword: 123456

Actuator访问路径

通过actuator/+端点名就可以获取相应的信息。

路径作用
/actuator/beans显示应用程序中所有Spring bean的完整列表。
/actuator/configprops显示所有配置信息。
/actuator/env陈列所有的环境变量。
/actuator/mappings显示所有@RequestMapping的url整理列表。
/actuator/health显示应用程序运行状况信息 up表示成功 down失败
/actuator/info查看自定义应用信息

Admin-UI分布式微服务监控中心

Admin-UI底层使用actuator,实现监控信息 的界面

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: 8081management:endpoints:web:exposure:include: "*"endpoint:health:show-details: ALWAYS

性能优化

扫包优化

默认情况下,我们会使用 @SpringBootApplication 注解来自动获取应用的配置信息,但这样也会给应用带来一些副作用。使用这个注解后,会触发自动配置( auto-configuration )和 组件扫描 ( component scanning ),这跟使用 @Configuration@EnableAutoConfiguration@ComponentScan 三个注解的作用是一样的。这样做给开发带来方便的同时,也会有三方面的影响:

1、会导致项目启动时间变长。当启动一个大的应用程序,或将做大量的集成测试启动应用程序时,影响会特别明显。

2、会加载一些不需要的多余的实例(beans)。

3、会增加 CPU 消耗。

针对以上三个情况,我们可以移除 @SpringBootApplication 和 @ComponentScan 两个注解来禁用组件自动扫描,然后在我们需要的 bean 上进行显式配置。

SpringBoot JVM参数调优

各种参数
参数名称含义默认值
-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:ThreadStackSizeThread 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:SurvivorRatioEden区与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的存活时间1ssoftly 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:TLABWasteTargetPercentTLAB占eden区的百分比1%
-XX:+CollectGen0FirstFullGC时是否先YGCfalse
调优策略
  1. 初始化堆内存和最大堆相同
  2. 减少垃圾回收次数
内部调优

1533633207629

输入 -XX:+PrintGCDetails 是为了在控制台显示回收的信息

1533633302622

外部调优

进入对应jar的目录,在CMD输入java -server -Xms32m -Xmx32m  -jar springboot.jar

使用工具java visual vm

1533633302622

使用工具java console

1533633885354

将Servlet容器从Tomcat变成Undertow

Undertow 是一个采用 Java 开发的灵活的高性能 Web 服务器,提供包括阻塞和基于 NIO 的非堵塞机制。Undertow 是红帽公司的开源产品,是 JBoss默认的 Web 服务器。��

Undertow

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>

然后添加 Undertow:

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-undertow</artifactId>
</dependency>

Tomcat 优化

见��Spring Boot Memory Performance

热部署

热部署,就是在应用程序在不停止的情况下,自动实现新的部署

原理

使用类加载器classroad来检测字节码文件,然后重新加载到jvm内存中

第一步:检测本地.class文件变动(版本号,修改时间不一样)

第二步:自动监听,实现部署

应用场景

本地开发时,可以提高运行环境

Dev-tools

spring-boot-devtools 是一个为开发者服务的一个模块,其中最重要的功能就是自动应用代码更改到最新的App上面去

POM

        <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><optional>true</optional><scope>true</scope></dependency>

原理

  1. devtools会监听classpath下的文件变动,并且会立即重启应用(发生在保存时机),因为其采用的虚拟机机制,该项重启是很快的。
  2. devtools可以实现页面热部署(即页面修改后会立即生效,这个可以直接在application.properties文件中配置spring.thymeleaf.cache=false来实现(注意:不同的模板配置不一样)

发布打包

Jar类型打包方式

1.使用mvn clean package 打包

2.使用java –jar 包名

war类型打包方式

1.使用mvn celan package 打包

2.使用java –jar 包名

外部Tomcat运行

1.使用mvn celan package 打包

2.将war包 放入到tomcat webapps下运行即可。

注意: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>

参考文献

JdbcTemplate

SpringBoot分页插件PageHelper

jpa

Spring For All 社区 Spring 官方教程翻译

SpringBoot使用Redis缓存

Spring Boot Admin简单使用

Spring Boot 性能优化

WebFlux

感谢以上大大们~!

广告时间:想要了解更多精彩新姿势?请访问我的博客

查看全文
如若内容造成侵权/违法违规/事实不符,请联系编程学习网邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!

相关文章

  1. 【Java】java.util.Objects 工具类方法研究

     Objects 与 Object 区别 Object 是 Java 中所有类的基类,位于java.lang包。 Objects 是 Object 的工具类,位于java.util包。它从jdk1.7开始才出现,被final修饰不能被继承,拥有私有的构造函数。 它由一些静态的实用方法组成,这些方法是null-save(空指针安全的)或nul…...

    2024/4/27 16:45:01
  2. 用NGUI 显示游戏物体的名字血条

    http://www.unitymanual.com/thread-14635-1-1.html用NGUI 显示游戏物体的名字,当然也可以显示物体的血条 状态信息 最终效果 第一步 首先找到场景中的camera,设置一下 Clear Flags 的属性为Depth only culling Mask的属性为Everything 标签设置为MainCamera 第2步 制作一个…...

    2024/4/14 4:47:34
  3. AjaxPro.dll与ajax.dll区别

    ASP.NET AjaxPro的应用1、首先下载AjaxPro组件。并将AjaxPro.dll引用到网站(或项目)。2、修改Web.config。在 <system.web> 元素中添加以下代码。-XML<configuration><system.web><httpHandlers><!-- Register the ajax handler --><add ve…...

    2024/4/12 5:56:03
  4. 跟着小甲鱼学Python第二天

    因为今天去打了会游戏,所以并没有学多少东西,我反思Python的数据类型 字符串:用”,”“表示;如’520’,“520” 数值类型: 整型:在Python3中,整形长度不受限制 布尔类型:0为false,非0为true 浮点型 :小数,有无小数点来区分整形与浮点型 e记忆法: 1.5e5 表示150000…...

    2024/4/10 8:33:43
  5. 九度OJ_1153:括号匹配问题

    题目描述:在某个字符串(长度不超过100)中有左括号、右括号和大小写字母;规定(与常见的算数式子一样)任何一个左括号都从内到外与在它右边且距离最近的右括号匹配。写一个程序,找到无法匹配的左括号和右括号,输出原来字符串,并在下一行标出不能匹配的括号。不能匹配的左…...

    2024/4/14 3:14:07
  6. 2、 关于导入maven项目javax.annotation.Nullable问题

    1、这里需引入findbug包,默认的scope是test,可以根据情况修改<dependency> <groupId>com.google.code.findbugs</groupId> <artifactId>annotations</artifactId> <version>3.0.1</version> </dependency>...

    2024/4/12 13:39:45
  7. vim安装中文帮助手册

    现在开始学习使用vim,vim已经安装,英文帮助太难看,估摸着有没中文版的 google了一翻,参考了两篇文章: http://blog.csdn.net/baikaishui525/article/details/6722202 http://www.cnblogs.com/henryau/archive/2013/01/06/ubuntu_vim.html 做一个简要的记录 1,下载安装包。…...

    2024/4/10 8:33:40
  8. [Python]小甲鱼Python视频第006课(Pyhon之常用操作符)课后题及参考解答

    # -*- coding: utf-8 -*- """ Created on Mon Mar 4 23:18:54 2019@author: fengs """""" 测试题:0. Python 的 floor 除法现在使用 “//” 实现,那 3.0 // 2.0 您目测会显示什么内容呢?1.01. a < b < c 事实上是等于?…...

    2024/4/19 21:58:09
  9. ajaxpro2.0 和服务端交互 传递参数 的实现

    今天做的网站页面我需要用ajax来实现 我的平台是vs2008 本来我以前写过一篇文章 介绍ajaxpro的使用 但是今天的有点意外 调用不出结果 因为我用的是网站程序 以前调用的时候js都需要加上命名空间 namespace 的名称 但是网站程序 没有命名空间 这些 就死了 找啊找 终于找到了…...

    2024/4/20 11:09:10
  10. NYOJ - 15 - 括号匹配(二)(区间DP)

    题目描述 给你一个字符串,里面只包含"(",")","[","]"四种符号,请问你需要至少添加多少个括号才能使这些括号匹配起来。如:[]是匹配的([])[]是匹配的((]是不匹配的([)]是不匹配的输入第一行输入一个正整数N,表示测试数据组数(N<…...

    2024/4/10 8:33:37
  11. 【lombok】@NoArgsConstructor/@RequirArgsConstructor/@AllArgsConstructor - 生成无参构造器,指定参数构造器或包含所有参数的构造器

    这三个注解的集合接受某些字段的一个参数,简单的用于分配这个参数给这个字段。 @NoArgsConstructor生成的构造器无参数。如果这是不可能的(因为有final字段),则会导致编译错误。 除非使用@NoArgsConstructor(force=true),然后将所有的final字段都初始化为0/false/null。 对…...

    2024/4/18 2:36:01
  12. Redmine 使用手册 总结

    Redmine使用手册 一、Redmine简介Redmine是基于ROR框架开发的一套跨平台项目管理系统,是项目管理系统的后起之秀,据说是源于Basecamp的ror版而来,支持多种数据库,除了和DotProject的功能大致相当外,还有不少自己独特的功能,例如提供wiki、新闻台、时间跟踪、feed聚合、导…...

    2024/4/12 13:17:27
  13. 小甲鱼Python笔记(类)

    类和对象 类的构造方法 def __init__():1 class People: 2 def __init__(self,name): 3 self.name = name注意:在构造方法中的变量不用再次声明,必须有self,创建类的对象是用=类的私有成员 让方法或者类变为私有,只要在它的名字前加上双下划线1 class People: …...

    2024/4/12 5:57:15
  14. 括号匹配算法

    括号匹配算法概述​ 括号匹配在很多字符串处理的场景中时常被用到,诸如各大IDE括号不匹配的错误提示,编译器编译时检查应该成对出现的括号是否符合要求等,在这里我们就直接使用一种比较常规,但效率不差的方法去解决括号匹配的问题就行了。栈方法匹配问题​ 为了方便描述…...

    2024/4/17 1:52:21
  15. ajaxpro 对象未定义,在本地调试没问题,但是IIS没效果

    原因1,有可能你的前台代码没有加 <form id="Form1" runat="Server"> 表单原因2,webconfig的配置问题,iis 6.0 <httpHandlers><add verb="ajaxpro" path="*.ashx" type="AjaxPro.AjaxHandlerFactory,AjaxP…...

    2024/4/10 8:33:32
  16. AFNetworking解析

    首先导入categorylist文件和 AFNetworking文件 再创建mymodel继承月NSobject 在mymodel.h里面写:@property(nonatomic,strong) NSString *categoryId,*categoryName,*count,*lessenPrice;(后面的属性是解析对应的属性名,自己找) 别忘了开启网络数据 在viewcontroller.m里面写: …...

    2024/4/26 23:44:56
  17. 角色名字所有大区唯一的实现策略

    有的公司可能有一个专门角色名字唯一性判断的服务器,名字服务器。这个服务器的目标保证一个大区或者所有大区的名字唯一。所有大区名字唯一有一个好处是,合服的时候不会出现角色名冲突。一个大区唯一的实现策略很直接很容易。这边文章我们尝试讨论所有大区名字唯一的实现策略…...

    2024/4/10 8:33:30
  18. Apache HttpClient 4.3开发手册

    一、概述Apache HttpClient 4系列已经发布很久了,但由于它与HttpClient 3.x版本完全不兼容,以至于业内采用此库的公司较少,在互联网上也少有相关的文档资料分享。本文旨在写一个简要的Apache HttpClient 4.3开发指南,帮助开发者快速上手Apache HttpClient 4.3.x库。要注意的…...

    2024/4/12 5:58:15
  19. (转)AjaxPro相关

    AJAX在去年已经接触过,但都是使用手动的方法编写客户端代码,再加上被请求的页面,感觉非常累,虽然早听说过AJAX.NET和其他一些第3方开发的框架,却一直没有时间来体验。今天干完手上的活,下了个最新版本的AJAX.NET体验了下 1、准备工作新建项目,使用.NET1.1就引用下载下来…...

    2024/4/12 5:56:57
  20. 一道算法面试题:括号匹配问题

    转载出处:http://mp.weixin.qq.com/s/PNhMY7FOFsXROeyohWts2w还记得有一次笔试题,有一道括号匹配的算法题,当时没有学习数据结构和算法,思路很模糊,后来了解一些数据结构之后就有思路了,今天将解法写出来。问题描述给定一个字符串,里边可能包含“()”、"{}"、…...

    2024/4/15 4:27:44

最新文章

  1. 薪酬构成要素:合理配置,满足员工需求

    薪酬构成要素的合理配置在满足员工需求方面扮演着至关重要的角色。薪酬不仅仅是员工为企业提供劳动力所获得的回报&#xff0c;更是员工价值的体现和激励手段。因此&#xff0c;薪酬构成要素的设计需要充分考虑员工的需求和企业的实际情况&#xff0c;以确保薪酬体系的合理性和…...

    2024/4/27 17:59:21
  2. 梯度消失和梯度爆炸的一些处理方法

    在这里是记录一下梯度消失或梯度爆炸的一些处理技巧。全当学习总结了如有错误还请留言&#xff0c;在此感激不尽。 权重和梯度的更新公式如下&#xff1a; w w − η ⋅ ∇ w w w - \eta \cdot \nabla w ww−η⋅∇w 个人通俗的理解梯度消失就是网络模型在反向求导的时候出…...

    2024/3/20 10:50:27
  3. 企业常用Linux文件命令相关知识+小案例

    远程连接工具无法连接VMWARE&#xff1a; 如果发现连接工具有时连不上&#xff0c;ip存在&#xff0c;这时候我们查看网络编辑器&#xff0c;更多配置&#xff0c;看vnet8是不是10段&#xff0c;nat设置是否是正确的&#xff1f; 软件重启一下虚机还原一下网络编辑器 查看文件…...

    2024/4/27 12:27:42
  4. GIS与数字孪生共舞,打造未来智慧场景

    作为一名数字孪生资深用户&#xff0c;近日我深刻理解到GIS&#xff08;地理信息系统&#xff09;在构建数字孪生体中的关键作用。 数字孪生技术旨在构建现实世界的虚拟镜像&#xff0c;而GIS则是这一镜像中不可或缺的空间维度框架和导航灯塔。数字孪生的核心是通过数字化方式…...

    2024/4/26 8:22:18
  5. 多态--下

    文章目录 概念多态如何实现的指向谁调谁&#xff1f;例子分析 含有虚函数类的大小是多少&#xff1f;虚函数地址虚表地址多继承的子类的大小怎么计算&#xff1f;练习题虚函数和虚继承 概念 优先使用组合、而不是继承; 继承会破坏父类的封装、因为子类也可以调用到父类的函数;…...

    2024/4/24 6:46:26
  6. 【外汇早评】美通胀数据走低,美元调整

    原标题:【外汇早评】美通胀数据走低,美元调整昨日美国方面公布了新一期的核心PCE物价指数数据,同比增长1.6%,低于前值和预期值的1.7%,距离美联储的通胀目标2%继续走低,通胀压力较低,且此前美国一季度GDP初值中的消费部分下滑明显,因此市场对美联储后续更可能降息的政策…...

    2024/4/26 18:09:39
  7. 【原油贵金属周评】原油多头拥挤,价格调整

    原标题:【原油贵金属周评】原油多头拥挤,价格调整本周国际劳动节,我们喜迎四天假期,但是整个金融市场确实流动性充沛,大事频发,各个商品波动剧烈。美国方面,在本周四凌晨公布5月份的利率决议和新闻发布会,维持联邦基金利率在2.25%-2.50%不变,符合市场预期。同时美联储…...

    2024/4/26 20:12:18
  8. 【外汇周评】靓丽非农不及疲软通胀影响

    原标题:【外汇周评】靓丽非农不及疲软通胀影响在刚结束的周五,美国方面公布了新一期的非农就业数据,大幅好于前值和预期,新增就业重新回到20万以上。具体数据: 美国4月非农就业人口变动 26.3万人,预期 19万人,前值 19.6万人。 美国4月失业率 3.6%,预期 3.8%,前值 3…...

    2024/4/26 23:05:52
  9. 【原油贵金属早评】库存继续增加,油价收跌

    原标题:【原油贵金属早评】库存继续增加,油价收跌周三清晨公布美国当周API原油库存数据,上周原油库存增加281万桶至4.692亿桶,增幅超过预期的74.4万桶。且有消息人士称,沙特阿美据悉将于6月向亚洲炼油厂额外出售更多原油,印度炼油商预计将每日获得至多20万桶的额外原油供…...

    2024/4/27 4:00:35
  10. 【外汇早评】日本央行会议纪要不改日元强势

    原标题:【外汇早评】日本央行会议纪要不改日元强势近两日日元大幅走强与近期市场风险情绪上升,避险资金回流日元有关,也与前一段时间的美日贸易谈判给日本缓冲期,日本方面对汇率问题也避免继续贬值有关。虽然今日早间日本央行公布的利率会议纪要仍然是支持宽松政策,但这符…...

    2024/4/27 17:58:04
  11. 【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响

    原标题:【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响近日伊朗局势升温,导致市场担忧影响原油供给,油价试图反弹。此时OPEC表态稳定市场。据消息人士透露,沙特6月石油出口料将低于700万桶/日,沙特已经收到石油消费国提出的6月份扩大出口的“适度要求”,沙特将满…...

    2024/4/27 14:22:49
  12. 【外汇早评】美欲与伊朗重谈协议

    原标题:【外汇早评】美欲与伊朗重谈协议美国对伊朗的制裁遭到伊朗的抗议,昨日伊朗方面提出将部分退出伊核协议。而此行为又遭到欧洲方面对伊朗的谴责和警告,伊朗外长昨日回应称,欧洲国家履行它们的义务,伊核协议就能保证存续。据传闻伊朗的导弹已经对准了以色列和美国的航…...

    2024/4/26 21:56:58
  13. 【原油贵金属早评】波动率飙升,市场情绪动荡

    原标题:【原油贵金属早评】波动率飙升,市场情绪动荡因中美贸易谈判不安情绪影响,金融市场各资产品种出现明显的波动。随着美国与中方开启第十一轮谈判之际,美国按照既定计划向中国2000亿商品征收25%的关税,市场情绪有所平复,已经开始接受这一事实。虽然波动率-恐慌指数VI…...

    2024/4/27 9:01:45
  14. 【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试

    原标题:【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试美国和伊朗的局势继续升温,市场风险情绪上升,避险黄金有向上突破阻力的迹象。原油方面稍显平稳,近期美国和OPEC加大供给及市场需求回落的影响,伊朗局势并未推升油价走强。近期中美贸易谈判摩擦再度升级,美国对中…...

    2024/4/27 17:59:30
  15. 【原油贵金属早评】市场情绪继续恶化,黄金上破

    原标题:【原油贵金属早评】市场情绪继续恶化,黄金上破周初中国针对于美国加征关税的进行的反制措施引发市场情绪的大幅波动,人民币汇率出现大幅的贬值动能,金融市场受到非常明显的冲击。尤其是波动率起来之后,对于股市的表现尤其不安。隔夜美国股市出现明显的下行走势,这…...

    2024/4/25 18:39:16
  16. 【外汇早评】美伊僵持,风险情绪继续升温

    原标题:【外汇早评】美伊僵持,风险情绪继续升温昨日沙特两艘油轮再次发生爆炸事件,导致波斯湾局势进一步恶化,市场担忧美伊可能会出现摩擦生火,避险品种获得支撑,黄金和日元大幅走强。美指受中美贸易问题影响而在低位震荡。继5月12日,四艘商船在阿联酋领海附近的阿曼湾、…...

    2024/4/25 18:39:16
  17. 【原油贵金属早评】贸易冲突导致需求低迷,油价弱势

    原标题:【原油贵金属早评】贸易冲突导致需求低迷,油价弱势近日虽然伊朗局势升温,中东地区几起油船被袭击事件影响,但油价并未走高,而是出于调整结构中。由于市场预期局势失控的可能性较低,而中美贸易问题导致的全球经济衰退风险更大,需求会持续低迷,因此油价调整压力较…...

    2024/4/26 19:03:37
  18. 氧生福地 玩美北湖(上)——为时光守候两千年

    原标题:氧生福地 玩美北湖(上)——为时光守候两千年一次说走就走的旅行,只有一张高铁票的距离~ 所以,湖南郴州,我来了~ 从广州南站出发,一个半小时就到达郴州西站了。在动车上,同时改票的南风兄和我居然被分到了一个车厢,所以一路非常愉快地聊了过来。 挺好,最起…...

    2024/4/26 22:01:59
  19. 氧生福地 玩美北湖(中)——永春梯田里的美与鲜

    原标题:氧生福地 玩美北湖(中)——永春梯田里的美与鲜一觉醒来,因为大家太爱“美”照,在柳毅山庄去寻找龙女而错过了早餐时间。近十点,向导坏坏还是带着饥肠辘辘的我们去吃郴州最富有盛名的“鱼头粉”。说这是“十二分推荐”,到郴州必吃的美食之一。 哇塞!那个味美香甜…...

    2024/4/25 18:39:14
  20. 氧生福地 玩美北湖(下)——奔跑吧骚年!

    原标题:氧生福地 玩美北湖(下)——奔跑吧骚年!让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 啊……啊……啊 两…...

    2024/4/26 23:04:58
  21. 扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!

    原标题:扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!扒开伪装医用面膜,翻六倍价格宰客!当行业里的某一品项火爆了,就会有很多商家蹭热度,装逼忽悠,最近火爆朋友圈的医用面膜,被沾上了污点,到底怎么回事呢? “比普通面膜安全、效果好!痘痘、痘印、敏感肌都能用…...

    2024/4/25 2:10:52
  22. 「发现」铁皮石斛仙草之神奇功效用于医用面膜

    原标题:「发现」铁皮石斛仙草之神奇功效用于医用面膜丽彦妆铁皮石斛医用面膜|石斛多糖无菌修护补水贴19大优势: 1、铁皮石斛:自唐宋以来,一直被列为皇室贡品,铁皮石斛生于海拔1600米的悬崖峭壁之上,繁殖力差,产量极低,所以古代仅供皇室、贵族享用 2、铁皮石斛自古民间…...

    2024/4/25 18:39:00
  23. 丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者

    原标题:丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者【公司简介】 广州华彬企业隶属香港华彬集团有限公司,专注美业21年,其旗下品牌: 「圣茵美」私密荷尔蒙抗衰,产后修复 「圣仪轩」私密荷尔蒙抗衰,产后修复 「花茵莳」私密荷尔蒙抗衰,产后修复 「丽彦妆」专注医学护…...

    2024/4/26 19:46:12
  24. 广州械字号面膜生产厂家OEM/ODM4项须知!

    原标题:广州械字号面膜生产厂家OEM/ODM4项须知!广州械字号面膜生产厂家OEM/ODM流程及注意事项解读: 械字号医用面膜,其实在我国并没有严格的定义,通常我们说的医美面膜指的应该是一种「医用敷料」,也就是说,医用面膜其实算作「医疗器械」的一种,又称「医用冷敷贴」。 …...

    2024/4/27 11:43:08
  25. 械字号医用眼膜缓解用眼过度到底有无作用?

    原标题:械字号医用眼膜缓解用眼过度到底有无作用?医用眼膜/械字号眼膜/医用冷敷眼贴 凝胶层为亲水高分子材料,含70%以上的水分。体表皮肤温度传导到本产品的凝胶层,热量被凝胶内水分子吸收,通过水分的蒸发带走大量的热量,可迅速地降低体表皮肤局部温度,减轻局部皮肤的灼…...

    2024/4/27 8:32:30
  26. 配置失败还原请勿关闭计算机,电脑开机屏幕上面显示,配置失败还原更改 请勿关闭计算机 开不了机 这个问题怎么办...

    解析如下&#xff1a;1、长按电脑电源键直至关机&#xff0c;然后再按一次电源健重启电脑&#xff0c;按F8健进入安全模式2、安全模式下进入Windows系统桌面后&#xff0c;按住“winR”打开运行窗口&#xff0c;输入“services.msc”打开服务设置3、在服务界面&#xff0c;选中…...

    2022/11/19 21:17:18
  27. 错误使用 reshape要执行 RESHAPE,请勿更改元素数目。

    %读入6幅图像&#xff08;每一幅图像的大小是564*564&#xff09; f1 imread(WashingtonDC_Band1_564.tif); subplot(3,2,1),imshow(f1); f2 imread(WashingtonDC_Band2_564.tif); subplot(3,2,2),imshow(f2); f3 imread(WashingtonDC_Band3_564.tif); subplot(3,2,3),imsho…...

    2022/11/19 21:17:16
  28. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机...

    win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”问题的解决方法在win7系统关机时如果有升级系统的或者其他需要会直接进入一个 等待界面&#xff0c;在等待界面中我们需要等待操作结束才能关机&#xff0c;虽然这比较麻烦&#xff0c;但是对系统进行配置和升级…...

    2022/11/19 21:17:15
  29. 台式电脑显示配置100%请勿关闭计算机,“准备配置windows 请勿关闭计算机”的解决方法...

    有不少用户在重装Win7系统或更新系统后会遇到“准备配置windows&#xff0c;请勿关闭计算机”的提示&#xff0c;要过很久才能进入系统&#xff0c;有的用户甚至几个小时也无法进入&#xff0c;下面就教大家这个问题的解决方法。第一种方法&#xff1a;我们首先在左下角的“开始…...

    2022/11/19 21:17:14
  30. win7 正在配置 请勿关闭计算机,怎么办Win7开机显示正在配置Windows Update请勿关机...

    置信有很多用户都跟小编一样遇到过这样的问题&#xff0c;电脑时发现开机屏幕显现“正在配置Windows Update&#xff0c;请勿关机”(如下图所示)&#xff0c;而且还需求等大约5分钟才干进入系统。这是怎样回事呢&#xff1f;一切都是正常操作的&#xff0c;为什么开时机呈现“正…...

    2022/11/19 21:17:13
  31. 准备配置windows 请勿关闭计算机 蓝屏,Win7开机总是出现提示“配置Windows请勿关机”...

    Win7系统开机启动时总是出现“配置Windows请勿关机”的提示&#xff0c;没过几秒后电脑自动重启&#xff0c;每次开机都这样无法进入系统&#xff0c;此时碰到这种现象的用户就可以使用以下5种方法解决问题。方法一&#xff1a;开机按下F8&#xff0c;在出现的Windows高级启动选…...

    2022/11/19 21:17:12
  32. 准备windows请勿关闭计算机要多久,windows10系统提示正在准备windows请勿关闭计算机怎么办...

    有不少windows10系统用户反映说碰到这样一个情况&#xff0c;就是电脑提示正在准备windows请勿关闭计算机&#xff0c;碰到这样的问题该怎么解决呢&#xff0c;现在小编就给大家分享一下windows10系统提示正在准备windows请勿关闭计算机的具体第一种方法&#xff1a;1、2、依次…...

    2022/11/19 21:17:11
  33. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”的解决方法...

    今天和大家分享一下win7系统重装了Win7旗舰版系统后&#xff0c;每次关机的时候桌面上都会显示一个“配置Windows Update的界面&#xff0c;提示请勿关闭计算机”&#xff0c;每次停留好几分钟才能正常关机&#xff0c;导致什么情况引起的呢&#xff1f;出现配置Windows Update…...

    2022/11/19 21:17:10
  34. 电脑桌面一直是清理请关闭计算机,windows7一直卡在清理 请勿关闭计算机-win7清理请勿关机,win7配置更新35%不动...

    只能是等着&#xff0c;别无他法。说是卡着如果你看硬盘灯应该在读写。如果从 Win 10 无法正常回滚&#xff0c;只能是考虑备份数据后重装系统了。解决来方案一&#xff1a;管理员运行cmd&#xff1a;net stop WuAuServcd %windir%ren SoftwareDistribution SDoldnet start WuA…...

    2022/11/19 21:17:09
  35. 计算机配置更新不起,电脑提示“配置Windows Update请勿关闭计算机”怎么办?

    原标题&#xff1a;电脑提示“配置Windows Update请勿关闭计算机”怎么办&#xff1f;win7系统中在开机与关闭的时候总是显示“配置windows update请勿关闭计算机”相信有不少朋友都曾遇到过一次两次还能忍但经常遇到就叫人感到心烦了遇到这种问题怎么办呢&#xff1f;一般的方…...

    2022/11/19 21:17:08
  36. 计算机正在配置无法关机,关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机...

    关机提示 windows7 正在配置windows 请勿关闭计算机 &#xff0c;然后等了一晚上也没有关掉。现在电脑无法正常关机以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;关机提示 windows7 正在配…...

    2022/11/19 21:17:05
  37. 钉钉提示请勿通过开发者调试模式_钉钉请勿通过开发者调试模式是真的吗好不好用...

    钉钉请勿通过开发者调试模式是真的吗好不好用 更新时间:2020-04-20 22:24:19 浏览次数:729次 区域: 南阳 > 卧龙 列举网提醒您:为保障您的权益,请不要提前支付任何费用! 虚拟位置外设器!!轨迹模拟&虚拟位置外设神器 专业用于:钉钉,外勤365,红圈通,企业微信和…...

    2022/11/19 21:17:05
  38. 配置失败还原请勿关闭计算机怎么办,win7系统出现“配置windows update失败 还原更改 请勿关闭计算机”,长时间没反应,无法进入系统的解决方案...

    前几天班里有位学生电脑(windows 7系统)出问题了&#xff0c;具体表现是开机时一直停留在“配置windows update失败 还原更改 请勿关闭计算机”这个界面&#xff0c;长时间没反应&#xff0c;无法进入系统。这个问题原来帮其他同学也解决过&#xff0c;网上搜了不少资料&#x…...

    2022/11/19 21:17:04
  39. 一个电脑无法关闭计算机你应该怎么办,电脑显示“清理请勿关闭计算机”怎么办?...

    本文为你提供了3个有效解决电脑显示“清理请勿关闭计算机”问题的方法&#xff0c;并在最后教给你1种保护系统安全的好方法&#xff0c;一起来看看&#xff01;电脑出现“清理请勿关闭计算机”在Windows 7(SP1)和Windows Server 2008 R2 SP1中&#xff0c;添加了1个新功能在“磁…...

    2022/11/19 21:17:03
  40. 请勿关闭计算机还原更改要多久,电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机怎么办...

    许多用户在长期不使用电脑的时候&#xff0c;开启电脑发现电脑显示&#xff1a;配置windows更新失败&#xff0c;正在还原更改&#xff0c;请勿关闭计算机。。.这要怎么办呢&#xff1f;下面小编就带着大家一起看看吧&#xff01;如果能够正常进入系统&#xff0c;建议您暂时移…...

    2022/11/19 21:17:02
  41. 还原更改请勿关闭计算机 要多久,配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以...

    配置windows update失败 还原更改 请勿关闭计算机&#xff0c;电脑开机后一直显示以以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;配置windows update失败 还原更改 请勿关闭计算机&#x…...

    2022/11/19 21:17:01
  42. 电脑配置中请勿关闭计算机怎么办,准备配置windows请勿关闭计算机一直显示怎么办【图解】...

    不知道大家有没有遇到过这样的一个问题&#xff0c;就是我们的win7系统在关机的时候&#xff0c;总是喜欢显示“准备配置windows&#xff0c;请勿关机”这样的一个页面&#xff0c;没有什么大碍&#xff0c;但是如果一直等着的话就要两个小时甚至更久都关不了机&#xff0c;非常…...

    2022/11/19 21:17:00
  43. 正在准备配置请勿关闭计算机,正在准备配置windows请勿关闭计算机时间长了解决教程...

    当电脑出现正在准备配置windows请勿关闭计算机时&#xff0c;一般是您正对windows进行升级&#xff0c;但是这个要是长时间没有反应&#xff0c;我们不能再傻等下去了。可能是电脑出了别的问题了&#xff0c;来看看教程的说法。正在准备配置windows请勿关闭计算机时间长了方法一…...

    2022/11/19 21:16:59
  44. 配置失败还原请勿关闭计算机,配置Windows Update失败,还原更改请勿关闭计算机...

    我们使用电脑的过程中有时会遇到这种情况&#xff0c;当我们打开电脑之后&#xff0c;发现一直停留在一个界面&#xff1a;“配置Windows Update失败&#xff0c;还原更改请勿关闭计算机”&#xff0c;等了许久还是无法进入系统。如果我们遇到此类问题应该如何解决呢&#xff0…...

    2022/11/19 21:16:58
  45. 如何在iPhone上关闭“请勿打扰”

    Apple’s “Do Not Disturb While Driving” is a potentially lifesaving iPhone feature, but it doesn’t always turn on automatically at the appropriate time. For example, you might be a passenger in a moving car, but your iPhone may think you’re the one dri…...

    2022/11/19 21:16:57