实现一
创建feign请求拦截器
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import feign.RequestInterceptor;
import feign.RequestTemplate;
import org.slf4j.MDC;
import org.springframework.context.annotation.Configuration;
/**
* feign请求拦截器,
* 设置feign接口的请求头,方便传递日志流水号。
*
* @author liaorj
* @date 2024/3/19
*/
@Configuration
public class FeignRequestInterceptor implements RequestInterceptor {
@Override
public void apply(RequestTemplate requestTemplate) {
String logId = MDC.get("LOG_ID");
if(StrUtil.isNotBlank(logId)){
requestTemplate.header("LOG_ID", logId);
} else {
requestTemplate.header("LOG_ID", System.currentTimeMillis() + RandomUtil.randomString(3));
}
}
}
调用方FeignClient配置
注意configuration配置。
import com.example.trainticket.common.interceptor.FeignRequestInterceptor;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import java.util.Date;
/**
* member模块feign接口
*
* @author liaorj
* @date 2024/3/19
*/
@FeignClient(name = "member-service", path = "/member", configuration = {FeignRequestInterceptor.class})
public interface MemberFeignClient {
@PostMapping("/feign/ticket/remove")
boolean removeTickets(@RequestParam("date") @DateTimeFormat(pattern = "yyyy-MM-dd") Date date);
}
被调用方Feign接口
@PostMapping("/ticket/remove")
public boolean removeTickets(@RequestParam("date") @DateTimeFormat(pattern = "yyyy-MM-dd") Date date) {
//MDC.put("LOG_ID", logId);不用手动put,在拦截器那边判断并put
//你的业务代码...
}
公共的日志拦截器配置
import cn.hutool.core.util.RandomUtil;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.slf4j.MDC;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
/**
* 日志拦截器
*
* @author liaorj
* @date 2023/12/13
*/
@Component
public class LogInterceptor implements HandlerInterceptor {
/**
* 目的:增加日志流水号
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String requestUrl = request.getRequestURL().toString();
if (requestUrl.contains("/feign/")) {
//feign请求,特殊处理日志号,保证调用者和被调用者的日志号一致,方便后续排查。
String logId = request.getHeader("LOG_ID");
MDC.put("LOG_ID", logId);
} else {
MDC.put("LOG_ID", System.currentTimeMillis() + RandomUtil.randomString(3));
}
return true;
}
}
import com.example.trainticket.common.interceptor.LogInterceptor;
import com.example.trainticket.common.interceptor.MemberInterceptor;
import jakarta.annotation.Resource;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Resource
private LogInterceptor logInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(logInterceptor);
}
}
定时任务同步日志号
由于拦截器无法拦截系统任务设置日志流水号,所以只能手动put。
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.RandomUtil;
import com.example.trainticket.batch.feign.MemberFeignClient;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.quartz.DisallowConcurrentExecution;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.slf4j.MDC;
/**
*
* @author liaorj
* @date 2024/3/19
*/
@Slf4j
//禁止任务并发执行
@DisallowConcurrentExecution
public class RemoveTicketsJob implements Job {
@Resource
private MemberFeignClient memberFeignClient;
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
//由于拦截器无法拦截系统任务设置日志流水号,所以只能手动put
MDC.put("LOG_ID", System.currentTimeMillis() + RandomUtil.randomString(3));
DateTime now = DateTime.now();
DateTime past = DateUtil.offsetDay(now, -30);
boolean result = memberFeignClient.removeTickets(past);
}
}