使用Spring Rest Tempalte, https://spring.io/guides/gs/consuming-rest/
RestTemplate restTemplate = new RestTemplate();
为了使得获取和注入token机制与业务功能代码解耦,需要在resttemplate注入自定义interceptor https://www.tutorialspoint.com/spring_boot/spring_boot_interceptor.htm
interceptor file:
public class DemoInterceptor implements ClientHttpRequestInterceptor { @Override public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution){ //get token here. String tokenValue = String.format("%s %s", "Authorization", "XXXXXXXXXXX"); request.getHeaders().add("Authorization", tokenValue); } }
resttemplate add interceptor
DemoInterceptor ris = new DemoInterceptor(); restTemplate.setInterceptors(Arrays.asList({ris});
把cert文件生成jks证书, 生成方式参考:
openssl pkcs12 -export -in server.crt -inkey server.key -out server.pkcs12 keytool -importkeystore -srckeystore server.pkcs12 -destkeystore server-keystore.jks -srcstoretype pkcs12
新建ssl request builder
public class SslRequestFactoryBuilder { private static Logger logger = LoggerFactory.getLogger(SslRequestFactoryBuilder.class); public ClientHttpRequestFactory build(SslOption sslOption) { HttpClientBuilder httpClientBuilder = HttpClients.custom(); if (sslOption != null && sslOption.getEnable() != null && sslOption.getEnable()) { logger.info("ssl connection is being enabled"); SSLContext sslContext = getSslContext(sslOption); httpClientBuilder.setSSLContext(sslContext); } else { logger.info("ssl connection not active, use http instead"); } CloseableHttpClient client = httpClientBuilder.build(); ClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(client); ClientHttpRequestFactory bufferRequestFactory = new BufferingClientHttpRequestFactory(requestFactory); return bufferRequestFactory; } private SSLContext getSslContext(SslOption sslOption) { SSLContext sslContext; try { sslContext = SSLContextBuilder .create() .loadKeyMaterial(ResourceUtils.getFile(sslOption.getKeyStore()), sslOption.getKeyStorePassword().toCharArray(), sslOption.getKeyPass().toCharArray()) .loadTrustMaterial(ResourceUtils.getFile(sslOption.getTrustStore()), sslOption.getTrustStorePassword().toCharArray()) .build(); } catch (Exception e) { logger.error("ssl restTemplate initialize failed!"); throw new RuntimeException("ssl restTemplate initialize failed!", e); } return sslContext; } }
resttemplate add interceptor
ClientHttpRequestFactory requestFactory = builder.buildPool(sslOption)
restTemplate.setRequestFactory(requestFactory);
添加spring retry依赖 https://www.baeldung.com/spring-retry, enable retrying
@Retryable( value = {RetryException.class}, maxAttemptsExpression = "2", backoff = @Backoff(5000)) public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException { ClientHttpResponse response = execution.execute(request, body); // if error, throw exception throw new RetryException("retry"); return response; }
添加 Dozer 转换框架, http://dozer.sourceforge.net/
compile(‘net.sf.dozer:dozer:5.4.0‘)
定义class A 和 B, A为数据DTO, B为领域模型
class A{ @mapping("at1") private String attr1; @mapping("at2") private String attr2; private String attr3; ... } class B{ private String at1; private String at2; ... }
源数据转为目标数据
Mapper mapper = new DozerBeanMapper(); B b = mapper.map(a, B.class)
采用 Spring Cache + ehcache方案,https://www.baeldung.com/spring-boot-ehcache
添加项目依赖,spring boot enable cache
compile(‘javax.cache:cache-api‘) compile(‘org.ehcache:ehcache:3.6.1‘) compile(‘org.springframework.boot:spring-boot-starter-cache‘)
新增cache配置
@Configuration public class ProfileCacheConfig implements JCacheManagerCustomizer { private static Logger logger = LoggerFactory.getLogger(ProfileCacheConfig.class); @Autowired private ProfileProperties profileProperties; @Override public void customize(CacheManager cacheManager) { CacheProperty cacheProperty = profileProperties.getCache(); cacheManager.createCache("CACHE_NAME", new MutableConfiguration<>() .setExpiryPolicyFactory(ModifiedExpiryPolicy.factoryOf(new Duration(TimeUnit.MINUTES, cacheProperty.getProfileExpireMinutes()))) .setStoreByValue(false)); } }
在方法上面添加cacheable注解,启用缓存
@Cacheable(value = "CACHE_NAME", key = "#param") public void method(string param){ ****** }
采用MDC方案,将生成的x-trace-Id注入到request,response的header里面
拦截每个前端发送给每个后端的请求, 继承HandlerInterceptorAdapter,生成x-trace-Id, 注入到 MDC context里面
public class XTraceInterceptor extends HandlerInterceptorAdapter { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String xTraceId = generateTraceId(); MDC.put("x-trace-Id", xTraceId); response.setHeader("x-trace-Id", xTraceId); return true; } private String generateTraceId() { String randomId = UUID.randomUUID().toString(); String xTraceId = String.format("%s-%s", "demo", randomId); return xTraceId; } }
拓展WebMvcConfigurationSupport,将XTraceInterceptor注入
public class AppConfig extends WebMvcConfigurationSupport { @Override protected void addInterceptors(InterceptorRegistry registry) { XTraceInterceptor xtrace = new XTraceInterceptor(); registry.addInterceptor(loggerInterceptor); super.addInterceptors(registry); } }
restTemplate调用服务的时候,新建interceptor,在取出来注入到request header当中
public class LoggingRequestInterceptor implements ClientHttpRequestInterceptor { @Override public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException { String xTraceId = MDC.get(LoggerAttributeKeys.X_TRACE_ID); if (xTraceId != null) { request.getHeaders().add(LoggerAttributeKeys.X_TRACE_ID, xTraceId); } ClientHttpResponse response = execution.execute(request, body); return response; } }
SpringBoot RestTemplate 对应问题和解决方案
原文:https://www.cnblogs.com/lijma/p/10826981.html