SpringBoot笔记
缓存
1,初识cache–@Cacheable
- 在主入口的类上加注解==@EnableCaching==
- controller
/**
* @Cacheable注解的说明
* cacheNames/value (缓存组件的名字)
* key (缓存数据使用的值)用于指定
* keyGenerator : key的生成器 key和 keyGenerator 二选一
* cacheManager : 指定缓存管理器
* cacheResolver : 指定获取解析器
* condition :符合条件才缓存
* unless : 否定 才缓存
* sync :是否使用异步
* @param id
* @return
*/
@Cacheable(value = {"emp"},key = "#root.methodName+'['+#id+']'")
@Override
public Employee getEmpById(Integer id) {
return employeeMapper.getEmpById(id);
}
2,@Cacheable缓存工作原理
- 先到缓存中找,如果没有才去调用方法查数据库,再把值放进缓存里
3,@Cacheable的其他属性
- key
指定key
@Cacheable(value = {"emp"},key = "#root.methodName+'['+#id+']'")
- keyGenerator
@Cacheable(value = {"emp"},keyGenerator = "MykeyGenerator")
编写MyCacheConfig
@Configuration
public class MyCacheConfig {
@Bean("MykeyGenerator")
public KeyGenerator keyGenerator(){
return new KeyGenerator(){
@Override
public Object generate(Object target, Method method, Object... params) {
return target.getClass()+"::"+method.getName()+"params:{"+ Arrays.asList(params).toString() +"}";
}
};
}
}
- condition
只缓存输入id=1的
@Cacheable(value = {"emp"},condition = "#id==1")
- unless
输入的id=1 不缓存
@Cacheable(value = {"emp"},keyGenerator = "MykeyGenerator",unless = "#id==1")
- sync :是否使用异步
默认是 false :方法执行完以同步的方式将方法的结果存在缓存中
4,@CachePut
- 先调方法,再把方法的结果放进缓存中
注意:key要与查询的key保持一致
@CachePut(value = {"emp"},key = "#employee.id")
@Override
public void updateEmp(Employee employee) {
employeeMapper.updateEmp(employee);
}
5,@CacheEvict
/**
* @CacheEvict:清除缓存
* key:指定要清除的数据
* allEntries=true:清除这个缓存所有的数据
* beforeInvocation:缓存的清除是否在方法之前执行
* 默认代表是在方法执行之后执行=false
* @param id
*/
@CacheEvict(value = "emp"/*,key = "#id"*//*,allEntries = true*/)
@Override
public void deleteEmpById(Integer id) {
// employeeMapper.deleteEmpById(id);
}
6,@CacheConfig
- 抽取缓存的公共配置
7,Caching
- 前后都有把值存进缓存中
- 一开始是lastName
- 调用getEmpByLastName()后 把 id 和 email 也存进缓存里了
Redis Template
- 要使用 Redis 导入jar
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<version>2.2.5.RELEASE</version>
</dependency>
- 在application.xml中配置属性
spring:
redis:
port: 6379
host: *******
password: *****
1,存值
@Autowired
private StringRedisTemplate stringRedisTemplate;
@Test
void TestRedis(){
// stringRedisTemplate.opsForValue().append("msg","helloword");
String msg = stringRedisTemplate.opsForValue().get("msg");
System.out.println(msg);
}
2,存对象
报错–没有序列化
org.springframework.data.redis.serializer.SerializationException: Cannot serialize;
解决:
public class Employee implements Serializable
- test
@Autowired
RedisTemplate redisTemplate;
@Test
void TestRedis02(){
Employee empById = employeeMapper.getEmpById(1);
redisTemplate.opsForValue().set("emp",empById);
}
不提倡直接用序列化的方式存值,
- Java的序列化不能跨语言
- JDK序列化慢 JSON的速度快
- 建议
@Autowired
RedisTemplate<Object,Object> objRedisTemplate;
@Test
void TestRedis03(){
Employee empById = employeeMapper.getEmpById(1);
objRedisTemplate.opsForValue().set("emp-list",empById);
}
- RedisSerConfig
@Configuration
public class RedisSerConfig {
@Bean(value = "objRedisTemplate")
public RedisTemplate<Object,Object> objRedisTemplate(
RedisConnectionFactory redisConnectionFactory){
RedisTemplate<Object, Object> template = new RedisTemplate<>();
template.setConnectionFactory(redisConnectionFactory);
Jackson2JsonRedisSerializer<Object> j = new Jackson2JsonRedisSerializer<>(Object.class);
template.setDefaultSerializer(j);
return template;
}
}
- 通用的Redis序列化模板
@Configuration
public class RedisConfig {
// 自己定义了一个 RedisTemplate
@Bean
@SuppressWarnings("all")
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
// 我们为了自己开发方便,一般直接使用 <String, Object>
RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
template.setConnectionFactory(factory);
// Json序列化配置
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);
// String 的序列化
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
// key采用String的序列化方式
template.setKeySerializer(stringRedisSerializer);
// hash的key也采用String的序列化方式
template.setHashKeySerializer(stringRedisSerializer);
// value序列化方式采用jackson
template.setValueSerializer(jackson2JsonRedisSerializer);
// hash的value序列化方式采用jackson
template.setHashValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
}
}
消息
RabbitMQ
1,接收与发送消息
- application.yaml
spring:
rabbitmq:
host: ***
username: ***
password: ***
port: 5672
- test
@Autowired
RabbitTemplate rabbitTemplate;
@Test//单播 点对点
void contextLoads() {
//Message需要自己构造,定义消息头和消息内容
// rabbitTemplate.send();
//默认object为消息体,只需要传入要发送的对象,自动序列化发送给rabbitmq
HashMap<String, Object> map = new HashMap<>();
map.put("msg","这是一条消息");
map.put("list", Arrays.asList("hello",123,true));
rabbitTemplate.convertAndSend("exchange.direct","wu.news",map);
}
//接收 --- 接收到了从消息队列中删除,再次执行会空指针异常
@Test
public void receive(){
Object o = rabbitTemplate.receiveAndConvert("wu.news");
System.out.println(o.getClass());
System.out.println(o);
}
- 结果
更改序列化方式–json
import org.springframework.amqp.support.converter.MessageConverter;
@Configuration
public class MyAMQPConfig {
@Bean
public MessageConverter messageConverter(){
return new Jackson2JsonMessageConverter();
}
}
2,广播
//广播
@Test
public void sendMsg(){
rabbitTemplate.convertAndSend("exchange.fanout","",new Book("幻","李白"));
}
消息监听
- 在main中添加注解 @EnableRabbit
import org.springframework.amqp.core.Message;
@Service
public class MyService {
@RabbitListener(queues = "wu.emps")
public void receive01(Book book){
System.out.println("1::"+"收到消息:"+book.toString());
}
@RabbitListener(queues = "wu.emps")
public void receive02(Message message){
System.out.println("2::"+message.getBody());
System.out.println("3::"+message.getMessageProperties());
}
/*@RabbitListener(queues = {"wu","wu.news"})
public void receive03(Message message){
System.out.println("{\"wu.emps\",\"wu.news\"}::::");
System.out.println("4::"+message.getBody());
System.out.println("5::"+message.getMessageProperties());
}*/
}
3,AmqpAdmin
public void createExchange(){
//创建Exchange
amqpAdmin.declareExchange(new DirectExchange("amqpadmin.exchange"));
System.out.println("done");
//queue
amqpAdmin.declareQueue(new Queue("amqpadmin.quene",true));
//绑定
amqpAdmin.declareBinding(new Binding("amqpadmin.quene",Binding.DestinationType.QUEUE,
"amqpadmin.exchange","rounting.haha",null));
}
检索
- 访问路径地址,出现如下为部署成功
- 什么是索引
存储数据到 Elasticsearch 的行为叫做 索引
我的理解:
ES集群—可以连接多个数据库的东西
索引—数据库
类型—表
文档—表的一条记录–json数据
属性—表的字段
你可以发送GET,HEAD,PUT,DELETE请求,分别表示获取,检查是否存在(看status返回状态码),增加/修改,删除
分布式-springboot-dubbo-zookeeper整合
实现远程调用
1,在消费者-提供者中都-导入Dubbo相关依赖和zookeeper客户端
<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>
2,提供者
- application.properties
dubbo.application.name=providerticket
dubbo.registry.address=zookeeper://*********:2181
dubbo.scan.base-packages=com.wu.providerticket.service
- TicketService.java
public interface TicketService {
String getTicket();
}
- TicketServiceImpl.java
package com.wu.providerticket.service;
import com.alibaba.dubbo.config.annotation.Service;
@org.springframework.stereotype.Service
@Service
public class TicketServiceImpl implements TicketService{
@Override
public String getTicket() {
return "<厉害了,我的果>!";
}
}
2,消费者
- application.properties
dubbo.application.name=providerticket
dubbo.registry.address=zookeeper://**********:2181
- 在消费者案例中新建包
- UserService.java
使用@Reference 注解 远程引用实现类
@Service
public class UserService {
@Reference //远程引用实现类
TicketService ticketService;
public void hello(){
String ticket = ticketService.getTicket();
System.out.println("买到票:"+ticket);
}
}
注意两个案例在主启动类中都要写上注解:@EnableDubbo
效果: