0%

日常踩坑 2019-3-4

记两个小坑…

  1. Spring Cache condition And unless 弄反了

不缓存 null, 写成了 condition = "#result != null, 表示: 当入参 result 不为空时缓存执行结果.

正确写法应该为 unless = "#result == null", 表示: 当返回值为 null 时不缓存.

  1. 消息队列初始化时机不正确

我使用了 @PostConstruct 在Spring初始化完成后开始处理消息, 这是不正确的, 一定程度上会阻塞系统启动, 应该要在系统初始化完成后才开始处理消息.

Spring Cache

@Cacheable

  • key

cache key, 默认按照方法所有的参数进行组合(toString).

  • value

cache name, 缓存名称, 必须指定至少一个.

  • condition

入参条件, 返回 true OR false, 只有入参判断为 true 才进行缓存.

  • unless

结果条件, 排除判断为 true 的, 其他的都进行缓存, 下面的样例是不缓存 return null

1
@Cacheable(unless = "#result == null")

@CachePut

  • key
  • value
  • condition

@CacheEvict

  • key
  • value
  • condition
  • allEntries

是否情况所有缓存内容, 默认为 false

  • beforeInvocation

方法执行前就清空缓存, 默认为false, 如果为 true 会导致执行出现异常也清掉缓存.


消息队列消费者何时开始初始化?

@PostConstruct

在Spring容器加载完成后执行被该注解修饰的方法.

一开始我使用的是该注解, 导致系统还没起来就去处理消息, 消息差不多处理完才启动系统, 卡半天接口还没暴露出来, 严重拖慢系统启动时间, 影响系统正常运行, 总之不能这样玩!!!

ApplicationListener

系统启动完成后执行实现的 onApplicationEvent 方法, 将初始化消费者任务丢进去执行即可.

  • 先将每个消费者存进Map
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
public interface MQProcessor {

Logger log = LoggerFactory.getLogger(MQProcessor.class);

Map<String, MQProcessor> mqProcessorMap = new ConcurrentHashMap<>();

String getTag();

void startConsumer();

void process(Message message, ConsumeContext context);
}

public abstract class AbstractMQProcessor implements MQProcessor {

protected ExecutorService subExecutorService = Executors.newFixedThreadPool(30);

protected abstract String getTopic();

public abstract void initConsumer();

public void startConsumer() {
initConsumer();
}

@PostConstruct
void init() {
mqProcessorMap.put(getTopic() + ":" + getTag(), this);
}
}
  • 系统启动完成后执行
1
2
3
4
5
6
7
8
9
10
11
12
13
@Component
public class ApplicationReadyEventListener implements ApplicationListener<ApplicationReadyEvent> {
private static Logger logger = LoggerFactory.getLogger(ApplicationReadyEventListener.class);

@Override
public void onApplicationEvent(ApplicationReadyEvent event) {
logger.info("spring boot start success!!");

MQProcessor.mqProcessorMap.forEach((s, mqProcessor) -> {
mqProcessor.startConsumer();
});
}
}