mirror of
https://github.com/PowerJob/PowerJob.git
synced 2025-07-17 00:00:04 +08:00
feat: powerjob-remote http support spring-webmvc
This commit is contained in:
parent
e01770adc7
commit
3e2db37446
@ -14,6 +14,7 @@
|
||||
<module>powerjob-remote-benchmark</module>
|
||||
<module>powerjob-remote-impl-http</module>
|
||||
<module>powerjob-remote-impl-akka</module>
|
||||
<module>powerjob-remote-impl-http-spring</module>
|
||||
</modules>
|
||||
|
||||
<artifactId>powerjob-remote</artifactId>
|
||||
|
41
powerjob-remote/powerjob-remote-impl-http-spring/pom.xml
Normal file
41
powerjob-remote/powerjob-remote-impl-http-spring/pom.xml
Normal file
@ -0,0 +1,41 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>powerjob-remote</artifactId>
|
||||
<groupId>tech.powerjob</groupId>
|
||||
<version>4.0.0</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>powerjob-remote-impl-http-spring</artifactId>
|
||||
<version>4.3.0</version>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
|
||||
<spring.version>5.3.23</spring.version>
|
||||
<powerjob-remote-framework.version>4.3.0</powerjob-remote-framework.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>tech.powerjob</groupId>
|
||||
<artifactId>powerjob-remote-framework</artifactId>
|
||||
<version>${powerjob-remote-framework.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-webmvc</artifactId>
|
||||
<version>${spring.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
@ -0,0 +1,17 @@
|
||||
package tech.powerjob.remote.http;
|
||||
|
||||
import tech.powerjob.remote.framework.transporter.Protocol;
|
||||
|
||||
/**
|
||||
* HttpProtocol
|
||||
*
|
||||
* @author tjq
|
||||
* @since 2022/12/31
|
||||
*/
|
||||
public class HttpProtocol implements Protocol {
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return tech.powerjob.common.enums.Protocol.HTTP.name();
|
||||
}
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
package tech.powerjob.remote.http;
|
||||
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
|
||||
import org.springframework.web.util.pattern.PathPatternParser;
|
||||
import tech.powerjob.remote.framework.actor.ActorInfo;
|
||||
import tech.powerjob.remote.framework.actor.HandlerInfo;
|
||||
import tech.powerjob.remote.framework.cs.CSInitializer;
|
||||
import tech.powerjob.remote.framework.cs.CSInitializerConfig;
|
||||
import tech.powerjob.remote.framework.transporter.Transporter;
|
||||
import tech.powerjob.remote.http.spring.SpringMvcTransporter;
|
||||
import tech.powerjob.remote.http.spring.SpringUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author songyinyin
|
||||
* @since 2023/2/11 19:55
|
||||
*/
|
||||
public class HttpSpringCSInitializer implements CSInitializer {
|
||||
|
||||
private RequestMappingHandlerMapping requestMappingHandlerMapping;
|
||||
|
||||
@Override
|
||||
public String type() {
|
||||
return tech.powerjob.common.enums.Protocol.HTTP.name();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(CSInitializerConfig config) {
|
||||
this.requestMappingHandlerMapping = (RequestMappingHandlerMapping) SpringUtils.getBean("requestMappingHandlerMapping");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Transporter buildTransporter() {
|
||||
return new SpringMvcTransporter();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindHandlers(List<ActorInfo> actorInfos) {
|
||||
for (ActorInfo actorInfo : actorInfos) {
|
||||
for (HandlerInfo handlerInfo : actorInfo.getHandlerInfos()) {
|
||||
|
||||
RequestMappingInfo.BuilderConfiguration options = new RequestMappingInfo.BuilderConfiguration();
|
||||
options.setPatternParser(new PathPatternParser());
|
||||
RequestMappingInfo mapping = RequestMappingInfo.paths(handlerInfo.getLocation().toPath())
|
||||
.methods(RequestMethod.POST)
|
||||
// 处理请求的提交内容类型
|
||||
// .consumes(MediaType.APPLICATION_JSON_VALUE)
|
||||
// 返回的内容类型
|
||||
.produces(MediaType.APPLICATION_JSON_VALUE)
|
||||
.options(options)
|
||||
.build();
|
||||
Method method = handlerInfo.getMethod();
|
||||
requestMappingHandlerMapping.registerMapping(mapping, actorInfo.getActor(), method);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
package tech.powerjob.remote.http.spring;
|
||||
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.web.bind.support.WebDataBinderFactory;
|
||||
import org.springframework.web.context.request.NativeWebRequest;
|
||||
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
|
||||
import org.springframework.web.method.support.ModelAndViewContainer;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor;
|
||||
import tech.powerjob.common.exception.PowerJobException;
|
||||
import tech.powerjob.remote.framework.actor.Handler;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 带有 @Handler 注解的,接收的请求参数 使用 json 解析,等同于Spring中,在请求参数前使用注解:@RequestBody
|
||||
*
|
||||
* @author songyinyin
|
||||
* @see RequestResponseBodyMethodProcessor
|
||||
* @since 2023/2/12 18:02
|
||||
*/
|
||||
public class PowerjobCSMethodProcessor implements HandlerMethodArgumentResolver {
|
||||
|
||||
private HandlerMethodArgumentResolver requestResponseBodyMethodProcessor;
|
||||
|
||||
@Override
|
||||
public boolean supportsParameter(MethodParameter parameter) {
|
||||
return parameter.hasMethodAnnotation(Handler.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
|
||||
if (requestResponseBodyMethodProcessor == null) {
|
||||
RequestMappingHandlerAdapter requestMappingHandlerAdapter = SpringUtils.getBean(RequestMappingHandlerAdapter.class);
|
||||
this.requestResponseBodyMethodProcessor = getRequestResponseBodyMethodProcessor(requestMappingHandlerAdapter.getArgumentResolvers());
|
||||
}
|
||||
if (requestResponseBodyMethodProcessor == null) {
|
||||
throw new PowerJobException("requestResponseBodyMethodProcessor is null");
|
||||
}
|
||||
return requestResponseBodyMethodProcessor.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
|
||||
}
|
||||
|
||||
private HandlerMethodArgumentResolver getRequestResponseBodyMethodProcessor(List<HandlerMethodArgumentResolver> resolvers) {
|
||||
if (resolvers == null) {
|
||||
return null;
|
||||
}
|
||||
for (HandlerMethodArgumentResolver resolver : resolvers) {
|
||||
if (resolver instanceof RequestResponseBodyMethodProcessor) {
|
||||
return resolver;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
package tech.powerjob.remote.http.spring;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
import tech.powerjob.common.PowerSerializable;
|
||||
import tech.powerjob.remote.framework.base.RemotingException;
|
||||
import tech.powerjob.remote.framework.base.URL;
|
||||
import tech.powerjob.remote.framework.transporter.Protocol;
|
||||
import tech.powerjob.remote.framework.transporter.Transporter;
|
||||
import tech.powerjob.remote.http.HttpProtocol;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionStage;
|
||||
|
||||
/**
|
||||
* spring-webmvc 使用 RestTemplate 发送http请求,后续兼容 spring-webflux 后,部分请求可以是非阻塞式的
|
||||
*
|
||||
* @author songyinyin
|
||||
* @since 2023/2/12 11:43
|
||||
*/
|
||||
public class SpringMvcTransporter implements Transporter {
|
||||
|
||||
private static final Protocol PROTOCOL = new HttpProtocol();
|
||||
|
||||
private final RestTemplate restTemplate = new RestTemplate();
|
||||
|
||||
@Override
|
||||
public Protocol getProtocol() {
|
||||
return PROTOCOL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tell(URL url, PowerSerializable request) {
|
||||
String fullUrl = getFullUrl(url);
|
||||
restTemplate.postForEntity(fullUrl, request, String.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> CompletionStage<T> ask(URL url, PowerSerializable request, Class<T> clz) throws RemotingException {
|
||||
String fullUrl = getFullUrl(url);
|
||||
ResponseEntity<T> responseEntity = restTemplate.postForEntity(fullUrl, request, clz);
|
||||
// throw exception
|
||||
final int statusCode = responseEntity.getStatusCodeValue();
|
||||
if (statusCode != HttpStatus.OK.value()) {
|
||||
// CompletableFuture.get() 时会传递抛出该异常
|
||||
throw new RemotingException(String.format("request [url:%s] failed, status: %d, msg: %s",
|
||||
fullUrl, statusCode, responseEntity.getBody()
|
||||
));
|
||||
}
|
||||
return CompletableFuture.completedFuture(responseEntity.getBody());
|
||||
}
|
||||
|
||||
private String getFullUrl(URL url) {
|
||||
return "http://" + url.getAddress().toFullAddress() + url.getLocation().toPath();
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
package tech.powerjob.remote.http.spring;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
|
||||
/**
|
||||
* Spring ApplicationContext 工具类
|
||||
*
|
||||
* @author tjq
|
||||
* @since 2020/4/7
|
||||
*/
|
||||
public class SpringUtils implements ApplicationContextAware {
|
||||
|
||||
private static ApplicationContext context;
|
||||
|
||||
public static <T> T getBean(Class<T> clz) {
|
||||
return context.getBean(clz);
|
||||
}
|
||||
|
||||
public static Object getBean(String beanName) {
|
||||
return context.getBean(beanName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext ctx) throws BeansException {
|
||||
context = ctx;
|
||||
}
|
||||
}
|
||||
|
@ -57,7 +57,11 @@ public class VertxTransporter implements Transporter {
|
||||
// 获取远程服务器的HTTP连接
|
||||
Future<HttpClientRequest> httpClientRequestFuture = httpClient.request(requestOptions);
|
||||
// 转换 -> 发送请求获取响应
|
||||
Future<HttpClientResponse> responseFuture = httpClientRequestFuture.compose(httpClientRequest -> httpClientRequest.send(JsonObject.mapFrom(request).toBuffer()));
|
||||
Future<HttpClientResponse> responseFuture = httpClientRequestFuture.compose(httpClientRequest ->
|
||||
httpClientRequest
|
||||
.putHeader("content-type", "application/json")
|
||||
.send(JsonObject.mapFrom(request).toBuffer())
|
||||
);
|
||||
return responseFuture.compose(httpClientResponse -> {
|
||||
// throw exception
|
||||
final int statusCode = httpClientResponse.statusCode();
|
||||
|
@ -24,6 +24,21 @@
|
||||
<groupId>tech.powerjob</groupId>
|
||||
<artifactId>powerjob-worker</artifactId>
|
||||
<version>${powerjob.worker.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>tech.powerjob</groupId>
|
||||
<artifactId>powerjob-remote-impl-http</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>tech.powerjob</groupId>
|
||||
<artifactId>powerjob-remote-impl-akka</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>tech.powerjob</groupId>
|
||||
<artifactId>powerjob-remote-impl-http-spring</artifactId>
|
||||
<version>${powerjob.worker.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
|
@ -0,0 +1,40 @@
|
||||
package tech.powerjob.worker.autoconfigure;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
import tech.powerjob.remote.http.HttpSpringCSInitializer;
|
||||
import tech.powerjob.remote.http.spring.PowerjobCSMethodProcessor;
|
||||
import tech.powerjob.remote.http.spring.SpringUtils;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author songyinyin
|
||||
* @since 2023/2/12 22:23
|
||||
*/
|
||||
@Configuration
|
||||
@AutoConfigureBefore(PowerJobAutoConfiguration.class)
|
||||
@ConditionalOnClass(HttpSpringCSInitializer.class)
|
||||
public class PowerJobRemoteAutoConfiguration implements WebMvcConfigurer {
|
||||
|
||||
@Bean
|
||||
public SpringUtils powerJobSpringUtils() {
|
||||
return new SpringUtils();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public PowerjobCSMethodProcessor powerjobCSMethodProcessor() {
|
||||
return new PowerjobCSMethodProcessor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
|
||||
resolvers.add(powerjobCSMethodProcessor());
|
||||
}
|
||||
}
|
@ -1,2 +1,3 @@
|
||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||
tech.powerjob.worker.autoconfigure.PowerJobAutoConfiguration
|
||||
tech.powerjob.worker.autoconfigure.PowerJobAutoConfiguration,\
|
||||
tech.powerjob.worker.autoconfigure.PowerJobRemoteAutoConfiguration
|
||||
|
Loading…
x
Reference in New Issue
Block a user