springboot配置Druid
pom.xml
注:springboot与druid的版本兼容问题(Druid 1.1.8以上兼容springboot2.0)
<!-- druid连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.9</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
application.yml
Druid 1.1.9 jar包里含有自动配置类,所以默认注册了 DruidStatView、druidWebStatFilter。
此处可以自定义设置 DruidStatView、druidWebStatFilter的属性
spring:
datasource:
url: jdbc:mysql://localhost:3306/***?userUnicode=true&characterEncoding=UTF8&useSSL=false
username: ****
password: ****
type: com.alibaba.druid.pool.DruidDataSource
druid:
stat-view-servlet:
enabled: true
urlPattern:
allow:
deny:
loginUsername: root
loginPassword: root
resetEnable:
web-stat-filter:
enabled: true
urlPattern:
exclusions:
sessionStatMaxCount:
sessionStatEnable:
principalSessionName:
principalCookieName:
profileEnable:
Druid配置参数(Druid)
配置 | 缺省值 | 说明 |
---|---|---|
name | 配置这个属性的意义在于,如果存在多个数据源,监控的时候可以通过名字来区分开来。 如果没有配置,将会生成一个名字,格式是:”DataSource-“ + System.identityHashCode(this) | |
jdbcUrl | 连接数据库的url,不同数据库不一样。例如:mysql : jdbc:mysql://10.20.153.104:3306/druid2 oracle : jdbc:oracle:thin:@10.20.149.85:1521:ocnauto | |
username | 连接数据库的用户名 | |
password | 连接数据库的密码。如果你不希望密码直接写在配置文件中, 可以使用ConfigFilter。详细看这里:(Druid ConfigFilter) | |
driverClassName | 根据url自动识别 | 这一项可配可不配,如果不配置druid会根据url自动识别dbType,然后选择相应的driverClassName |
initialSize | 0 | 初始化时建立物理连接的个数。初始化发生在显示调用init方法,或者第一次getConnection时 |
maxActive | 8 | 最大连接池数量 |
maxIdle | 8 | 已经不再使用,配置了也没效果 |
minIdle | 最小连接池数量 | |
maxWait | 获取连接时最大等待时间,单位毫秒。配置了maxWait之后,缺省启用公平锁,并发效率会有所下降, 如果需要可以通过配置useUnfairLock属性为true使用非公平锁。 | |
poolPreparedStatements | false | 是否缓存reparedStatement,就是PSCache。 PSCache对支持游标的数据库性能提升巨大,比如说oracle。 在mysql5.5以下的版本中没有PSCache功能,建议关闭掉。作者在5.5版本中使用PSCache,通过监控界面发现PSCache有缓存命中率记录, 该应该是支持PSCache。 |
maxOpenPreparedStatements | -1 | 要启用PSCache,必须配置大于0,当大于0时, poolPreparedStatements自动触发修改为true。 在Druid中,不会存在Oracle下PSCache占用内存过多的问题, 可以把这个数值配置大一些,比如说100 |
validationQuery | 用来检测连接是否有效的sql,要求是一个查询语句。 如果validationQuery为null,testOnBorrow、testOnReturn、 testWhileIdle都不会其作用。 | |
testOnBorrow | true | 申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。 |
testOnReturn | false | 归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能 |
testWhileIdle | false | 建议配置为true,不影响性能,并且保证安全性。 申请连接的时候检测,如果空闲时间大于 timeBetweenEvictionRunsMillis, 执行validationQuery检测连接是否有效。 |
timeBetweenEvictionRunsMillis | 有两个含义: (1) Destroy线程会检测连接的间隔时间 (2) testWhileIdle的判断依据,详细看testWhileIdle属性的说明 |
|
numTestsPerEvictionRun | 不再使用,一个DruidDataSource只支持一个EvictionRun | |
minEvictableIdleTimeMillis | 连接保持空闲而不被驱逐的最长时间 | |
connectionInitSqls | 物理连接初始化的时候执行的sql | |
exceptionSorter | 根据dbType自动识别 | 当数据库抛出一些不可恢复的异常时,抛弃连接 |
filters | 属性类型是字符串,通过别名的方式配置扩展插件, 常用的插件有: 监控统计用的filter:stat 日志用的filter:log4j 防御sql注入的filter:wall |
|
proxyFilters | 类型是List<com.alibaba.druid.filter.Filter> ,如果同时配置了filters和proxyFilters, 是组合关系,并非替换关系 |
springboot整合mybatis并打印sql至日志
logging:
level:
root: info
#打印sql 前缀为mapper的全路径
com.example.mapper: debug
# 不指定路径在当前项目下生成springboot.log日志
file: log.log
整合JavaMail发送邮件
添加对应依赖
pom.xml
<dependency>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
<version>1.4</version>
</dependency>
编写发送邮件的类
package com.example.JavaMail;
import org.springframework.stereotype.Component;
import javax.mail.*;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import java.util.List;
import java.util.Properties;
/**
* @author yanzt
* @date 2018/6/29 15:33
* @description
*/
@Component
public class MailSender {
//SMTP发送邮件,是否进行身份验证
private static final String smtpAuth = "true";
//SMTP服务器
private static final String smtpHost = "smtp.qq.com";
//端口号 QQ邮箱有两个端口号:465/587
private static final String smtpPort = "587";
//发送邮箱
private static final String fromMailAddress = "2507967396@qq.com";
//发送邮箱的16位SMTP口令
private static final String fromMailStmpPwd = "kziktiflnzjiecbc";
/**
* @param content 邮件内容
* @param title 邮件标题
* @param internerAddress 收件人地址集合
* 发送邮件
* */
public static void send(String title, String content, List<String> internerAddress){
Properties prop = new Properties();
prop.put("mail.smtp.auth", smtpAuth);
prop.put("mail.smtp.host",smtpHost);
prop.put("mail.smtp.port",smtpPort);
prop.put("mail.user",fromMailAddress);
prop.put("mail.password",fromMailStmpPwd);
Authenticator authenticator = new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(fromMailAddress,fromMailStmpPwd);
}
};
Session mailSession = Session.getInstance(prop,authenticator);
Message message = new MimeMessage(mailSession);
try {
message.setFrom(new InternetAddress(fromMailAddress));
message.setSubject(title);
/**text文本格式发送邮件*/
message.setText(content);
/**html格式发送邮件*/
// message.setContent(content,"text/html; charset=UTF-8");
} catch (MessagingException e) {
e.printStackTrace();
}
for(int i=0,size=internerAddress.size();i<size;i++){
try {
message.setRecipient(Message.RecipientType.TO, new InternetAddress(internerAddress.get(i)));
Transport.send(message);
} catch (MessagingException e) {
// e.printStackTrace();
continue;
}
}
}
}
开启POP3/SMTP
第一步:进入QQ邮箱点击“设置”
第二步:点击“账户”后往下拉找到POP3/IMAP/SMTP…
第三步:请点击“开启”并且按照提示步骤完成获取“授权码”即可,授权码就是发送邮件参数的SMTP口令(fromMailStmpPwd)。
测试发送邮件
@ResponseBody
@RequestMapping("/sendMail")
public void sendMail(){
List<String> internerAddress = new ArrayList<>();
internerAddress.add("2975804955@qq.com");
MailSender.send("测试邮件","测试邮件的内容啊!",internerAddress);
}
springboot集成spring cache
pom.xml
<!--添加缓存依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
在程序的入口中加入@ EnableCaching开启缓存技术:
package com.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
@SpringBootApplication
@EnableScheduling
@EnableCaching
public class RestSpringbootDemoApplication {
public static void main(String[] args) {
SpringApplication.run(RestSpringbootDemoApplication.class, args);
}
/**
* 使用 websockt注解的时候,使用@EnableScheduling注解
* 启动的时候一直报错,增加这个bean 则报错解决。
* 报错信息: Unexpected use of scheduler.
*https://stackoverflow.com/questions/49343692/websocketconfigurer-and-scheduled-are-not-work-well-in-an-application
*
* @return
*/
@Bean
public TaskScheduler taskScheduler(){
ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
taskScheduler.setPoolSize(10);
taskScheduler.initialize();
return taskScheduler;
}
}
在需要缓存的地方加入@Cacheable注解,比如在getUser()方法上加入@Cacheable(“userInf”),这个方法就开启了缓存策略,当缓存有这个数据的时候,会直接返回数据,不会等待去查询数据库。
/**
*
* 如果设置sync=true,
* 如果缓存中没有数据,多个线程同时访问这个方法,则只有一个方法会执行到方法,其它方法需要等待
* 如果缓存中已经有数据,则多个线程可以同时从缓存中获取数据
*
* */
@Cacheable(value = "userInf",sync = false)
@RequestMapping(value = "/user/{id}", method = RequestMethod.GET, produces = "application/json")
public UserInf getUser(@PathVariable("id") int id) {
UserInf user = (UserInf) userInfService.getUserInf(id);
log.info("查询用户 :" + user);
return user;
}
springboot集成RabbitMQ
详见《RabbitMQ消息队列》中 springboot集成RabbitMQ
springboot整合MongoDB
详见《MongoDB》中 springboot集成MongoDB
pom.xml
<!-- Spring Boot MongoDB -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
<version>2.0.2.RELEASE</version>
</dependency>
application.yml
data:
mongodb:
host: 127.0.0.1
port: 27017
username: root
password: root
authentication-database: admin
database: test
#uri方式会报错
model类
package com.example.mongodb.model;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.Field;
import java.util.Date;
import java.util.List;
@Document(collection = "article_info")
public class Article {
@Id
private String id;
@Field("title")
private String title;
@Field("url")
private String url;
@Field("author")
private String author;
@Field("tags")
private List<String> tags;
@Field("visit_count")
private Long visitCount;
@Field("add_time")
private Date addTime;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public List<String> getTags() {
return tags;
}
public void setTags(List<String> tags) {
this.tags = tags;
}
public Long getVisitCount() {
return visitCount;
}
public void setVisitCount(Long visitCount) {
this.visitCount = visitCount;
}
public Date getAddTime() {
return addTime;
}
public void setAddTime(Date addTime) {
this.addTime = addTime;
}
@Override
public String toString() {
return "article{" +
"id='" + id + '\'' +
", title='" + title + '\'' +
", url='" + url + '\'' +
", author='" + author + '\'' +
", tags=" + tags +
", visitCount=" + visitCount +
", addTime=" + addTime +
'}';
}
}
继承MongoRepository接口
package com.example.mongodb.repository;
import com.example.mongodb.model.Article;
import org.springframework.data.mongodb.repository.MongoRepository;
/**
* @author yanzt
* @date 2018/6/27 14:30
* @description
*/
public interface ArticleRepository extends MongoRepository<Article,String> {
}
测试
package com.example.mongodb.controller;
import com.example.annotation.IgnoreSecurity;
import com.example.mongodb.model.Article;
import org.bson.types.ObjectId;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
/**
* MongoDB数据库的基本操作
* */
@RestController
@RequestMapping("/testMongoDb")
public class testMongoDbController {
@Autowired
private MongoTemplate mongoTemplate;
/**
* 初始化文章信息
* */
@RequestMapping("/init")
@IgnoreSecurity
public void initArticle(){
Article article = new Article();
article.setTitle("MongoTemplate的基本使用");
article.setAuthor("yinjihuan");
article.setUrl("http://cxytiandi.com/blog/detail/1");
article.setTags(Arrays.asList("java", "mongodb", "spring"));
article.setVisitCount(0L);
article.setAddTime(new Date());
mongoTemplate.save(article);
//批量添加
List<Article> articles = new ArrayList<>();
for(int i = 0 ;i < 10 ;i++){
article = new Article();
article.setTitle("MongoTemplate的基本使用");
article.setAuthor("yinjihuan");
article.setUrl("http://cxytiandi.com/blog/detail/" + i);
article.setTags(Arrays.asList("java", "mongodb", "spring"));
article.setVisitCount(0L);
article.setAddTime(new Date());
articles.add(article);
}
mongoTemplate.insert(articles,Article.class);
}
@RequestMapping("/delete")
@IgnoreSecurity
public void delete(){
//查询
Query query = Query.query(Criteria.where("author").is("yinjihuan"));
mongoTemplate.findAndRemove(query,Article.class);//删除第一条
// mongoTemplate.remove(query,Article.class);//删除查询到的数据
// mongoTemplate.findAllAndRemove(query,Article.class);//同上
// mongoTemplate.getDb().drop();//删除所有
// mongoTemplate.dropCollection(Article.class);//删除所有
// mongoTemplate.dropCollection("article_info");//删除所有
}
@RequestMapping("/update")
@IgnoreSecurity
public void update(){
//查询
Query query = Query.query(Criteria.where("author").is("yinjihuan"));
Update update = Update.update("title","MongoTemplate").set("visitCount",10);
mongoTemplate.updateFirst(query,update,Article.class);//更新第一条
mongoTemplate.updateMulti(query,update,Article.class);
//query不存在则新增一条记录
query = Query.query(Criteria.where("author").is("jason"));
update = Update.update("title", "MongoTemplate").set("visitCount", 10);
mongoTemplate.upsert(query,update,Article.class);
//key不存在则新增
/*update = Update.update("title", "MongoTemplate").set("money", 100);
mongoTemplate.updateMulti(query, update, Article.class);*/
//原有基础上做加法
/*update = Update.update("title", "MongoTemplate").inc("money", 100);
mongoTemplate.updateMulti(query, update, Article.class);*/
//修改key
/*update = Update.update("title", "MongoTemplate").rename("visitCount", "vc");
mongoTemplate.updateMulti(query, update, Article.class);*/
//update的pull方法用于删除tags数组中的java
query = Query.query(Criteria.where("author").is("yinjihuan"));
update = Update.update("title", "MongoTemplate").pull("tags", "java");
mongoTemplate.updateMulti(query, update, Article.class);
}
/**查询操作*/
@RequestMapping("/select")
@IgnoreSecurity
public void select(){
Query query = Query.query(Criteria.where("author").is("yinjihuan"));
List<Article> articles = mongoTemplate.find(query,Article.class);//查询符合条件的所有记录
System.out.println("查询符合条件的所有记录:"+articles.toString());
Article article = mongoTemplate.findOne(query,Article.class);//查询符合条件的第一条记录
System.out.println("查询符合条件的第一条记录:"+article.toString());
articles = mongoTemplate.findAll(Article.class);//查询集合中所有记录
System.out.println("查询集合中所有记录:"+articles.toString());
try {
article = mongoTemplate.findById(new ObjectId("5afd4e0120180c05f8f0b93d"),Article.class);
System.out.println("根据ID查询:"+article.toString());
} catch (Exception e) {
System.out.println(e.getMessage());
}
//in查询
List<String> authors = Arrays.asList("yinjihuan", "jason");
query = Query.query(Criteria.where("author").in(authors));
articles = mongoTemplate.find(query, Article.class);
System.out.println("in查询:"+articles.toString());
//ne(!=)查询
query = Query.query(Criteria.where("author").ne("jason"));
articles = mongoTemplate.find(query, Article.class);
System.out.println("ne(!=)查询:"+articles.toString());
//lt(<)查询访问量小于10的文章
query = Query.query(Criteria.where("visitCount").lt(10));
articles = mongoTemplate.find(query, Article.class);
System.out.println("lt(<)查询:"+articles.toString());
//范围查询,大于5小于10
query = Query.query(Criteria.where("visitCount").gt(5).lt(10));
articles = mongoTemplate.find(query, Article.class);
System.out.println("范围查询:"+articles.toString());
//模糊查询,author中包含a的数据
query = Query.query(Criteria.where("author").regex("a"));
articles = mongoTemplate.find(query, Article.class);
System.out.println("模糊查询:"+articles.toString());
//数组查询,查询tags里数量为3的数据
query = Query.query(Criteria.where("tags").size(3));
articles = mongoTemplate.find(query, Article.class);
System.out.println("数组查询:"+articles.toString());
//or查询,查询author=jason的或者visitCount=0的数据
query = Query.query(Criteria.where("").orOperator( Criteria.where("author").is("jason"), Criteria.where("visitCount").is(0)));
articles = mongoTemplate.find(query, Article.class);
System.out.println("or查询:"+articles.toString());
}
}
springboot整合Actuator
https://docs.spring.io/spring-boot/docs/2.0.3.BUILD-SNAPSHOT/reference/htmlsingle/#production-ready
主要是完成微服务的监控,完成监控治理。可以查看微服务间的数据处理和调用,当它们之间出现了异常,就可以快速定位到出现问题的地方。
依赖
maven 项目 在 pom.xml
文件中加入 actuator 的依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
同时注意只有端点/health和/info端点是暴露的。
Property | Default |
---|---|
management.endpoints.jmx.exposure.exclude |
|
management.endpoints.jmx.exposure.include |
* |
management.endpoints.web.exposure.exclude |
|
management.endpoints.web.exposure.include |
info, health |
- 您可以按如下方式公开所有端点:
management.endpoints.web.exposure.include=*
- 您可以通过以下方式显式启用
/shutdown
端点:management.endpoint.shutdown.enabled=true
- 要公开所有(已启用)网络端点除
env
端点之外:
management:
endpoints:
web:
exposure:
include: "*"
endpoint:
shutdown:
enabled: true
Endpoints
通过执行器端点,您可以监控应用程序并与之交互。Spring Boot包含许多内置端点,允许您添加自己的端点。例如, health
端点提供基本的应用程序健康信息。
可以启用或禁用每个单独的端点。它控制是否创建端点并且其bean存在于应用程序上下文中。要远程访问,还必须通过JMX或HTTP公开端点 。大多数应用程序选择HTTP,其中端点的ID以及前缀/actuator
映射到URL。例如,默认情况下,health
端点映射到 /actuator/health
。
ID | 描述 | 默认情况下启用 |
---|---|---|
auditevents |
公开当前应用程序的审核事件信息。 | 是 |
beans |
显示应用程序中所有Spring bean的完整列表。 | 是 |
conditions |
显示在配置和自动配置类上评估的条件以及它们匹配或不匹配的原因。 | 是 |
configprops |
显示所有的整理列表@ConfigurationProperties 。 |
是 |
env |
露出Spring的属性ConfigurableEnvironment 。 |
是 |
flyway |
显示已应用的任何Flyway数据库迁移。 | 是 |
health |
显示应用健康信息。 | 是 |
httptrace |
显示HTTP跟踪信息(默认情况下,最后100个HTTP请求 - 响应交换)。 | 是 |
info |
显示任意应用信息。 | 是 |
loggers |
显示和修改应用程序中记录器的配置。 | 是 |
liquibase |
显示已应用的任何Liquibase数据库迁移。 | 是 |
metrics |
显示当前应用程序的“指标”信息。 | 是 |
mappings |
显示所有@RequestMapping 路径的整理列表。 |
是 |
scheduledtasks |
显示应用程序中的计划任务。 | 是 |
sessions |
Allows retrieval and deletion of user sessions from a Spring Session-backed session store. Not available when using Spring Session’s support for reactive web applications. | 是 |
shutdown |
允许应用程序正常关闭。 | 没有 |
threaddump |
执行线程转储。 | 是 |
如果您的应用程序是Web应用程序(Spring MVC,Spring WebFlux或Jersey),则可以使用以下附加端点:
ID | 描述 | 默认情况下启用 |
---|---|---|
heapdump |
返回GZip压缩hprof 堆转储文件。 |
是 |
jolokia |
通过HTTP公开JMX bean(当Jolokia在类路径上时,不适用于WebFlux)。 | 是 |
logfile |
返回日志文件的内容(如果已设置logging.file 或logging.path 属性)。支持使用HTTP Range 标头来检索部分日志文件的内容。 |
是 |
prometheus |
以可以由Prometheus服务器抓取的格式公开指标。 | 是 |
启用端点
默认情况下,shutdown
启用除以外的所有端点。要配置端点的启用,请使用其management.endpoint.<id>.enabled
属性。以下示例启用shutdown
端点:
management.endpoint.shutdown.enabled = true
如果您希望端点启用是选择加入而不是选择退出,请将该management.endpoints.enabled-by-default
属性设置 为false
并使用各个端点 enabled
属性重新加入。以下示例启用info
端点并禁用所有其他端点:
management.endpoints.enabled-by-default = false
management.endpoint.info.enabled = true