wang.ramboll.extend.request.limit.autoconfigure.RequestLimitAutoConfiguration Maven / Gradle / Ivy
The newest version!
package wang.ramboll.extend.request.limit.autoconfigure;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import wang.ramboll.extend.basic.content.SpringBeanNames;
import wang.ramboll.extend.basic.exception.ExtendRuntimeException;
import wang.ramboll.extend.data.cache.CacheWrapper;
import wang.ramboll.extend.data.cache.autoconfigure.CacheAutoConfiguration;
import wang.ramboll.extend.request.limit.RequestFrequencyLimitAnnotationScanner;
import wang.ramboll.extend.request.limit.filter.ServletRequestFilter;
import wang.ramboll.extend.request.limit.interceptor.RequestFrequencyLimitInterceptor;
import wang.ramboll.extend.request.limit.interceptor.RequestFrequencyLimitWork;
import wang.ramboll.extend.request.limit.wrapper.LimitReturnObjWrapper;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
* 请求防刷/限量拦截自动配置类
* @author WangRuibo
*/
@Configuration(
proxyBeanMethods = false
)
@EnableConfigurationProperties(RequestLimitProperties.class)
@ConditionalOnMissingBean(RequestLimitAutoConfiguration.class)
@DependsOn(SpringBeanNames.DATA_CACHE_WRAPPER_BEAN_NAME)
@AutoConfigureAfter(CacheAutoConfiguration.class)
public class RequestLimitAutoConfiguration implements WebMvcConfigurer {
private static final Logger logger = LoggerFactory.getLogger(RequestLimitAutoConfiguration.class);
private static final String REQUEST_FREQUENCY_LIMIT_KEY_TEMPLATE = "RAMBOLL_REQUEST_FREQUENCY_LIMIT:%s";
private RequestLimitProperties requestLimitProperties ;
private CacheWrapper cacheWrapper;
private LimitReturnObjWrapper defaultReturnObj = new LimitReturnObjWrapper();
/**
* 请求防刷/限量拦截自动配置类 构造器
*/
@Autowired
public RequestLimitAutoConfiguration(RequestLimitProperties requestLimitProperties,@Qualifier(SpringBeanNames.DATA_CACHE_WRAPPER_BEAN_NAME) CacheWrapper cacheWrapper) {
logger.info("Init RequestLimitAutoConfiguration...");
this.requestLimitProperties = requestLimitProperties;
this.cacheWrapper = cacheWrapper;
}
@ConditionalOnProperty(name = "wang.ramboll.request.limit.use-fail-return-bean",havingValue = "true")
@DependsOn(SpringBeanNames.REQUEST_LIMIT_DEFAULT_FAIL_RETURN_BEAN_NAME)
@Bean(name = SpringBeanNames.REQUEST_LIMIT_DEFAULT_FAIL_RETURN_BEAN_NAME + ".TEMP")
public Object setDefaultReturnObj(@Qualifier(SpringBeanNames.REQUEST_LIMIT_DEFAULT_FAIL_RETURN_BEAN_NAME) Object defaultReturnObj) {
logger.info("Auto set DefaultLimitReturnBean ... ");
this.defaultReturnObj.setObj(defaultReturnObj);
return this.defaultReturnObj;
}
@Bean(name = SpringBeanNames.HTTP_SERVLET_REQUEST_FILTER)
@ConditionalOnMissingBean(name = SpringBeanNames.HTTP_SERVLET_REQUEST_FILTER)
public ServletRequestFilter servletRequestFilter(){
logger.info("Init ServletRequestFilter...");
return new ServletRequestFilter();
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
try {
if(requestLimitProperties.isEnable()){
List scanRequestLimitAnnotationMappingUrlList = RequestFrequencyLimitAnnotationScanner.scanRequestFrequencyLimitAnnotationMappingUrl(requestLimitProperties.getControllerPackageArray());
if(scanRequestLimitAnnotationMappingUrlList.size()>0){
scanRequestLimitAnnotationMappingUrlList.forEach(s->logger.info("Find request mapping url with @RequestFrequencyLimit -> {}",s));
if(requestLimitProperties.isUseFailReturnBean()){
logger.info("Use user set default-limit-return-bean -> {}",SpringBeanNames.REQUEST_LIMIT_DEFAULT_FAIL_RETURN_BEAN_NAME);
} else if(null!=requestLimitProperties.getDefaultLimitReturnClass()){
logger.info("Use user set default-limit-return-class -> {}",requestLimitProperties.getDefaultLimitReturnClass());
defaultReturnObj.setObj(requestLimitProperties.getDefaultLimitReturnClass().newInstance());
} else {
logger.info("Use default default-limit-return-class -> {}",DefaultLimitReturn.class.getName());
logger.info("Use default default-limit-return-code -> {}",requestLimitProperties.getDefaultLimitReturnCode());
logger.info("Use default default-limit-return-message -> {}",requestLimitProperties.getDefaultLimitReturnMessage());
defaultReturnObj.setObj(new DefaultLimitReturn(requestLimitProperties.getDefaultLimitReturnCode(),requestLimitProperties.getDefaultLimitReturnMessage()));
}
logger.info("Add RequestFrequencyLimitInterceptor ...");
registry.addInterceptor(new RequestFrequencyLimitInterceptor(new RequestFrequencyLimitWork() {
@Override
public boolean work(String unionContent, long delay, long maxTimes) {
String cacheKey = String.format(REQUEST_FREQUENCY_LIMIT_KEY_TEMPLATE,unionContent);
if(cacheWrapper.getCacheOperations().get(cacheKey)==null){//没有拦截,创建记录,放行
cacheWrapper.getCacheOperations().increment(cacheKey,delay,TimeUnit.MILLISECONDS);
return true ;
} else {//有记录增加次数
Long l = cacheWrapper.getCacheOperations().increment(cacheKey,delay,TimeUnit.MILLISECONDS);
if(l>maxTimes) return false ;//超出限制,拦截
else return true ;//未超出,放行
}
}
@Override
public void cancelLimit(String unionContent, long maxTimes) {
if(maxTimes>1){
//解除拦截
cacheWrapper.getCacheOperations().remove(String.format(REQUEST_FREQUENCY_LIMIT_KEY_TEMPLATE,unionContent));
}
}
}, defaultReturnObj)).addPathPatterns(scanRequestLimitAnnotationMappingUrlList);
}
}
} catch (Exception e) {
logger.error(e.getMessage(),e);
throw new ExtendRuntimeException(e.getMessage(),e);
}
}
}