Skip to content
Snippets Groups Projects
Unverified Commit 4e3d7050 authored by leo's avatar leo Committed by GitHub
Browse files

optimize: Saga SpringBeanServiceInvoker support switch json parser (#3513)

parent 40406447
No related branches found
No related tags found
No related merge requests found
Showing
with 278 additions and 16 deletions
......@@ -208,6 +208,7 @@ public class DefaultStateMachineConfig implements StateMachineConfig, Applicatio
SpringBeanServiceInvoker springBeanServiceInvoker = new SpringBeanServiceInvoker();
springBeanServiceInvoker.setApplicationContext(getApplicationContext());
springBeanServiceInvoker.setThreadPoolExecutor(threadPoolExecutor);
springBeanServiceInvoker.setSagaJsonParser(getSagaJsonParser());
this.serviceInvokerManager.putServiceInvoker(DomainConstants.SERVICE_TYPE_SPRING_BEAN,
springBeanServiceInvoker);
}
......
......@@ -27,9 +27,6 @@ import java.util.Map;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.atomic.AtomicInteger;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.Feature;
import io.seata.common.exception.FrameworkErrorCode;
import io.seata.common.util.CollectionUtils;
import io.seata.saga.engine.exception.EngineExecutionException;
......@@ -39,6 +36,8 @@ import io.seata.saga.engine.utils.ExceptionUtils;
import io.seata.saga.statelang.domain.ServiceTaskState;
import io.seata.saga.statelang.domain.TaskState.Retry;
import io.seata.saga.statelang.domain.impl.ServiceTaskStateImpl;
import io.seata.saga.statelang.parser.JsonParser;
import io.seata.saga.statelang.parser.JsonParserFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
......@@ -56,6 +55,7 @@ public class SpringBeanServiceInvoker implements ServiceInvoker, ApplicationCont
private ApplicationContext applicationContext;
private ThreadPoolExecutor threadPoolExecutor;
private String sagaJsonParser;
@Override
public Object invoke(ServiceTaskState serviceTaskState, Object... input) throws Throwable {
......@@ -296,8 +296,12 @@ public class SpringBeanServiceInvoker implements ServiceInvoker, ApplicationCont
} else if (isPrimitive(paramType)) {
return value;
} else {
String jsonValue = JSON.toJSONString(value);
return JSON.parseObject(jsonValue, paramType, Feature.SupportAutoType);
JsonParser jsonParser = JsonParserFactory.getJsonParser(getSagaJsonParser());
if (jsonParser == null) {
throw new RuntimeException("Cannot get JsonParser by name : " + getSagaJsonParser());
}
String jsonValue = jsonParser.toJsonString(value, true, false);
return jsonParser.parse(jsonValue, paramType, false);
}
}
......@@ -344,4 +348,12 @@ public class SpringBeanServiceInvoker implements ServiceInvoker, ApplicationCont
return null;
}
}
public String getSagaJsonParser() {
return sagaJsonParser;
}
public void setSagaJsonParser(String sagaJsonParser) {
this.sagaJsonParser = sagaJsonParser;
}
}
\ No newline at end of file
......@@ -39,6 +39,15 @@ public interface JsonParser {
*/
String toJsonString(Object o, boolean prettyPrint);
/**
* Object to Json string
* @param o
* @param ignoreAutoType
* @param prettyPrint
* @return
*/
String toJsonString(Object o, boolean ignoreAutoType, boolean prettyPrint);
/**
* parse json string to Object
*
......
......@@ -40,6 +40,11 @@ public class FastjsonParser implements JsonParser {
SerializerFeature.WriteClassName,
SerializerFeature.PrettyFormat };
private static final SerializerFeature[] FEATURES_PRETTY = new SerializerFeature[] {
SerializerFeature.DisableCircularReferenceDetect,
SerializerFeature.WriteDateUseDateFormat,
SerializerFeature.PrettyFormat };
public static final String NAME = "fastjson";
@Override
......@@ -49,11 +54,26 @@ public class FastjsonParser implements JsonParser {
@Override
public String toJsonString(Object o, boolean prettyPrint) {
return toJsonString(o, false, prettyPrint);
}
@Override
public String toJsonString(Object o, boolean ignoreAutoType, boolean prettyPrint) {
if (prettyPrint) {
return JSON.toJSONString(o, SERIALIZER_FEATURES_PRETTY);
if (ignoreAutoType) {
return JSON.toJSONString(o, FEATURES_PRETTY);
}
else {
return JSON.toJSONString(o, SERIALIZER_FEATURES_PRETTY);
}
}
else {
return JSON.toJSONString(o, SERIALIZER_FEATURES);
if (ignoreAutoType) {
return JSON.toJSONString(o);
}
else {
return JSON.toJSONString(o, SERIALIZER_FEATURES);
}
}
}
......
......@@ -61,15 +61,31 @@ public class JacksonJsonParser implements JsonParser {
@Override
public String toJsonString(Object o, boolean prettyPrint) {
return toJsonString(o, false, prettyPrint);
}
@Override
public String toJsonString(Object o, boolean ignoreAutoType, boolean prettyPrint) {
try {
if (o instanceof List && ((List) o).isEmpty()) {
return "[]";
}
if (prettyPrint) {
return objectMapperWithAutoType.writerWithDefaultPrettyPrinter().writeValueAsString(o);
if (ignoreAutoType) {
return objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(o);
}
else {
return objectMapperWithAutoType.writerWithDefaultPrettyPrinter().writeValueAsString(o);
}
}
else {
return objectMapperWithAutoType.writeValueAsString(o);
if (ignoreAutoType) {
return objectMapper.writeValueAsString(o);
}
else {
return objectMapperWithAutoType.writeValueAsString(o);
}
}
} catch (JsonProcessingException e) {
throw new RuntimeException("Parse object to json error", e);
......
......@@ -219,7 +219,7 @@ public class StateMachineAsyncTests {
}
@Test
public void testStateMachineWithComplextParams() {
public void testStateMachineWithComplexParams() {
long start = System.currentTimeMillis();
......
......@@ -20,12 +20,14 @@ import io.seata.saga.engine.mock.DemoService.People;
import io.seata.saga.statelang.domain.DomainConstants;
import io.seata.saga.statelang.domain.ExecutionStatus;
import io.seata.saga.statelang.domain.StateMachineInstance;
import io.seata.saga.statelang.parser.JsonParserFactory;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
......@@ -279,7 +281,36 @@ public class StateMachineTests {
}
@Test
public void testStateMachineWithComplextParams() {
public void testStateComplexParams() {
People people1 = new People();
people1.setName("lilei");
people1.setAge(18);
People people2 = new People();
people2.setName("lilei2");
people2.setAge(19);
People people3 = new People();
people3.setName("lilei3");
people3.setAge(20);
People people4 = new People();
people4.setName("lilei4");
people4.setAge(21);
people1.setChildrenArray(new People[] {people2});
people1.setChildrenList(Arrays.asList(people3));
Map<String, People> map1 = new HashMap<>(1);
map1.put("lilei4", people4);
people1.setChildrenMap(map1);
String json = JsonParserFactory.getJsonParser("jackson").toJsonString(people1, false, true);
System.out.println(json);
}
@Test
public void testStateMachineWithComplexParams() {
long start = System.currentTimeMillis();
......
......@@ -24,6 +24,8 @@ import io.seata.saga.engine.AsyncCallback;
import io.seata.saga.engine.StateMachineEngine;
import io.seata.saga.engine.exception.EngineExecutionException;
import io.seata.saga.engine.impl.DefaultStateMachineConfig;
import io.seata.saga.engine.mock.DemoService.Engineer;
import io.seata.saga.engine.mock.DemoService.People;
import io.seata.saga.proctrl.ProcessContext;
import io.seata.saga.statelang.domain.DomainConstants;
import io.seata.saga.statelang.domain.ExecutionStatus;
......@@ -248,6 +250,36 @@ public class StateMachineDBTests extends AbstractServerTest {
Assertions.assertTrue(GlobalStatus.CommitRetrying.equals(globalTransaction.getStatus()));
}
@Test
public void testStateMachineWithComplexParams() {
long start = System.currentTimeMillis();
Map<String, Object> paramMap = new HashMap<>(1);
People people = new People();
people.setName("lilei");
people.setAge(18);
Engineer engineer = new Engineer();
engineer.setName("programmer");
paramMap.put("people", people);
paramMap.put("career", engineer);
String stateMachineName = "simpleStateMachineWithComplexParamsJackson";
StateMachineInstance instance = stateMachineEngine.start(stateMachineName, null, paramMap);
People peopleResult = (People) instance.getEndParams().get("complexParameterMethodResult");
Assertions.assertNotNull(peopleResult);
Assertions.assertTrue(people.getName().equals(people.getName()));
long cost = System.currentTimeMillis() - start;
System.out.println("====== XID: " + instance.getId() + " cost :" + cost);
Assertions.assertTrue(ExecutionStatus.SU.equals(instance.getStatus()));
}
@Test
public void testCompensationStateMachine() throws Exception {
......
......@@ -177,7 +177,7 @@ public class StateMachineAsyncDBMockServerTests {
}
@Test
public void testStateMachineWithComplextParams() {
public void testStateMachineWithComplexParams() {
long start = System.currentTimeMillis();
......@@ -187,7 +187,7 @@ public class StateMachineAsyncDBMockServerTests {
people.setAge(18);
paramMap.put("people", people);
String stateMachineName = "simpleStateMachineWithComplexParams";
String stateMachineName = "simpleStateMachineWithComplexParamsJackson";
StateMachineInstance inst = stateMachineEngine.startAsync(stateMachineName, null, paramMap, callback);
......
......@@ -613,7 +613,7 @@ public class StateMachineDBMockServerTests {
}
@Test
public void testStateMachineWithComplextParams() {
public void testStateMachineWithComplexParams() {
long start = System.currentTimeMillis();
......@@ -628,7 +628,7 @@ public class StateMachineDBMockServerTests {
paramMap.put("people", people);
paramMap.put("career", engineer);
String stateMachineName = "simpleStateMachineWithComplexParams";
String stateMachineName = "simpleStateMachineWithComplexParamsJackson";
StateMachineInstance instance = stateMachineEngine.start(stateMachineName, null, paramMap);
......
{
"Name": "simpleStateMachineWithComplexParams",
"Comment": "带复杂参数的测试状态机定义",
"Comment": "带复杂参数的测试状态机定义fastjson格式",
"StartState": "FirstState",
"Version": "0.0.1",
"States": {
......
{
"Name": "simpleStateMachineWithComplexParamsJackson",
"Comment": "带复杂参数的测试状态机定义jackson格式",
"StartState": "FirstState",
"Version": "0.0.1",
"States": {
"FirstState": {
"Type": "ServiceTask",
"ServiceName": "demoService",
"ServiceMethod": "complexParameterMethod",
"Next": "ChoiceState",
"ParameterTypes" : ["java.lang.String", "int", "io.seata.saga.engine.mock.DemoService$People", "[Lio.seata.saga.engine.mock.DemoService$People;", "java.util.List", "java.util.Map"],
"Input": [
"$.[people].name",
"$.[people].age",
{
"@type": "io.seata.saga.engine.mock.DemoService$People",
"name": "lilei",
"age": 18,
"childrenArray": [
"[Lio.seata.saga.engine.mock.DemoService$People;",
[
{
"@type": "io.seata.saga.engine.mock.DemoService$People",
"name": "lilei",
"age": 18
},
{
"@type": "io.seata.saga.engine.mock.DemoService$People",
"name": "lilei",
"age": 18
}
]
],
"childrenList": [
"java.util.ArrayList",
[
{
"@type": "io.seata.saga.engine.mock.DemoService$People",
"name": "lilei",
"age": 18
},
{
"@type": "io.seata.saga.engine.mock.DemoService$People",
"name": "lilei",
"age": 18
}
]
],
"childrenMap": {
"@type": "java.util.LinkedHashMap",
"lilei": {
"@type": "io.seata.saga.engine.mock.DemoService$People",
"name": "lilei",
"age": 18
}
}
},
[
"[Lio.seata.saga.engine.mock.DemoService$People;",
[
{
"@type": "io.seata.saga.engine.mock.DemoService$People",
"name": "$.[people].name",
"age": "$.[people].age"
},
{
"@type": "io.seata.saga.engine.mock.DemoService$People",
"name": "$.[people].name",
"age": "$.[people].age"
}
]
],
[
"java.util.ArrayList",
[
{
"@type": "io.seata.saga.engine.mock.DemoService$People",
"name": "$.[people].name",
"age": "$.[people].age"
}
]
],
{
"@type": "java.util.LinkedHashMap",
"lilei": {
"@type": "io.seata.saga.engine.mock.DemoService$People",
"name": "$.[people].name",
"age": "$.[people].age"
}
}
],
"Output": {
"complexParameterMethodResult": "$.#root"
}
},
"ChoiceState":{
"Type": "Choice",
"Choices":[
{
"Expression":"[complexParameterMethodResult].age > 0",
"Next":"SecondState"
},
{
"Expression":"[complexParameterMethodResult].age <= 0",
"Next":"ThirdState"
}
],
"Default":"Fail"
},
"SecondState": {
"Type": "ServiceTask",
"ServiceName": "demoService",
"ServiceMethod": "interfaceParameterMethod",
"Input": [
"$.[career]"
],
"Output": {
"secondStateResult": "$.#root"
},
"Next": "ThirdState"
},
"ThirdState": {
"Type": "ServiceTask",
"ServiceName": "demoService",
"ServiceMethod": "interfaceParameterMethod",
"Input": [
"$.[secondStateResult]"
],
"Next": "Succeed"
},
"Succeed": {
"Type":"Succeed"
},
"Fail": {
"Type":"Fail",
"ErrorCode": "NOT_FOUND",
"Message": "not found"
}
}
}
\ No newline at end of file
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment