SpringBoot与缓存 Spring缓存抽象 缓存注解 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 Cache 缓存接口,定义缓存操作。实现又:RedisCache、EhCacheCache、ConcurrentMapCaChe等 CacheManager 缓存管理器,管理各种缓存(Cache)组件 @Cacheable 主要针对方法配置,能够根据方法的请求参数对其结果进行缓存 @CacheEvict 清空缓存 @CachePut 保证方法被调用,又希望结果被缓存 @EnableCaching 开启基于注解的缓存 keyGenerator 缓存数据时key生成策略 serialize 缓存数据时value序列化策略
导入依赖 1 2 3 4 <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-cache</artifactId > </dependency >
启动类添加注解
详解 @Cacheable 主要针对方法配置,能够根据方法的请求参数对其结果进行缓存
在ServerImpl方法上添加@Cacheable
@Cacheable参数说明
cacheName/value:指定缓存组件的名字;将方法的返回值结果放在哪个缓存中,是数组的方式,可以指定多个缓存
key:缓存数据使用的key:可以用它来指定,默认是使用方法参数的值
编写SpEL指定 key
keyGenerator:key生成器,可以自己指定key的生成器的组件id
key/keyGenertor 二选一
cacheManager:指定缓存管理器:或者cacheResolver指定获取解析器
condition:指定符合条件情况下才缓存
unless:否定缓存:当unless指定的条件为true,方法的返回值就不会被缓存,可以获得结果进行判断
sync:是否使用异步模式
@CachPut 即调用方法,又更新缓存数据,修改了数据库的某个数据,同时更新缓存
运行时机:先调用目标方法,在将结果缓存
key要和要更新缓存的key一样
@CacheEvict 缓存清除,如删除数据之后删除缓存
参数说明:
allEntries = false 删除对应key里的所有缓存数据,true为删除所有
beforeInvocation = false, 缓存的清除是否在方法之前执行,true为是
注意 :开启之后如果方法出错,缓存还是会被清除
@Caching 指定多个缓存规则
例
1 2 3 4 5 6 7 8 9 @Caching ( cacheable = { @Cacheable (value="xxx" ,key="xxx" ) }, put = { @CachePut (value="xxx" ,key="xxx" ), @CachePut (Value="xxx" ,key="xxx" ) } )
@CacheConfig 定义在类上,抽取缓存的公共配置
@CacheConfig(cacheNames=”xxx”)意思是所有的key都叫这个名字
使用Redis缓存数据 导入依赖
1 2 3 4 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>
spring会自动配置Redis,实实用缓存注解缓存数据的时候默认就使用Redis缓存数据了
SpringBoot与消息
RabbitMQ简介 https://jingganghuluwa.github.io/2020/03/19/RabbitMQ/
SpringBoot与检索 中文网https://www.elastic.co/guide/cn/elasticsearch/guide/current/_retrieving_a_document.html
检索
使用docker安装elasticsearch 运行
1 docker run -e ES_JAVA_OPTS="-Xms512m -Xmx512m" -d -p 9200:9200 -p 9300:9300 --name ES01 容器ID
配置elasticsearch
进入elasticsearch,安装vim
进入config目录下修改elasticsearch.yml
1 2 3 4 cluster.name: "docker-cluster" network.host: 0.0.0.0 http.cors.enabled: true http.cors.allow-origin: "*"
测试连接成功
浏览器安装插件 Elasticsearch Head方便查看信息
浏览器打开http://192.168.156.128:9200/
概念
关系图
类似于MySQL
索引 = 数据库
类型 = 表
文档 = 一行数据
属性 = 一行数据的某个属性
创建一个雇员目录
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 PUT /megacorp/employee/1 { "first_name" : "John" , "last_name" : "Smith" , "age" : 25 , "about" : "I love to go rock climbing" , "interests" : [ "sports" , "music" ] } PUT /megacorp/employee/2 { "first_name" : "Jane" , "last_name" : "Smith" , "age" : 32 , "about" : "I like to collect rock albums" , "interests" : [ "music" ] } PUT /megacorp/employee/3 { "first_name" : "Douglas" , "last_name" : "Fir" , "age" : 35 , "about" : "I like to build cabinets" , "interests" : [ "forestry" ] }
使用postman操作
检索刚刚存入的数据
其他请求类型 DELETE 删除
HEAD 判断是否有数据,有数据状态码为200,没有的话就404
轻量搜索 查询所有的信息
1 GET http://192.168.156.128:9200/_search
文档里都有不写了
https://www.elastic.co/guide/cn/elasticsearch/guide/current/_search_lite.html
SpringBoot整合elasticsearch 导入依赖
1 2 3 4 5 6 7 8 <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-data-elasticsearch</artifactId > </dependency > <dependency > <groupId > org.projectlombok</groupId > <artifactId > lombok</artifactId > </dependency >
配置application.properties
1 2 spring.data.elasticsearch.cluster-name =elasticsearch spring.data.elasticsearch.cluster-nodes =192.168.156.128:9300
在 pojo包下 编写实体类Book
1 2 3 4 5 6 7 8 9 10 11 12 13 14 package cn.duxiu.pojo;import lombok.AllArgsConstructor;import lombok.Data;import lombok.NoArgsConstructor;@Data @NoArgsConstructor @AllArgsConstructor public class Book { private Integer id; private String bookName; private String author; }
在repository包下编写BookRepository接口
1 2 3 4 5 6 7 package cn.duxiu.repository;import cn.duxiu.pojo.Book;import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;public interface BookRepository extends ElasticsearchRepository <Book ,Integer > {}
编写测试类测试
1 2 3 4 5 6 7 @Test public void t1 () { Book book = new Book(); bookRepository.index(book); } }
在BookRepository中自定义方法,规则和SpringDataJPA相似
1 2 public List<Book> findByBookNameLike (String bookName) ;
测试
1 2 3 4 5 @Test public void t2 () { List<Book> list = bookRepository.findByBookNameLike("游" ); list.forEach(System.out::println); }
参考Spring官方文档
https://docs.spring.io/spring-data/elasticsearch/docs/3.2.6.RELEASE/reference/html/#new-featuresv
SpringBoot与任务 异步 启动类上添加注解
service包下编写AsyncService
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 @Service public class AsyncService { @Async public void hello () { try { Thread.sleep(3000 ); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("处理数据中..." ); } }
controller包下编写AsyncController
1 2 3 4 5 6 7 8 9 10 11 12 @RestController public class AsyncController { @Autowired AsyncService asyncService; @GetMapping ("/hello" ) public String hello () { asyncService.hello(); return "success" ; } }
使用了异步之后,立即响应输出了success,随后”处理数据中…”也输出完毕
而未使用异步就会等”处理数据中…”也输出完毕再打印success
定时任务
启动类上添加注解
在service包写编写ScheduledService
1 2 3 4 5 6 7 8 9 10 11 @Service public class ScheduledService { @Scheduled (cron = "0 * * * * MON-FRI" ) public void hello () { System.out.println("hello...." ); } }
邮件任务
导入依赖
1 2 3 4 <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-mail</artifactId > </dependency >
以QQ邮箱发送为例
设置QQ邮箱先进入QQ邮箱账户设置
得到授权码
配置application.properties
1 2 3 spring.mail.username=1839743406@qq.com spring.mail.password=授权码 spring.mail.hot=smtp.qq.com
普通邮件发送 编写测试类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 @Autowired JavaMailSenderImpl mailSender; @Test public void contextLoads () { SimpleMailMessage message = new SimpleMailMessage(); message.setSubject("通知,今晚开会" ); message.setText("今晚七点开会" ); message.setTo("jinganghuluwaa@gmail.com" ); message.setFrom("1839743406@qq.com" ); mailSender.send(message); }
成功发送
复杂邮件发送 测试类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 @Test public void t2 () throws Exception { MimeMessage mailMessage = mailSender.createMimeMessage(); MimeMessageHelper helper = new MimeMessageHelper(mailMessage,true ); helper.setSubject("通知,今晚开会" ); helper.setText("<b style='color:red'>今晚七点开会</b>" ,true ); helper.setTo("jinganghuluwaa@gmail.com" ); helper.setFrom("1839743406@qq.com" ); helper.addAttachment("1.jpg" ,new File("F:\\壁纸\\Minecraft.jpg" )); helper.addAttachment("2.jpg" ,new File("F:\\壁纸\\Minecraft2.jpg" )); mailSender.send(mailMessage); }
SpringBoot与安全 https://jingganghuluwa.github.io/2020/03/18/Shiro/
SpringBoot与分布式 分布式应用
Zookeeper和Dubbo
Docker安装Zookeeper 拉取镜像
运行 1 docker run --privileged=true --restart=always -d --name zookeeper --publish 2181:2181 -d zookeeper:latest
常用zookepper操作命令 进入容器后
1 2 3 zkCli.sh 连接客户端 ls/ 查看根目录下包含的节点 ls /services 查看已注册进来的服务
创建工程
new一个Module
创建Spring Inirializr
勾选 web 模块,这个是买票子工程
在service包下创建TicketService,模拟卖票
1 2 3 4 public interface TicketService { public String getTicket () ; }
创建实现类TicketService
1 2 3 4 5 6 7 public class TicketServiceImpl implements TicketService { @Override public String getTicket () { return "《文体两开花》" ; } }
再创建一个module,模拟买票,也就是用户,消费者
service包下创建UserService
1 2 3 public class UserService {}
服务流程 1、将服务提供则注册到注册中心
在模块 Ticket 中导入依赖
1 2 3 4 5 6 7 8 9 10 11 12 13 <dependency > <groupId > com.alibaba.boot</groupId > <artifactId > dubbo-spring-boot-starter</artifactId > <version > 0.1.0</version > </dependency > <dependency > <groupId > com.github.sgroschupf</groupId > <artifactId > zkclient</artifactId > <version > 0.1</version > </dependency >
配置 Ticket 下的application.properties
1 2 3 dubbo.application.name =provider-ticket dubbo.registry.address =zookeeper://192.168.156.128:2181 dubbo.scan.base-packages =cn.duxiu.ticket.service
修改 TicketServiceImpl
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 @Component @Service @EnableDubbo public class TicketServiceImpl implements TicketService { @Override public String getTicket () { return "《文体两开花》" ; } }
启动 Ticket,然之后会报错
启动后在消费者 Consumer-user 下导入依赖
1 2 3 4 5 6 7 8 9 10 11 12 13 <dependency > <groupId > com.alibaba.boot</groupId > <artifactId > dubbo-spring-boot-starter</artifactId > <version > 0.1.0</version > </dependency > <dependency > <groupId > com.github.sgroschupf</groupId > <artifactId > zkclient</artifactId > <version > 0.1</version > </dependency >
配置Consumer-user下的application.properties
1 2 dubbo.application.name =consumer-user dubbo.registry.address =zookeeper://192.168.156.128:2181
将Ticket下的 service整个包复制到 Consumer 下
只需要TicketService和包目录,其他的可以删掉
Consumer下编写测试类
1 2 3 4 5 6 7 8 9 10 11 12 13 @SpringBootTest class ConsumerUserApplicationTests { @Autowired UserService userService; @Test void contextLoads () { userService.hello(); } }
重启Ticket ,必须要保证Ticket运行,运行测试类
完事
SpringBoot和SpringCloud
创建工程 Empty Project
创建模块 eureka-server 注册中心
依赖选择
创建第二个模块,provoder-titck 服务提供者
选择依赖, 服务注册和发现 模块
创建第三个模块,consumer-user 服务消费者
配置eureka-seerver 里的 application.yml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 server: port: 8761 eureka: instance: hostname: eureka-server client: register-with-eureka: false fetch-registry: false service-url: defaultZone: http://192.168.156.128:8761/eureka/
eureka-seerver 启动类上添加注解
运行
配置provider-ticket 服务提供者 下的application.yml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 server: port: 8001 spring: application: name: provider-ticket eureka: instance: prefer-ip-address: true client: service-url: defaultZone: http://localhost:8761/eureka/
在service 包下编写 TicketService
1 2 3 4 5 6 7 @Service public class TicketService { public String getTicket () { return "《文体两开花》" ; } }
在controller 下编写 TicketController
1 2 3 4 5 6 7 8 9 10 11 @RestController public class TicketController { @Autowired TicketService ticketService; @GetMapping ("/ticket" ) public String getTicket () { return ticketService.getTicket(); } }
先重启 eureka-server 再启动 provider-ticket
浏览器访问 http://localhost:8001/ticket
注册中心
同一个应用部署多个实例注册到注册中心中 为了测试方便 TicketService 加上一句输出
1 2 3 4 5 6 7 8 @Service public class TicketService { public String getTicket () { System.out.println("8001" ); return "《文体两开花》" ; } }
将provider-ticket 打包
双击打包
将打好的包复制出来,做好标记
继续 更改 yml 文件 端口改成 8002 输出语句改成8002 打包
从文件夹内进入CMD 运行 两个jar 包
再去注册中心瞅一眼
成功
consumer-user消费 配置consumer-user模块的application.yaml
1 2 3 4 5 6 7 8 9 10 11 12 13 spring: application: name: consumer-user server: port: 8200 eureka: instance: prefer-ip-address: true client: service-url: defaultZone: http://localhost:8761/eureka/
修改consumer-user模块的启动类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 @EnableDiscoveryClient @SpringBootApplication public class ConsumerUserApplication { public static void main (String[] args) { SpringApplication.run(ConsumerUserApplication.class , args ) ; } @LoadBalanced @Bean public RestTemplate restTemplate () { return new RestTemplate(); } }
controller包下创建
1 2 3 4 5 6 7 8 9 10 11 12 @RestController public class UserController { @Autowired RestTemplate restTemplate; @GetMapping ("/buy" ) public String buyTicket (String name) { String s = restTemplate.getForObject("http://PROVIDER-TICKET/ticket" , String.class ) ; return name + "购买了" + s; } }
运行 eureka-server,再运行刚刚那两个打好包的 provider-ticket,再运行consumer-user
查看注册中心
调用 consumer-user 的买票方法
因为使用了负载均衡,查看 cmd 启动的 provider- ticket
使用轮询的方式负载均衡
热部署 IDEA安装插件
JRebel and XRebel for IntelliJ
启动项目会弹个窗口出来,点击红色箭头标的地方
https://blog.csdn.net/qierkang/article/details/95095954
教程