控制层访问拦截实现
第一步:拦截器定义
package com.cy.pj.common.web;
/**
* Spring MVC中拦截器
* @author Administrator
*/
public class TimeAccessInterceptor
implements HandlerInterceptor {
/**
* preHandle在控制层目标方法执行之前执行
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
System.out.println("preHandler()");
//获取java中的日历对象
Calendar c=Calendar.getInstance();
c.set(Calendar.HOUR_OF_DAY, 6);
c.set(Calendar.MINUTE, 0);
c.set(Calendar.SECOND, 0);
long start=c.getTimeInMillis();
c.set(Calendar.HOUR_OF_DAY,24);
long end=c.getTimeInMillis();
long cTime=System.currentTimeMillis();
if(cTime<start||cTime>end)
throw new ServiceException("不在访问时间之内");
return true;
}
}
第二步:拦截器配置
package com.cy.pj.common.config;
@Configuration
public class SpringWebConfig implements WebMvcConfigurer{//web.xml
//配置spring mvc 拦截器
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new TimeAccessInterceptor())
.addPathPatterns("/user/doLogin");
}
}
异步写用户行为日志
Spring异步任务应用时,底层基于AOP方式为目标对象创建代理对象,在执行目标方法时,将目标方法运行在一个异步线程中。
项目中采用@Async默认异步配置获取异步线程。@Async默认异步配置可能会产生大量的线程,假如会有大量写库请求(例如将日志写入数据库),这时就会不断创建大量线程,极有可能压爆服务器内存。
方案一
第一步:启动异步,在项目启动类上添加@EnableAsync注解
package com.cy;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;
@EnableAsync //spring容器启动时会创建线程池
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
第二步:定义异步池
package com.cy.pj.common.config;
@Slf4j
@Setter
@Configuration
@ConfigurationProperties("async-thread-pool")
public class SpringAsyncConfig implements AsyncConfigurer{
/**核心线程数*/
private int corePoolSize=3;
/**最大线程数*/
private int maxPoolSize=5;
/**线程空闲时间*/
private int keepAliveTime=30;
/**队列容量*/
private int queueCapacity=100;
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(corePoolSize);
executor.setMaxPoolSize(maxPoolSize);
executor.setKeepAliveSeconds(keepAliveTime);
executor.setQueueCapacity(queueCapacity);
executor.setThreadNamePrefix("db-log-thread-");
executor.setRejectedExecutionHandler((Runnable r, ThreadPoolExecutor exe) -> {
log.warn("当前任务线程池队列已满.");
});
executor.initialize();
return executor;
}
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return new AsyncUncaughtExceptionHandler() {
@Override
public void handleUncaughtException(Throwable ex , Method method , Object... params) {
log.error("线程池执行任务发生未知异常.", ex);
}
};
}
}
其中,@ConfigurationProperties(“async-thread-pool”)配置是在spring boot的配置文件中
async-thread-pool:
corePoolSize: 5
maxPoolSize: 10
keepAliveTime: 30
queueCapacity: 50
第三步:在写日志的业务方法上使用异步
@Async
@Override
public void saveObject(SysLog entity) {
sysLogDao.insertObject(entity);
}
方案二
自定义池方式实现
package com.cy.pj.common.config;
@Slf4j
@Setter
@Configuration
@ConfigurationProperties("async-thread-pool")
public class SpringAsyncConfig {
/**核心线程数*/
private int corePoolSize=3;
/**最大线程数*/
private int maxPoolSize=5;
/**线程空闲时间*/
private int keepAliveTime=30;
/**队列容量*/
private int queueCapacity=100;
/**构建线程工厂*/
private ThreadFactory threadFactory=new ThreadFactory() {
//CAS算法
private AtomicInteger at=new AtomicInteger(1000);
@Override
public Thread newThread(Runnable r) {
return new Thread(r, "db-async-thread-"+at.getAndIncrement());
}
};
/**
*/
@Bean("asyncPoolExecutor")
public ThreadPoolExecutor newPoolExecutor() {
System.out.println("corePoolSize="+corePoolSize);
//创建阻塞式对象:基于数组存储结构,FIFO算法实现的一个阻塞式队列
BlockingQueue<Runnable> workQueue=
new ArrayBlockingQueue<>(queueCapacity);
//创建池对象
ThreadPoolExecutor threadPoolExecutor=
new ThreadPoolExecutor(
corePoolSize,
maxPoolSize,
keepAliveTime,
TimeUnit.SECONDS,
workQueue,
threadFactory);
return threadPoolExecutor;
}
}
池对象应用
@Async("asyncPoolExecutor")
@Transactional(propagation = Propagation.REQUIRES_NEW)
@Override
public void saveObject(SysLog entity) {
sysLogDao.insertObject(entity);
}