Skip to content
This repository has been archived by the owner on Feb 18, 2024. It is now read-only.

spring service delay addressing #473

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion samples/springboot-samples/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
<spring.boot.version>2.7.16</spring.boot.version>
<java.version>1.8</java.version>
<sofa.ark.version>2.2.7</sofa.ark.version>
<sofa.serverless.runtime.version>0.5.6</sofa.serverless.runtime.version>
<sofa.serverless.runtime.version>0.5.7-SNAPSHOT</sofa.serverless.runtime.version>
<disruptor.version>3.4.2</disruptor.version>
<os.plugin.version>1.7.1</os.plugin.version>
<protobuf.plugin.version>0.6.1</protobuf.plugin.version>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
public class BaseApplication {

public static void main(String[] args) {
System.setProperty("spring.service.delay.addressing.enable", "true");

SpringApplication.run(BaseApplication.class, args);
System.out.println("SofaArkSpringGuidesApplication start!");
System.out.println("Spring Boot Version: " + SpringApplication.class.getPackage().getImplementationVersion());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@
import com.alipay.sofa.biz.facade.Param;
import com.alipay.sofa.biz.facade.Provider;
import com.alipay.sofa.biz.facade.Result;
import com.alipay.sofa.serverless.common.api.AutowiredFromBiz;
import com.alipay.sofa.serverless.common.api.SpringServiceFinder;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;
import java.util.Map;

/**
Expand All @@ -19,9 +21,28 @@
@RestController
public class SampleController {

@AutowiredFromBiz(bizName = "biz1", bizVersion = "0.0.1-SNAPSHOT", name = "studentProvider")
private Provider studentProvider;

@AutowiredFromBiz(bizName = "biz1", name = "teacherProvider")
private Provider teacherProvider;

@RequestMapping(value = "/", method = RequestMethod.GET)
public String hello() {

Result tmp = studentProvider.provide(new Param());
System.out.println(tmp.getClass());
System.out.println(tmp.isSuccess());
System.out.println(tmp.getPeople().getClass());
System.out.println(tmp);

Result tmp1 = teacherProvider.provide(new Param());
System.out.println(tmp1.getClass());
System.out.println(tmp1.isSuccess());
System.out.println(tmp1.getPeople().getClass());
System.out.println(tmp1);


Provider studentProvider = SpringServiceFinder.getModuleService("biz1", "0.0.1-SNAPSHOT",
"studentProvider", Provider.class);
Result result = studentProvider.provide(new Param());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public BizRuntimeContext bizRuntimeContext(ApplicationContext applicationContext

@Bean
@ConditionalOnMissingBean
@ConditionalOnNotMasterBiz
// @ConditionalOnNotMasterBiz
public ArkAutowiredBeanPostProcessor arkAutowiredBeanPostProcessor() {
return new ArkAutowiredBeanPostProcessor();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public void prepare() {
public void test() {
contextRunner.run(context -> {
Assertions.assertThat(context).hasSingleBean(BizRuntimeContext.class);
Assertions.assertThat(context).doesNotHaveBean(ArkAutowiredBeanPostProcessor.class);
Assertions.assertThat(context).hasSingleBean(ArkAutowiredBeanPostProcessor.class);
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,6 @@

import java.util.Map;

import static com.alipay.sofa.serverless.common.service.ServiceProxyFactory.determineMostSuitableBiz;

/**
* @author: yuanyuan
* @date: 2023/9/21 9:11 下午
Expand All @@ -32,35 +30,38 @@ public class SpringServiceFinder {

public static <T> T getBaseService(String name, Class<T> serviceType) {
Biz masterBiz = ArkClient.getMasterBiz();
return ServiceProxyFactory.createServiceProxy(masterBiz, name, serviceType, null);
return ServiceProxyFactory.createServiceProxy(masterBiz.getBizName(),
masterBiz.getBizVersion(), name, serviceType, null);
}

public static <T> T getBaseService(Class<T> serviceType) {
Biz masterBiz = ArkClient.getMasterBiz();
return ServiceProxyFactory.createServiceProxy(masterBiz, serviceType, null);
return ServiceProxyFactory.createServiceProxy(masterBiz.getBizName(),
masterBiz.getBizVersion(), null, serviceType, null);
}

public static <T> Map<String, T> listBaseServices(Class<T> serviceType) {
Biz masterBiz = ArkClient.getMasterBiz();
return ServiceProxyFactory.batchCreateServiceProxy(masterBiz, serviceType, null);
return ServiceProxyFactory.batchCreateServiceProxy(masterBiz.getBizName(),
masterBiz.getBizVersion(), serviceType, null);
}

public static <T> T getModuleService(String moduleName, String moduleVersion, String name,
Class<T> serviceType) {
Biz biz = determineMostSuitableBiz(moduleName, moduleVersion);
return ServiceProxyFactory.createServiceProxy(biz, name, serviceType, null);
return ServiceProxyFactory.createServiceProxy(moduleName, moduleVersion, name, serviceType,
null);
}

public static <T> T getModuleService(String moduleName, String moduleVersion,
Class<T> serviceType) {
Biz biz = determineMostSuitableBiz(moduleName, moduleVersion);
return ServiceProxyFactory.createServiceProxy(biz, serviceType, null);
return ServiceProxyFactory.createServiceProxy(moduleName, moduleVersion, null, serviceType,
null);
}

public static <T> Map<String, T> listModuleServices(String moduleName, String moduleVersion,
Class<T> serviceType) {
Biz biz = determineMostSuitableBiz(moduleName, moduleVersion);
return ServiceProxyFactory.batchCreateServiceProxy(biz, serviceType, null);
return ServiceProxyFactory.batchCreateServiceProxy(moduleName, moduleVersion, serviceType,
null);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,6 @@
import java.util.Map;
import java.util.Set;

import static com.alipay.sofa.serverless.common.service.ServiceProxyFactory.determineMostSuitableBiz;

/**
* @author: yuanyuan
* @date: 2023/9/26 11:29 上午
Expand All @@ -59,15 +57,19 @@
AutowiredFromBase autowiredFromBase = field.getAnnotation(AutowiredFromBase.class);
AutowiredFromBiz autowiredFromBiz = field.getAnnotation(AutowiredFromBiz.class);

Biz biz;
String bizName;
String bizVersion;
String name;
boolean required;
if (autowiredFromBase != null) {
biz = ArkClient.getMasterBiz();
Biz masterBiz = ArkClient.getMasterBiz();
bizName = masterBiz.getBizName();
bizVersion = masterBiz.getBizVersion();
name = autowiredFromBase.name();
required = autowiredFromBase.required();
} else if (autowiredFromBiz != null) {
biz = determineMostSuitableBiz(autowiredFromBiz.bizName(), autowiredFromBiz.bizVersion());
bizName = autowiredFromBiz.bizName();
bizVersion = autowiredFromBiz.bizVersion();
name = autowiredFromBiz.name();
required = autowiredFromBiz.required();
} else {
Expand All @@ -80,12 +82,12 @@
try {
Class<?> fieldType = field.getType();
if (StringUtils.hasText(name)) {
serviceProxy = ServiceProxyFactory.createServiceProxy(biz, name, fieldType, clientClassLoader);
serviceProxy = ServiceProxyFactory.createServiceProxy(bizName, bizVersion, name, fieldType, clientClassLoader);

Check warning on line 85 in sofa-serverless-runtime/sofa-serverless-common/src/main/java/com/alipay/sofa/serverless/common/service/ArkAutowiredBeanPostProcessor.java

View check run for this annotation

Codecov / codecov/patch

sofa-serverless-runtime/sofa-serverless-common/src/main/java/com/alipay/sofa/serverless/common/service/ArkAutowiredBeanPostProcessor.java#L85

Added line #L85 was not covered by tests
}

if (serviceProxy == null) {
if (!Collection.class.isAssignableFrom(fieldType) && !Map.class.isAssignableFrom(fieldType)) {
serviceProxy = ServiceProxyFactory.createServiceProxy(biz, fieldType, clientClassLoader);
serviceProxy = ServiceProxyFactory.createServiceProxy(bizName, bizVersion, null, fieldType, clientClassLoader);
}
}

Expand All @@ -98,7 +100,7 @@
serviceType = (Class<?>) actualTypeArguments[1];
}

Map<String, ?> serviceProxyMap = ServiceProxyFactory.batchCreateServiceProxy(biz, serviceType, clientClassLoader);
Map<String, ?> serviceProxyMap = ServiceProxyFactory.batchCreateServiceProxy(bizName, bizVersion, serviceType, clientClassLoader);

if (Map.class.isAssignableFrom(fieldType)) {
serviceProxy = serviceProxyMap;
Expand Down Expand Up @@ -126,7 +128,7 @@
if (serviceProxy != null) {
ReflectionUtils.makeAccessible(field);
ReflectionUtils.setField(field, bean, serviceProxy);
LOGGER.info("Finished processing bean [{}], injected object [{}] to bean [{}] field [{}]", beanName, serviceProxy, bean, field);
LOGGER.info("Finished processing bean [{}], success to inject object to bean [{}] field [{}]", beanName, bean, field);
}

}, field -> !Modifier.isStatic(field.getModifiers())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
package com.alipay.sofa.serverless.common.service;

import com.alipay.sofa.ark.api.ArkClient;
import com.alipay.sofa.ark.common.util.StringUtils;
import com.alipay.sofa.ark.spi.model.Biz;
import com.alipay.sofa.ark.spi.model.BizState;
import com.alipay.sofa.serverless.common.BizRuntimeContext;
Expand All @@ -28,6 +27,7 @@
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.util.StringUtils;

import java.util.HashMap;
import java.util.List;
Expand All @@ -45,42 +45,68 @@
*/
public class ServiceProxyFactory {

public static <T> T createServiceProxy(Biz biz, String name, Class<T> serviceType,
ClassLoader clientClassLoader) {
T service = getService(biz, name);
return doCreateServiceProxy(biz, service, serviceType, clientClassLoader);
public static <T> T createServiceProxy(String bizName, String bizVersion, String name,
Class<T> clientType, ClassLoader clientClassLoader) {
Object service = getService(bizName, bizVersion, name, clientType);
return doCreateServiceProxy(bizName, bizVersion, service, name, clientType,
clientClassLoader);
}

public static <T> T createServiceProxy(Biz biz, Class<T> serviceType,
ClassLoader clientClassLoader) {
Class<?> serviceClass = checkBizStateAndGetTargetClass(biz, serviceType);
T service = (T) getService(biz, serviceClass);
return doCreateServiceProxy(biz, service, serviceType, clientClassLoader);
}

public static <T> Map<String, T> batchCreateServiceProxy(Biz biz, Class<T> serviceType,
public static <T> Map<String, T> batchCreateServiceProxy(String bizName, String bizVersion,
Class<T> serviceType,
ClassLoader clientClassLoader) {
Biz biz = ArkClient.getBizManagerService().getBiz(bizName, bizVersion);
Class<?> serviceClass = checkBizStateAndGetTargetClass(biz, serviceType);
Map<String, ?> serviceMap = listService(biz, serviceClass);
Map<String, T> proxyMap = new HashMap<>();
for (String beanName : serviceMap.keySet()) {
proxyMap
.put(
beanName,
doCreateServiceProxy(biz, serviceMap.get(beanName), serviceType,
clientClassLoader));
proxyMap.put(
beanName,
doCreateServiceProxy(biz.getBizName(), biz.getBizVersion(),
serviceMap.get(beanName), null, serviceType, clientClassLoader));
}
return proxyMap;
}

private static <T> T getService(Biz biz, String name) {
BizRuntimeContext bizRuntimeContext = checkBizStateAndGetBizRuntimeContext(biz);
return (T) bizRuntimeContext.getRootApplicationContext().getBean(name);
}
public static Object getService(String bizName, String bizVersion, String name,
Class<?> clientType) {
Biz biz = determineMostSuitableBiz(bizName, bizVersion);

private static <T> T getService(Biz biz, Class<T> serviceType) {
BizRuntimeContext bizRuntimeContext = checkBizStateAndGetBizRuntimeContext(biz);
return bizRuntimeContext.getRootApplicationContext().getBean(serviceType);
if (biz == null && Boolean.getBoolean("spring.service.delay.addressing.enable")) {
return null;

Check warning on line 76 in sofa-serverless-runtime/sofa-serverless-common/src/main/java/com/alipay/sofa/serverless/common/service/ServiceProxyFactory.java

View check run for this annotation

Codecov / codecov/patch

sofa-serverless-runtime/sofa-serverless-common/src/main/java/com/alipay/sofa/serverless/common/service/ServiceProxyFactory.java#L76

Added line #L76 was not covered by tests
}

if (biz == null) {
throw new BizRuntimeException(E100003, "biz does not exist");

Check warning on line 80 in sofa-serverless-runtime/sofa-serverless-common/src/main/java/com/alipay/sofa/serverless/common/service/ServiceProxyFactory.java

View check run for this annotation

Codecov / codecov/patch

sofa-serverless-runtime/sofa-serverless-common/src/main/java/com/alipay/sofa/serverless/common/service/ServiceProxyFactory.java#L80

Added line #L80 was not covered by tests
} else if (biz.getBizState() != BizState.ACTIVATED
&& biz.getBizState() != BizState.DEACTIVATED) {
throw new BizRuntimeException(E100004, "biz state is not valid");

Check warning on line 83 in sofa-serverless-runtime/sofa-serverless-common/src/main/java/com/alipay/sofa/serverless/common/service/ServiceProxyFactory.java

View check run for this annotation

Codecov / codecov/patch

sofa-serverless-runtime/sofa-serverless-common/src/main/java/com/alipay/sofa/serverless/common/service/ServiceProxyFactory.java#L83

Added line #L83 was not covered by tests
}

BizRuntimeContext bizRuntimeContext = BizRuntimeContextRegistry.getBizRuntimeContext(biz);
if (bizRuntimeContext == null) {
throw new BizRuntimeException(E100002, "biz runtime context is null");

Check warning on line 88 in sofa-serverless-runtime/sofa-serverless-common/src/main/java/com/alipay/sofa/serverless/common/service/ServiceProxyFactory.java

View check run for this annotation

Codecov / codecov/patch

sofa-serverless-runtime/sofa-serverless-common/src/main/java/com/alipay/sofa/serverless/common/service/ServiceProxyFactory.java#L88

Added line #L88 was not covered by tests
}
if (bizRuntimeContext.getRootApplicationContext() == null) {
throw new BizRuntimeException(E100002, "biz spring context is null");

Check warning on line 91 in sofa-serverless-runtime/sofa-serverless-common/src/main/java/com/alipay/sofa/serverless/common/service/ServiceProxyFactory.java

View check run for this annotation

Codecov / codecov/patch

sofa-serverless-runtime/sofa-serverless-common/src/main/java/com/alipay/sofa/serverless/common/service/ServiceProxyFactory.java#L91

Added line #L91 was not covered by tests
}

if (StringUtils.hasText(name)) {
return bizRuntimeContext.getRootApplicationContext().getBean(name);
}

if (clientType != null) {
Class<?> serviceType;
try {
serviceType = biz.getBizClassLoader().loadClass(clientType.getName());
} catch (ClassNotFoundException e) {
throw new BizRuntimeException(E100005, "Cannot find class " + clientType.getName()
+ " from the biz " + biz.getIdentity());

Check warning on line 104 in sofa-serverless-runtime/sofa-serverless-common/src/main/java/com/alipay/sofa/serverless/common/service/ServiceProxyFactory.java

View check run for this annotation

Codecov / codecov/patch

sofa-serverless-runtime/sofa-serverless-common/src/main/java/com/alipay/sofa/serverless/common/service/ServiceProxyFactory.java#L102-L104

Added lines #L102 - L104 were not covered by tests
}
return bizRuntimeContext.getRootApplicationContext().getBean(serviceType);
}

throw new BizRuntimeException(E100002, "invalid config");

Check warning on line 109 in sofa-serverless-runtime/sofa-serverless-common/src/main/java/com/alipay/sofa/serverless/common/service/ServiceProxyFactory.java

View check run for this annotation

Codecov / codecov/patch

sofa-serverless-runtime/sofa-serverless-common/src/main/java/com/alipay/sofa/serverless/common/service/ServiceProxyFactory.java#L109

Added line #L109 was not covered by tests
}

private static <T> Map<String, T> listService(Biz biz, Class<T> serviceType) {
Expand All @@ -96,41 +122,49 @@

/**
* @param biz 目标biz
* @param name 目标biz中beanName
* @param service 目标biz中符合条件的bean
* @param serviceType 调用方serviceType
* @param clientType 调用方clientType
* @param clientClassLoader 调用方classloader
* @return 供调用方调用的代理对象
*/
private static <T> T doCreateServiceProxy(Biz biz, Object service, Class<T> serviceType, ClassLoader clientClassLoader) {
private static <T> T doCreateServiceProxy(String bizName, String bizVersion, Object service, String name, Class<T> clientType, ClassLoader clientClassLoader) {
if (clientClassLoader == null) {
Class<?> callerClass = ReflectionUtils.getCallerClass(6);
clientClassLoader = callerClass.getClassLoader();
}

BizRuntimeContext bizRuntimeContext = BizRuntimeContextRegistry.getBizRuntimeContextByClassLoader(clientClassLoader);
Map<ClassLoader, Map<String, ServiceProxyCache>> serviceProxyCaches =
bizRuntimeContext.getServiceProxyCaches();
Map<String, ServiceProxyCache> cacheMap = serviceProxyCaches.computeIfAbsent(biz.getBizClassLoader(), o -> new ConcurrentHashMap<>());
// 服务端模块被卸载时,cacheMap会被清空,需要重新生成proxy并缓存
if (cacheMap.containsKey(service.getClass().getName())) {
ServiceProxyCache serviceProxyCache = cacheMap.get(service.getClass().getName());
return (T) serviceProxyCache.getProxy();
}

SpringServiceInvoker serviceInvoker = new SpringServiceInvoker(service, biz.getBizName(),
biz.getBizVersion(), biz.getIdentity(), clientClassLoader, service
.getClass().getClassLoader());
Map<ClassLoader, Map<String, ServiceProxyCache>> serviceProxyCaches = bizRuntimeContext.getServiceProxyCaches();

Biz biz = determineMostSuitableBiz(bizName, bizVersion);

if (biz != null) {
Map<String, ServiceProxyCache> cacheMap = serviceProxyCaches.computeIfAbsent(biz.getBizClassLoader(), o -> new ConcurrentHashMap<>());
// 服务端模块被卸载时,cacheMap会被清空,需要重新生成proxy并缓存
String cacheKey = service != null ? service.getClass().getName() : clientType.getName();
if (cacheMap.containsKey(cacheKey)) {
ServiceProxyCache serviceProxyCache = cacheMap.get(cacheKey);
return (T) serviceProxyCache.getProxy();
}
}

SpringServiceInvoker serviceInvoker = new SpringServiceInvoker(service, name, clientType, bizName, bizVersion, clientClassLoader, service != null ? service.getClass().getClassLoader() : null);
ProxyFactory factory = new ProxyFactory();
if (serviceType.isInterface()) {
factory.addInterface(serviceType);
if (clientType.isInterface()) {
factory.addInterface(clientType);

Check warning on line 155 in sofa-serverless-runtime/sofa-serverless-common/src/main/java/com/alipay/sofa/serverless/common/service/ServiceProxyFactory.java

View check run for this annotation

Codecov / codecov/patch

sofa-serverless-runtime/sofa-serverless-common/src/main/java/com/alipay/sofa/serverless/common/service/ServiceProxyFactory.java#L155

Added line #L155 was not covered by tests
} else {
factory.setTargetClass(serviceType);
factory.setTargetClass(clientType);
factory.setProxyTargetClass(true);
}
factory.addAdvice(serviceInvoker);
Object proxy = factory.getProxy(clientClassLoader);

cacheMap.put(service.getClass().getName(), new ServiceProxyCache(proxy, serviceInvoker));
if (biz != null) {
String cacheKey = service != null ? service.getClass().getName() : clientType.getName();
Map<String, ServiceProxyCache> cacheMap = serviceProxyCaches.computeIfAbsent(biz.getBizClassLoader(), o -> new ConcurrentHashMap<>());
cacheMap.put(cacheKey, new ServiceProxyCache(proxy, serviceInvoker));
}

return (T) proxy;
}
Expand All @@ -139,6 +173,9 @@
Biz biz;
if (StringUtils.isEmpty(moduleVersion)) {
List<Biz> bizList = ArkClient.getBizManagerService().getBiz(moduleName);
if (bizList.size() == 0) {
return null;

Check warning on line 177 in sofa-serverless-runtime/sofa-serverless-common/src/main/java/com/alipay/sofa/serverless/common/service/ServiceProxyFactory.java

View check run for this annotation

Codecov / codecov/patch

sofa-serverless-runtime/sofa-serverless-common/src/main/java/com/alipay/sofa/serverless/common/service/ServiceProxyFactory.java#L177

Added line #L177 was not covered by tests
}
biz = bizList.stream().filter(it -> BizState.ACTIVATED == it.getBizState()).findFirst().get();
} else {
biz = ArkClient.getBizManagerService().getBiz(moduleName, moduleVersion);
Expand Down
Loading