为了更加方便的使用aj-captcha验证码功能,本人将此项目集成到了大麦网项目中,作为基础组件来使用,并且将验证码缓存的方式修改成了改为redis来存储,因为在生产环境服务多实例情况下,使用本地缓存肯定是不行的
模块:damai-captcha-framework
组件保留了aj-captcha的所有验证功能,并且提供了获取验证码和校验验证码的api,可以根据业务需求来灵活使用
讲解
验证码缓存方式
首先我们看下aj-captcha中是怎么进行加载缓存数据的
Springboot3方式
org.springframework.boot.autoconfigure.AutoConfiguration.imports
com.damai.config.AjCaptchaAutoConfiguration
com.damai.config.CaptchaAutoConfig
Springboot2方式
spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.anji.captcha.config.AjCaptchaAutoConfiguration
使用了springboot的自动装配功能
AjCaptchaAutoConfiguration
@Configuration
@EnableConfigurationProperties(AjCaptchaProperties.class)
@ComponentScan("com.anji.captcha")
@Import({AjCaptchaServiceAutoConfiguration.class, AjCaptchaStorageAutoConfiguration.class})
public class AjCaptchaAutoConfiguration {
}
AjCaptchaStorageAutoConfiguration就是缓存数据的配置
@Configuration
public class AjCaptchaStorageAutoConfiguration {
@Bean(name = "AjCaptchaCacheService")
public CaptchaCacheService captchaCacheService(AjCaptchaProperties ajCaptchaProperties){
//缓存类型redis/local/....
return CaptchaServiceFactory.getCache(ajCaptchaProperties.getCacheType().name());
}
}
能够看到是通过ajCaptchaProperties.getCacheType().name()属性从CaptchaServiceFactory工厂中获取
属性通过aj.captcha.cache-type来配置
下面来分析下CaptchaServiceFactory工厂的加载流程
public static CaptchaCacheService getCache(String cacheType) {
return cacheService.get(cacheType);
}
public volatile static Map
public volatile static Map
static {
ServiceLoader
for (CaptchaCacheService item : cacheServices) {
cacheService.put(item.type(), item);
}
logger.info("supported-captchaCache-service:{}", cacheService.keySet().toString());
ServiceLoader
for (CaptchaService item : services) {
instances.put(item.captchaType(), item);
}
;
logger.info("supported-captchaTypes-service:{}", instances.keySet().toString());
}
cacheService中存在的就是缓存处理类,key为类型, value为CaptchaCacheService的实现类
spring启动后,会执行被@Bean修饰的captchaCacheService方法
当CaptchaServiceFactory的getCache方法时,会加载CaptchaServiceFactory类,从而加载static静态块
通过java spi机制扫描出CaptchaCacheService的实现类,然后添加到cacheService中
这时调用CaptchaServiceFactory的getCache方法时,就会根据缓存类型从cacheService中取出
在aj-captcha中,默认的缓存策略使用的是本地缓存
private StorageType cacheType = local;
CaptchaCacheServiceMemImpl就是本地缓存策略的实现
/**
* 对于分布式部署的应用,我们建议应用自己实现CaptchaCacheService,比如用Redis,参考service/spring-boot代码示例。
* 如果应用是单点的,也没有使用redis,那默认使用内存。
* 内存缓存只适合单节点部署的应用,否则验证码生产与验证在节点之间信息不同步,导致失败。
* @Title: 默认使用内存当缓存
* @author lide1202@hotmail.com
* @date 2020-05-12
*/
public class CaptchaCacheServiceMemImpl implements CaptchaCacheService {
@Override
public void set(String key, String value, long expiresInSeconds) {
CacheUtil.set(key, value, expiresInSeconds);
}
@Override
public boolean exists(String key) {
return CacheUtil.exists(key);
}
@Override
public void delete(String key) {
CacheUtil.delete(key);
}
@Override
public String get(String key) {
return CacheUtil.get(key);
}
@Override
public Long increment(String key, long val) {
Long ret = Long.valueOf(CacheUtil.get(key))+val;
CacheUtil.set(key,ret+"",0);
return ret;
}
@Override
public String type() {
return "local";
}
}
在生产中高并发的项目肯定都是多实例部署的,所以本地缓存这种方式肯定不行,我们改用redis的方式
使用redis我们要借助springboot提供的redis操作StringRedisTemplate
但要注意,这里缓存策略的实现都是用的java spi加载得到的,而且并没有被spring管理,所以直接通过构造器注入StringRedisTemplate是不行的,需要主动调用方法来进行注入,下面介绍如何改用redis的保存方式