Spring Boot高级
一、Spring Boot与缓存
一、JSR107
Java Caching定义了5个核心接口,分别是CachingProvider, CacheManager, Cache, Entry
和 Expiry。
• CachingProvider定义了创建、配置、获取、管理和控制多个CacheManager。一个应用可
以在运行期访问多个CachingProvider。
• CacheManager定义了创建、配置、获取、管理和控制多个唯一命名的Cache,这些Cache
存在于CacheManager的上下文中。一个CacheManager仅被一个CachingProvider所拥有。
• Cache是一个类似Map的数据结构并临时存储以Key为索引的值。一个Cache仅被一个
CacheManager所拥有。
• Entry是一个存储在Cache中的key-value对。
• Expiry 每一个存储在Cache中的条目有一个定义的有效期。一旦超过这个时间,条目为过期
的状态。一旦过期,条目将不可访问、更新和删除。缓存有效期可以通过ExpiryPolicy设置。
二、Spring缓存抽象
Spring从3.1开始定义了org.springframework.cache.Cache
和org.springframework.cache.CacheManager接口来统一不同的缓存技术;
并支持使用JCache(JSR-107)注解简化我们开发;
• Cache接口为缓存的组件规范定义,包含缓存的各种操作集合;
• Cache接口下Spring提供了各种xxxCache的实现;如RedisCache,EhCacheCache ,
ConcurrentMapCache等;
• 每次调用需要缓存功能的方法时,Spring会检查检查指定参数的指定的目标方法是否
已经被调用过;如果有就直接从缓存中获取方法调用后的结果,如果没有就调用方法
并缓存结果后返回给用户。下次调用直接从缓存中获取。
• 使用Spring缓存抽象时我们需要关注以下两点;
1、确定方法需要被缓存以及他们的缓存策略
2、从缓存中读取之前缓存存储的数据
三、几个重要概念&缓存注解
四、缓存使用
• 1、引入spring-boot-starter-cache模块
• 2、@EnableCaching开启缓存
• 3、使用缓存注解
• 4、切换为其他缓存
application.properties:
spring.datasource.url=jdbc:mysql://localhost:3306/springboot-cache
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=数据库密码
#开启驼峰命名
mybatis.configuration.map-underscore-to-camel-case=true
#开启日志
logging.level.com.qq.springboot.Mapper=debug
package com.qq.springboot;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/*
一、搭建基本环境
1.导入数据库文件 创建出department和employee表
2.创建javaBean封装数据库
3.整合MyBatis操作数据库
1.配置数据源信息
2.使用注解版的MyBatis:
1).@MapperScan指定需要扫描的mapper接口所在的包
二、快速体验缓存
步骤:
1.开启基于注解的缓存 @EnableCaching
2.标注缓存注解即可
@Cacheable
@CacheEvict
@CachePut
*/
@MapperScan("com.qq.springboot.Mapper")
@SpringBootApplication
public class SpringbootApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootApplication.class, args);
}
}
创建Mapper
EmployeeMapper接口:
package com.qq.springboot.Mapper;
import com.qq.springboot.Bean.Employee;
import org.apache.ibatis.annotations.*;
@Mapper
public interface EmployeeMapper {
@Select("select * from employee where id=#{id}")
public Employee getEmpById(Integer id);
@Delete("delete from employee where id=#{id}")
public void deleteById(Integer id);
@Update("update employee set lastName=#{lastName},email=#{email},gender=#{gender},d_id=#{dId} where id=#{id}")
public void UpdateEmp(Employee employee);
@Insert("insert into employee(lastName,email,gender,d_id) values(#{lastName},#{email},#{gender},#{dId})")
public void insertEmployee(Employee employee);
}
创建Service层:
EmployeeService:
package com.qq.springboot.Service;
import com.qq.springboot.Bean.Employee;
import com.qq.springboot.Mapper.EmployeeMapper;
import org.apache.ibatis.logging.stdout.StdOutImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
@Service
public class EmployeeService {
@Autowired
EmployeeMapper employeeMapper;
/*
将方法的运行结果进行缓存,以后再要相同的数据,直接从缓存中候去,不用调用方法;
CacheManager管理多个Cache组建的,对缓存的真正CRUD操作在Cache组件中,每一个缓存主键有自己唯一一个名字;
几个属性:
cacheNames/value:指定缓存组件的名字;
key:缓存数据使用的key:可以用来指定.默认是使用方法参数的值 1-方法的返回值
编写SpEL;#id;参数id的值 #a0 #p0 #root.args[0]
keyGenerator:key的生成器;可以自己指定key的生成器的组件id
key/keyGenerator:二选一使用
cacheManager:指定缓存管理器;或者cacheResolver指定获取解析器
condition:指定符合条件的情况下才缓存;
unless:否定缓存;当unless指定的条件为true,返回的值就不会被缓存;可以获取到结果进行判断
sync:是否使用异步模式
*/
@Cacheable(cacheNames = "emp")
public Employee getEmpById(Integer id){
System.out.println("查询"+id+"号员工");
Employee employee=employeeMapper.getEmpById(id);
return employee;
}
}
控制层Controller:
@RestController
public class EmployeeController {
@Autowired
EmployeeService employeeService;
@GetMapping("/emp/{id}")
public Employee getEmployee(@PathVariable("id")Integer id){
Employee employee=employeeService.getEmpById(id);
return employee;
}
}
五、整合redis实现缓存
- 引入spring-boot-starter-data-redis
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
- application.yml配置redis连接地址
spring.redis.host=链接的ip
- 使用RestTemplate操作redis
- redisTemplate.opsForValue();//操作字符串
- redisTemplate.opsForHash();//操作hash
- redisTemplate.opsForList();//操作list
- redisTemplate.opsForSet();//操作set
- redisTemplate.opsForZSet();//操作有序set
@Autowired
StringRedisTemplate stringRedisTemplate;//操作k-v都是字符串的
@Autowired
RedisTemplate redisTemplate;//k-v都是对象的
@Autowired
RedisTemplate<Object,Employee> empredisTemplate;
/*
Redis常见的五大数据类型
String(字符串),list(列表),Set(集合),Hash(散列),ZSet(有序集合)
*/
@Test
public void test01(){
stringRedisTemplate.opsForValue().append("msg","hello");
String msg=stringRedisTemplate.opsForValue().get("msg");
System.out.println(msg);
stringRedisTemplate.opsForList().leftPush("mylist","1");
stringRedisTemplate.opsForList().leftPush("mylist","2");
}
//测试保存对象
@Test
public void test02(){
Employee employeeById=employeeMapper.getEmpById(1);
//默认如果保存对象,使用jdk序列化机制,序列化后的数据保存到redis中
redisTemplate.opsForValue().set("emp-01",employeeById);
//1.将数据以json的方式保存
//(1)自己将对象转为json
//(2)redisTemplate默认的序列化规则,改变默认的序列化规则;
empredisTemplate.opsForValue().set("emp-01",employeeById);
}
- 配置缓存、CacheManagerCustomizers
- 测试使用缓存、切换缓存、 CompositeCacheManager
二、Spring Boot与消息(JMS、AMQP、RabbitMQ)
一、概述
- 大多应用中,可通过消息服务中间件来提升系统异步通信、扩展解耦能力
- 消息服务中两个重要概念:
消息代理(message broker)和目的地(destination)
当消息发送者发送消息以后,将由消息代理接管,消息代理保证消息传递到指定目的地。 - 消息队列主要有两种形式的目的地
队列(queue):点对点消息通信(point-to-point)
主题(topic):发布(publish)/订阅(subscribe)消息通信
- 点对点式:
– 消息发送者发送消息,消息代理将其放入一个队列中,消息接收者从队列中获取消息内容,消息读取后被移出队列
– 消息只有唯一的发送者和接受者,但并不是说只能有一个接收者 - 发布订阅式:
– 发送者(发布者)发送消息到主题,多个接收者(订阅者)监听(订阅)这个主题,那么就会在消息到达时同时收到消息 - JMS(Java Message Service)JAVA消息服务:
– 基于JVM消息代理的规范。ActiveMQ、HornetMQ是JMS实现 - AMQP(Advanced Message Queuing Protocol)
– 高级消息队列协议,也是一个消息代理的规范,兼容JMS
– RabbitMQ是AMQP的实现 - Spring支持
– spring-jms提供了对JMS的支持
– spring-rabbit提供了对AMQP的支持
– 需要ConnectionFactory的实现来连接消息代理
– 提供JmsTemplate、RabbitTemplate来发送消息
– @JmsListener(JMS)、@RabbitListener(AMQP)注解在方法上监听消息代理发布的消息
– @EnableJms、@EnableRabbit开启支持 - Spring Boot自动配置
– JmsAutoConfiguration
– RabbitAutoConfiguration
二、RabbitMQ简介
RabbitMQ简介:
RabbitMQ是一个由erlang开发的AMQP(Advanved Message Queue Protocol)的开源实现。
- 核心概念
- Message
消息,消息是不具名的,它由消息头和消息体组成。消息体是不透明的,而消息头则由一系列的可选属性组成,这些属性包括routing-key(路由键)、priority(相对于其他消息的优先权)、delivery-mode(指出该消息可能需要持久性存储)等。 - Publisher
消息的生产者,也是一个向交换器发布消息的客户端应用程序。 - Exchange
交换器,用来接收生产者发送的消息并将这些消息路由给服务器中的队列。
Exchange有4种类型:direct(默认),fanout, topic, 和headers,不同类型的Exchange转发消息的策略有所区别 - Queue
消息队列,用来保存消息直到发送给消费者。它是消息的容器,也是消息的终点。一个消息可投入一个或多个队列。消息一直在队列里面,等待消费者连接到这个队列将其取走。 - Binding
绑定,用于消息队列和交换器之间的关联。一个绑定就是基于路由键将交换器和消息队列连接起来的路由规则,所以可以将交换器理解成一个由绑定构成的路由表。
Exchange 和Queue的绑定可以是多对多的关系。 - Connection
网络连接,比如一个TCP连接。 - Channel
信道,多路复用连接中的一条独立的双向数据流通道。信道是建立在真实的TCP连接内的虚拟连接,AMQP 命令都是通过信道发出去的,不管是发布消息、订阅队列还是接收消息,这些动作都是通过信道完成。因为对于操作系统来说建立和销毁 TCP 都是非常昂贵的开销,所以引入了信道的概念,以复用一条 TCP 连接。 - Consumer
消息的消费者,表示一个从消息队列中取得消息的客户端应用程序。 - Virtual Host
虚拟主机,表示一批交换器、消息队列和相关对象。虚拟主机是共享相同的身份认证和加密环境的独立服务器域。每个 vhost 本质上就是一个 mini 版的 RabbitMQ 服务器,拥有自己的队列、交换器、绑定和权限机制。vhost 是 AMQP 概念的基础,必须在连接时指定,
RabbitMQ 默认的 vhost 是 / 。 - Broker
表示消息队列服务器实体
三、RabbitMQ运行机制
AMQP 中的消息路由
• AMQP 中消息的路由过程和 Java 开发者熟悉的 JMS 存在一些差别,AMQP 中增加了Exchange 和 Binding 的角色。生产者把消息发布到 Exchange 上,消息最终到达队列并被消费者接收,而 Binding 决定交换器的消息应该发送到那个队列。
Exchange 类型
• Exchange分发消息时根据类型的不同分发策略有区别,目前共四种类型:
direct、fanout、topic、headers 。headers 匹配 AMQP 消息的 header 而不是路由键, headers 交换器和 direct 交换器完全一致,但性能差很多,目前几乎用不到了,所以直接看另外三种类型:
消息中的路由键(routing key)如果和 Binding 中的 binding key 一致, 交换器就将消息发到对应的队列中。路由键与队列名完全匹配,如果一个队列绑定到交换机要求路由键为“dog”,则只转发 routing key 标记为“dog”的消息,不会转发“dog.puppy”,也不会转发“dog.guard”等等。它是完全
匹配、单播的模式。
每个发到 fanout 类型交换器的消息都会分到所有绑定的队列上去。fanout 交换器不处理路由键,只是简单的将队列绑定到交换器上,每个发送到交换器的消息都会被转发到与该交换器绑定的所有队列上。很像子网广播,每台子网内的主机都获得了一份复制的消息。fanout 类型转发消息是最快的。
topic 交换器通过模式匹配分配消息的路由键属性,将路由键和某个模式进行匹配,此时队列需要绑定到一个模式上。它将路由键和绑定键的字符串切分成单词,这些单词之间用点隔开。它同样也会识别两个通配符:符号“#”和符号“*”。#匹配0个或多个单词,*匹配一个单词。
四、RabbitMQ整合
- 引入 spring-boot-starter-amqp
- application.yml配置
- 测试RabbitMQ
- AmqpAdmin:管理组件
- RabbitTemplate:消息发送处理组件
三、Spring Boot与检索(ElasticSearch)
一、检索
我们的应用经常需要添加检索功能,开源的 ElasticSearch 是目前全文搜索引擎的首选。他可以快速的存储、搜索和分析海量数据。Spring Boot通过整合Spring Data ElasticSearch为我们提供了非常便捷的检索功能支持;
Elasticsearch是一个分布式搜索服务,提供Restful API,底层基于Lucene,采用多shard(分片)的方式保证数据安全,并且提供自动resharding的功能,github等大型的站点也是采用了ElasticSearch作为其搜索服务
二、概念
• 以 员工文档 的形式存储为例:一个文档代表一个员工数据。存储数据到
ElasticSearch 的行为叫做 索引 ,但在索引一个文档之前,需要确定将文档存储在哪里。
• 一个 ElasticSearch 集群可以 包含多个 索引 ,相应的每个索引可以包含多个 类型 , 这些不同的类型存储着多个 文档 ,每个文档又有 多个 属性 。
• 类似关系:
– 索引-数据库
– 类型-表
– 文档-表中的记录
– 属性-列
三、整合ElasticSearch测试
• 引入spring-boot-starter-data-elasticsearch
• 安装Spring Data 对应版本的ElasticSearch
• application.yml配置
• Spring Boot自动配置的
ElasticsearchRepository、ElasticsearchTemplate、Jest
• 测试ElasticSearch
package com.qq.springboot.Repository;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import com.qq.springboot.Bean.Book;
import javax.validation.constraints.Max;
import java.util.List;
public interface BookRepository extends ElasticsearchRepository<Book,Integer> {
public List<Book> findByBookName(String bookName);
}
@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringbootApplicationTests {
@Autowired
JestClient jestClient;
@Autowired
BookRepository bookRepository;
@Test
public void test02(){
Book book=new Book();
book.setId(1);
book.setAuthor("吴承恩");
book.setBookName("西游记");
bookRepository.index(book);
//查询
for(Book book1:bookRepository.findByBookName("游")){
System.out.println(book1);
}
}
@Test
public void contextLoads() {
//给ES中索引(保存)一个文档
Article article=new Article();
article.setId(1);
article.setTitle("好消息");
article.setAuthor("zs");
article.setContent("hello world");
//构建一个索引功能
Index index=new Index.Builder(article).index("qq").type("new").build();
try {
//执行
jestClient.execute(index);
} catch (IOException e) {
e.printStackTrace();
}
}
//测试搜索功能
@Test
public void search(){
//查询表达式
String json ="{\n" +
" \"query\" : {\n" +
" \"match\" : {\n" +
" \"content\" : \"hello\"\n" +
" }\n" +
" }\n" +
"}";
//构建搜索功能
Search search=new Search.Builder(json).addIndex("qq").addType("news").build();
//执行
try {
SearchResult result=jestClient.execute(search);
System.out.println(result.getJsonObject());
} catch (IOException e) {
e.printStackTrace();
}
}
}
四、Spring Boot与任务(异步任务、定时任务、邮件任务)
一、异步任务
在Java应用中,绝大多数情况下都是通过同步的方式来实现交互处理的;但是在处理与第三方系统交互的时候,容易造成响应迟缓的情况,之前大部分都是使用多线程来完成此类任务,其实,在Spring 3.x之后,就已经内置了@Async来完美解决这个问题。
两个注解:
@EnableAysnc、@Aysnc
二、定时任务
项目开发中经常需要执行一些定时任务,比如需要在每天凌晨时候,分析一次前一天的日志信息。Spring为我们提供了异步执行任务调度的方式,提供TaskExecutor 、TaskScheduler 接口。
两个注解:@EnableScheduling、@Scheduled
cron表达式:
@Service
public class AsyncService {
//告诉Spring这是一个异步方法
@Async
public void hello(){
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("处理数据....");
}
}
@Service
public class ScheduleService {
// @Scheduled(cron = "0 * * * * MON-SAT")
@Scheduled(cron = "0,1,2,3,4 * * * * MON-SAT")
public void hello(){
System.out.println("hello...");
}
}
@RestController
public class AsyncController {
@Autowired
AsyncService asyncService;
@GetMapping("/hello")
public String hello(){
asyncService.hello();
return "success";
}
}
@EnableAsync //开启异步注解功能
@EnableScheduling //开启基于注解的定时任务
@SpringBootApplication
public class SpringbootApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootApplication.class, args);
}
}
三、邮件任务
• 邮件发送需要引入spring-boot-starter-mail
• Spring Boot 自动配置MailSenderAutoConfiguration
• 定义MailProperties内容,配置在application.yml中
• 自动装配JavaMailSender
• 测试邮件发送
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
spring.mail.username=邮箱
spring.mail.password=skoidybzlftmdcih
spring.mail.host=smtp.qq.com
spring.mail.properties.mail.stmp.ssl.enable=true
@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringbootApplicationTests {
@Autowired
JavaMailSenderImpl mailSender;
//简单邮件
@Test
public void contextLoads() {
SimpleMailMessage mailMessage=new SimpleMailMessage();
//邮件设置
mailMessage.setSubject("通知");
mailMessage.setText("一步步靠近你");
mailMessage.setTo("接收的邮箱");
mailMessage.setFrom("发送的邮箱");
mailSender.send(mailMessage);
}
//复杂邮件
@Test
public void test02()throws Exception{
//创建一个复杂的消息邮件
MimeMessage mimeMessage=mailSender.createMimeMessage();
MimeMessageHelper helper=new MimeMessageHelper(mimeMessage,true);
//邮件设置
helper.setSubject("通知!");
helper.setText("<b style='color:red'>遇见你花光了所有勇气</b>",true);
helper.setTo("接收的邮箱");
helper.setFrom("发送的邮箱");
//上传文件
helper.addAttachment("1.jpg",new File("C:\\Users\\Pictures\\Saved Pictures\\1.jpg"));
helper.addAttachment("2.jpg",new File("C:\\Users\\Pictures\\Saved Pictures\\2.jpg"));
mailSender.send(mimeMessage);
}
}
五、Spring Boot与安全(安全、Spring Security)
一、安全
Spring Security是针对Spring项目的安全框架,也是Spring Boot底层安全模块默认的技术选型。他可以实现强大的web安全控制。对于安全控制,我们仅需引入spring-boot-starter-security模块,进行少量的配置,即可实现强大的安全管理。
几个类:
WebSecurityConfigurerAdapter:自定义Security策略
AuthenticationManagerBuilder:自定义认证策略
@EnableWebSecurity:开启WebSecurity模式
应用程序的两个主要区域是“认证”和“授权”(或者访问控制)。
这两个主要区域是Spring Security 的两个目标。
• “认证”(Authentication),是建立一个他声明的主体的过程(一个“主体”一般是指用户,设备或一些可以在你的应用程序中执行动作的其他系统)。
• “授权”(Authorization)指确定一个主体是否允许在你的应用程序执行一个动作的过程。为了抵达需要授权的店,主体的身份已经有认证过程建立。
• 这个概念是通用的而不只在Spring Security中。
二、Web&安全
- 登陆/注销
– HttpSecurity配置登陆、注销功能 - Thymeleaf提供的SpringSecurity标签支持
– 需要引入thymeleaf-extras-springsecurity4
– sec:authentication=“name”获得当前用户的用户名
– sec:authorize=“hasRole(‘ADMIN’)”当前用户必须拥有ADMIN权限时才会显示标签内容 - remember me
– 表单添加remember-me的checkbox
– 配置启用remember-me功能 - CSRF(Cross-site request forgery)跨站请求伪造
– HttpSecurity启用csrf功能,会为表单添加_csrf的值,提交携带来预防CSRF;
Controller:
@Controller
public class KungfuController {
private final String PREFIX = "pages/";
/**
* 欢迎页
* @return
*/
@GetMapping("/")
public String index() {
return "welcome";
}
/**
* 登陆页
* @return
*/
@GetMapping("/userlogin")
public String loginPage() {
return PREFIX+"login";
}
/**
* level1页面映射
* @param path
* @return
*/
@GetMapping("/level1/{path}")
public String level1(@PathVariable("path")String path) {
return PREFIX+"level1/"+path;
}
/**
* level2页面映射
* @param path
* @return
*/
@GetMapping("/level2/{path}")
public String level2(@PathVariable("path")String path) {
return PREFIX+"level2/"+path;
}
/**
* level3页面映射
* @param path
* @return
*/
@GetMapping("/level3/{path}")
public String level3(@PathVariable("path")String path) {
return PREFIX+"level3/"+path;
}
}
@EnableWebSecurity
public class MySecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
//定制请求的授权规则
httpSecurity.authorizeRequests().antMatchers("/").permitAll()
.antMatchers("/level1/**").hasRole("VIP1")
.antMatchers("/level2/**").hasRole("VIP2")
.antMatchers("/level3/**").hasRole("VIP3");
//开启自动配置的登录功能,如果没有权限,则跳转到登陆页面
httpSecurity.formLogin().usernameParameter("user").
passwordParameter("pwd").loginPage("/userlogin");
//1.login来到登录页
//2.重定向到/login?error表示登录失败
//开启自动配置的注销功能
httpSecurity.logout().logoutSuccessUrl("/"); //注销回到首页
//1.访问/logout表示用户注销,清空session
//2.注销成功会返回/login?logout页面
//开启记住我功能
httpSecurity.rememberMe().rememberMeParameter("remeber");
//登录成功之后,将cookie发给浏览器保存,以后访问页面带上这个cookie,只要通过检查就可以免登录
//点击注销删除cookie
}
//定义认证规则
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("zhangsan")
.password("123456").roles("VIP1","VIP2")
.and()
.withUser("lisi").password("123456").roles("VIP2","VIP3")
.and()
.withUser("wangwu").password("123456").roles("VIP1","VIP3");
}
}
六、Spring Boot与分布式(分步式、Dubbo/Zookeeper、Spring)
一、分布式应用
在分布式系统中,国内常用zookeeper+dubbo组合,而Spring Boot推荐使用全栈的Spring,Spring Boot+Spring Cloud。
分布式系统:
- 单一应用架构
当网站流量很小时,只需一个应用,将所有功能都部署在一起,以减少部署节点和成本。此时,用于简化增删改查工作量的数据访问框架(ORM)是关键。 - 垂直应用架构
当访问量逐渐增大,单一应用增加机器带来的加速度越来越小,将应用拆成互不相干的几个应用,以提升效率。此时,用于加速前端页面开发的Web框架(MVC)是关键。 - 分布式服务架构
当垂直应用越来越多,应用之间交互不可避免,将核心业务抽取出来,作为独立的服务,逐渐形成稳定的服务中心,使前端应用能更快速的响应多变的市场需求。此时,用于提高业务复用及整合的分布式服务框架(RPC)是关键。 - 流动计算架构
当服务越来越多,容量的评估,小服务资源的浪费等问题逐渐显现,此时需增加一个调度中心基于访问压力实时管理集群容量,提高集群利用率。此时,用于提高机器利用率的资源调度和治理中心(SOA)是关键。
二、Zookeeper和Dubbo
- ZooKeeper
ZooKeeper 是一个分布式的,开放源码的分布式应用程序协调服务。它是一个为分布式应用提供一致性服务的软件,提供的功能包括:配置维护、域名服务、分布式同步、组服务等。 - Dubbo
Dubbo是Alibaba开源的分布式服务框架,它最大的特点是按照分层的方式来架构,使用这种方式可以使各个层之间解耦合(或者最大限度地松耦合)。从服务模型的角度来看,Dubbo采用的是一种非常简单的模型,要么是提供方提供服务,要么是消费方消费服务,所以基于这一点可以抽象出服务提供方(Provider)和服务消费方(Consumer)两个角色。
https://github.com/alibaba/dubbo
• 1、安装zookeeper作为注册中心
• 2、编写服务提供者
• 3、编写服务消费者
• 4、整合dubbo
<dependency>
<groupId>com.alibaba.spring.boot</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>2.0.0</version>
</dependency>
三、Spring Boot和Spring Cloud
Spring Cloud
Spring Cloud是一个分布式的整体解决方案。Spring Cloud 为开发者提供了在分布式系统(配置管理,服务发现,熔断,路由,微代理,控制总线,一次性token,全局琐,leader选举,分布式session,集群状态)中快速构建的工具,使用Spring Cloud的开发者可以快速的启动服务或构建应用、同时能够快速和云平台资源进行对接。
- SpringCloud分布式开发五大常用组件
• 服务发现——Netflix Eureka
• 客服端负载均衡——Netflix Ribbon
• 断路器——Netflix Hystrix
• 服务网关——Netflix Zuul
• 分布式配置——Spring Cloud Config
Martin Fowler 微服务原文 https://martinfowler.com/articles/microservices.html
• Spring Cloud 入门
– 1、创建provider
– 2、创建consumer
– 3、引入Spring Cloud
– 4、引入Eureka注册中心
– 5、引入Ribbon进行客户端负载均衡
七、Spring Boot与开发热部署
一、热部署
在开发中我们修改一个Java文件后想看到效果不得不重启应用,这导致大量时间花费,我们希望不重启应用的情况下,程序可以自动部署(热部署)。有以下四种情况,如何能实现热部署。
• 1、模板引擎
– 在Spring Boot中开发情况下禁用模板引擎的cache
– 页面模板改变ctrl+F9可以重新编译当前页面并生效
2、Spring Loaded
Spring官方提供的热部署程序,实现修改类文件的热部署
– 下载Spring Loaded(项目地址https://github.com/spring-projects/spring-loaded)
– 添加运行时参数;
-javaagent:C:/springloaded-1.2.5.RELEASE.jar –noverify
3、JRebel
– 收费的一个热部署软件
– 安装插件使用即可
4、Spring Boot Devtools(推荐)
– 引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
– IDEA使用ctrl+F9
– 或做一些小调整
Intellij IEDA和Eclipse不同,Eclipse设置了自动编译之后,修改类它会自动编译,而IDEA在非RUN或DEBUG情况下
才会自动编译(前提是你已经设置了Auto-Compile)。
• 设置自动编译(settings-compiler-make project automatically)
• ctrl+shift+alt+/(maintenance)
• 勾选compiler.automake.allow.when.app.running
八、Spring Boot与监控管理
一、监控管理
通过引入spring-boot-starter-actuator,可以使用Spring Boot为我们提供的准
生产环境下的应用监控和管理功能。我们可以通过HTTP,JMX,SSH协议来进行操作,自动得到审计、健康及指标信息等
• 步骤:
– 引入spring-boot-starter-actuator
– 通过http方式访问监控端点
– 可进行shutdown(POST 提交,此端点默认关闭)
• 监控和管理端点
二、定制端点信息
server.port=8080
management.security.enabled=false
spring.redis.host=localhost
info.app.id=hello
info.app.version=1.0.0
#endpoints.actuator.enabled=false
endpoints.shutdown.enabled=true
#endpoints.beans.id=mybean
#endpoints.beans.path=/bean
#endpoints.beans.enabled=false
#endpoints.dump.path=/du
#关闭所有端点访问
#endpoints.enabled=false
#endpoints.beans.enabled=true
management.context-path=/manage
management.port=8181
– 定制端点一般通过endpoints+端点名+属性名来设置。
– 修改端点id(endpoints.beans.id=mybeans)
– 开启远程应用关闭功能(endpoints.shutdown.enabled=true)
– 关闭端点(endpoints.beans.enabled=false)
– 开启所需端点
• endpoints.enabled=false
• endpoints.beans.enabled=true
– 定制端点访问根路径
• management.context-path=/manage
– 关闭http端点
• management.port=-1
@Component
public class MyAppHealthIndicator implements HealthIndicator {
@Override
public Health health() {
//自定义的检查方法
//Health.up().build()代表健康
return Health.down().withDetail("msg","服务异常").build();
}
}