Dawn's Blogs

分享技术 记录成长

0%

Spring Boot学习 (4) 缓存 定时任务

缓存

Spring 框架提供了透明添加缓存到应用程序的支持。 只要通过使用 @EnableCaching 注解启用缓存支持,Spring Boot就会自动配置缓存基础设施。

Spring Cache

Spring Boot 提供的缓存包括:JCache、Redis、Simple 等。通过 spring.cache.type 配置参数来指定缓存类型,当该值为 None 时为完全禁用缓存。

在方法上使用 @Cachable、@CacheEvict、@CachePut 表示缓存的行为。

Simple

Simple 作为默认的缓存实现,使用 ConcurrentHashMap 作为缓存存储。

Redis

如果已经引入了 spring-boot-starter-redis,缓存的配置信息可以通过 spring.cache.redis.* 来设置。

如果需要对配置信息进行更多的控制,可以考虑注册一个 RedisCacheManagerBuilderCustomizer bean。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import java.time.Duration;

import org.springframework.boot.autoconfigure.cache.RedisCacheManagerBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;

@Configuration(proxyBeanMethods = false)
public class MyRedisCacheManagerConfiguration {

@Bean
public RedisCacheManagerBuilderCustomizer myRedisCacheManagerBuilderCustomizer() {
return (builder) -> builder
.withCacheConfiguration("cache1", RedisCacheConfiguration
.defaultCacheConfig().entryTtl(Duration.ofSeconds(10)))
.withCacheConfiguration("cache2", RedisCacheConfiguration
.defaultCacheConfig().entryTtl(Duration.ofMinutes(1)));

}

}

@Configuration 注解:

  • @Configuration 是 Spring 框架提供的一个元注解,用于表示一个类是一个配置类。
  • 配置类通常包含 @Bean 注解,定义了创建和配置 Bean 的方法。
  • Spring 会扫描 @Configuration 类,并将其中的 @Bean 方法注册为 Spring 容器中的 Bean(name 默认为方法名)。

@Configuration 注解的 proxyBeanMethods 属性:用于控制@Bean方法的代理行为,默认为 true。

  • 当 proxyBeanMethods 属性设置为 true 时,Spring 会对 @Configuration 类进行 CGLIB 代理。调用 @Bean 方法时,Spring 会检查是否已经存在该 Bean,如果存在,则直接返回已存在的 Bean,否则调用方法创建新的 Bean 并缓存起来。
  • 当 proxyBeanMethods 属性设置为 false 时,会禁用 CGLIB 代理。这种情况下,每一次调用 @Bean 都会执行一次方法体,不会缓存 Bean 对象,适用于那些需要每次返回新实例的场景

JetCache

JetCache 是一个基于 Java 的缓存系统封装,提供统一的 API 和注解来简化缓存的使用。 JetCache 提供了比 SpringCache 更加强大的注解,可以原生的支持 TTL、两级缓存、分布式自动刷新,还提供了 Cache 接口用于手工缓存操作,支持 Spring Boot、支持统计信息。 目前有四个实现:

  • 远程缓存:
    • redis
    • tair
  • 本地缓存:
    • caffeine
    • linked hash map

@EnableMethodCache、@EnableCreateCacheAnnotation 这两个注解分别激活 @Cached 和 @CreateCache 注解。也就是说,可以直接使用 @Cached 实现方法缓存,或者使用创建一个 Cache 实例两种方式,来使用 JetCache。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package com.company.mypackage;

import com.alicp.jetcache.anno.config.EnableCreateCacheAnnotation;
import com.alicp.jetcache.anno.config.EnableMethodCache;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
@EnableMethodCache(basePackages = "com.company.mypackage")
@EnableCreateCacheAnnotation
public class MySpringBootApp {
public static void main(String[] args) {
SpringApplication.run(MySpringBootApp.class);
}
}

配置信息参见:https://github.com/alibaba/jetcache/blob/master/docs/CN/Config.md

创建 Cache 实例

有两种方法创建 Cache 实例,分别是 CacheManager 和 @CacheCreate 注解(在jetcache 2.7 版本CreateCache注解已经废弃)。

  • 使用 CacheManager 可以创建 Cache 实例,area 和 name 相同的情况下,它和 Cached 注解使用同一个 Cache 实例。
1
2
3
4
5
6
7
8
9
10
11
12
13
@Autowired
private CacheManager cacheManager;
private Cache<String, UserDO> userCache;

@PostConstruct
public void init() {
QuickConfig qc = QuickConfig.newBuilder("userCache")
.expire(Duration.ofSeconds(100))
.cacheType(CacheType.BOTH) // two level cache
.syncLocal(true) // invalidate local cache in all jvm process after update
.build();
userCache = cacheManager.getOrCreateCache(qc);
}
  • 使用 @CreateCache 注解创建一个Cache实例,在jetcache 2.7 版本CreateCache注解已经废弃
1
2
@CreateCache(expire = 100)
private Cache<Long, UserDO> userCache;

方法缓存

在 spring 环境下,使用 @Cached 注解可以为一个方法添加缓存,@CacheUpdate 用于更新缓存,@CacheInvalidate 用于移除缓存元素。

1
2
3
4
5
6
7
8
9
10
public interface UserService {
@Cached(name="userCache.", key="#userId", expire = 3600)
User getUserById(long userId);

@CacheUpdate(name="userCache.", key="#user.userId", value="#user")
void updateUser(User user);

@CacheInvalidate(name="userCache.", key="#userId")
void deleteUser(long userId);
}

定时任务

Quartz

Spring Boot 提供了 Quartz 的 starter,spring-boot-starter-quartz。如果 Quartz 可用,就会自动配置一个 Scheduler。以下类型的 Bean 会被自动装配并与 Scheduler 关联:

  • JobDetail:定义了一个特定的 Job。 JobDetail 实例可以通过 JobBuilder API建立。
  • Calendar
  • Trigger:定义了一个特定的 Job 何时被触发。

定义任务

通过继承 QuartzJobBean 来定义自己的任务,重写 executeInternal 方法,并且可以通过 setter 注入属性。

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
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

import org.springframework.scheduling.quartz.QuartzJobBean;

public class MySampleJob extends QuartzJobBean {

private MyService myService;

private String name;

// Inject "MyService" bean
public void setMyService(MyService myService) {
this.myService = myService;
}

// Inject the "name" job data property
public void setName(String name) {
this.name = name;
}

@Override
protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
this.myService.someMethod(context.getFireTime(), this.name);
}

}

持久化任务

默认情况下,使用内存中的 JobStore。 然而,如果你的应用程序中有一个 DataSource Bean,并且相应地配置了 spring.quartz.job-store-type 属性,也可以配置一个基于 JDBC 的 store。

要让 Quartz 使用应用程序主 DataSource 以外的 DataSource,可以声明一个 DataSource bean,用 @QuartzDataSource 注释其 @Bean 方法。这样做可以确保Quartz特定的数据源被 SchedulerFactoryBean 和schema初始化所使用。

同样地,为了让 Quartz 使用应用程序的主 TransactionManager 以外的 TransactionManager,需要声明一个 TransactionManager Bean,用 @QuartzTransactionManager 注释其 @Bean 方法。

默认情况下,通过配置创建的Job不会覆盖已经从持久性 JobStore 中读取的已注册Job。 要启用覆盖现有作业定义,需要设置 spring.quartz.overwrite-existing-jobs 属性。

Spring Task

Spring 原生的支持定时任务功能,使用 @EnableScheduling 注解开启定时任务功能,使用 @Scheduled 注解指定定时任务。

1
2
3
4
5
6
7
@Component
class MyBean {
@Scheduled(cron = "1 * * * * ?")
public void myTask() {
// ...
}
}