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

Commit

Permalink
spring service delay find
Browse files Browse the repository at this point in the history
  • Loading branch information
yuanyuan2021 committed Jan 16, 2024
1 parent d985cb2 commit a3e6255
Show file tree
Hide file tree
Showing 9 changed files with 153 additions and 75 deletions.
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.6</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 @@ -77,10 +77,10 @@ public String hello() {
Result provide2 = provider.provide(new Param());
}

Provider teacherProvider1 = SpringServiceFinder.getModuleService("biz", "0.0.1-SNAPSHOT", "teacherProvider", Provider.class);
Provider teacherProvider1 = SpringServiceFinder.getModuleService("biz1", "0.0.1-SNAPSHOT", "teacherProvider", Provider.class);
Result result1 = teacherProvider1.provide(new Param());

Map<String, Provider> providerMap = SpringServiceFinder.listModuleServices("biz", "0.0.1-SNAPSHOT", Provider.class);
Map<String, Provider> providerMap = SpringServiceFinder.listModuleServices("biz1", "0.0.1-SNAPSHOT", Provider.class);
for (String beanName : providerMap.keySet()) {
Result result2 = providerMap.get(beanName).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 @@ -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 @@ public Object postProcessBeforeInitialization(Object bean, String beanName) thro
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 @@ public Object postProcessBeforeInitialization(Object bean, String beanName) thro
try {
Class<?> fieldType = field.getType();
if (StringUtils.hasText(name)) {
serviceProxy = ServiceProxyFactory.createServiceProxy(biz, name, fieldType, clientClassLoader);
serviceProxy = ServiceProxyFactory.createServiceProxy(bizName, bizVersion, name, fieldType, clientClassLoader);
}

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 @@ public Object postProcessBeforeInitialization(Object bean, String beanName) thro
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 @@ public Object postProcessBeforeInitialization(Object bean, String beanName) thro
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;
}

if (biz == null) {
throw new BizRuntimeException(E100003, "biz does not exist");
} else if (biz.getBizState() != BizState.ACTIVATED
&& biz.getBizState() != BizState.DEACTIVATED) {
throw new BizRuntimeException(E100004, "biz state is not valid");
}

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

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());
}
return bizRuntimeContext.getRootApplicationContext().getBean(serviceType);
}

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

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

/**
* @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);
} 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 @@ public static Biz determineMostSuitableBiz(String moduleName, String moduleVersi
Biz biz;
if (StringUtils.isEmpty(moduleVersion)) {
List<Biz> bizList = ArkClient.getBizManagerService().getBiz(moduleName);
if (bizList.size() == 0) {
return null;
}
biz = bizList.stream().filter(it -> BizState.ACTIVATED == it.getBizState()).findFirst().get();
} else {
biz = ArkClient.getBizManagerService().getBiz(moduleName, moduleVersion);
Expand Down
Loading

0 comments on commit a3e6255

Please sign in to comment.