diff --git a/pom.xml b/pom.xml index 1adeb6a5c3d0d970b21849d9f58b2b2726d2117b..b08ed89addbb69f9058d34dcab23d952b1e0d011 100644 --- a/pom.xml +++ b/pom.xml @@ -14,6 +14,7 @@ sdk-springboot sdk-context sdk-examples + sdk-springboot3 pom @@ -27,6 +28,7 @@ 3.8.1 2.7.11 + 3.2.5 2.3.23 31.1-jre 1.61.0 @@ -256,18 +258,6 @@ maven-compiler-plugin ${maven.plugin.version} - - org.springframework.boot - spring-boot - ${spring.boot.version} - provided - - - org.springframework.boot - spring-boot-autoconfigure - ${spring.boot.version} - provided - org.slf4j diff --git a/sdk-springboot/pom.xml b/sdk-springboot/pom.xml index 8d51de30679a449c18fbecde2ab49c1f23bb0f70..457822175af8d6805263da3e23b04a9a4ae7c8ef 100644 --- a/sdk-springboot/pom.xml +++ b/sdk-springboot/pom.xml @@ -31,11 +31,14 @@ org.springframework.boot spring-boot + ${spring.boot.version} org.springframework.boot spring-boot-autoconfigure + ${spring.boot.version} + diff --git a/sdk-springboot3/pom.xml b/sdk-springboot3/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..36e824c2dbad9a79a5cb51a1883d2855400e9ac7 --- /dev/null +++ b/sdk-springboot3/pom.xml @@ -0,0 +1,101 @@ + + + + io.openkunlun + sdk-java + 1.0.0-SNAPSHOT + + 4.0.0 + + sdk-springboot3 + + + 17 + 17 + UTF-8 + + + + + + org.projectlombok + lombok + 1.18.22 + provided + + + javax.annotation + javax.annotation-api + provided + + + ${project.groupId} + sdk-java-rpc + ${project.version} + + + + org.springframework.boot + spring-boot + ${spring.boot3.version} + + + org.springframework.boot + spring-boot-autoconfigure + ${spring.boot3.version} + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + 17 + 17 + UTF-8 + + + + org.apache.maven.plugins + maven-jar-plugin + + + **/log4j.xml + **/log4j2.xml + **/logback.xml + **/*.yml + **/*.yaml + **/*.conf + **/*.properties + **/META-INF/*.xml + + + false + false + + true + true + + + + + + org.apache.maven.plugins + maven-source-plugin + + + attach-sources + + jar + + + + + + + \ No newline at end of file diff --git a/sdk-springboot3/src/main/java/io/openkunlun/javadsl/springboot3/EnableDaprClient.java b/sdk-springboot3/src/main/java/io/openkunlun/javadsl/springboot3/EnableDaprClient.java new file mode 100644 index 0000000000000000000000000000000000000000..ac9f0ccc5466dd7d54bd29f4b926dc447150958f --- /dev/null +++ b/sdk-springboot3/src/main/java/io/openkunlun/javadsl/springboot3/EnableDaprClient.java @@ -0,0 +1,19 @@ +package io.openkunlun.javadsl.springboot3; + +import io.openkunlun.javadsl.springboot3.client.DaprClientConfigurator; +import io.openkunlun.javadsl.springboot3.client.DaprStubRegistrar; +import org.springframework.context.annotation.Import; + +import java.lang.annotation.*; + +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE}) +@Documented +@Import({DaprStubRegistrar.class, DaprClientConfigurator.class}) +public @interface EnableDaprClient { + + /** + * @return + */ + String[] basePackages() default {}; +} diff --git a/sdk-springboot3/src/main/java/io/openkunlun/javadsl/springboot3/EnableDaprServer.java b/sdk-springboot3/src/main/java/io/openkunlun/javadsl/springboot3/EnableDaprServer.java new file mode 100644 index 0000000000000000000000000000000000000000..b17f7de3c095c60de208d5b0855448c585c033fc --- /dev/null +++ b/sdk-springboot3/src/main/java/io/openkunlun/javadsl/springboot3/EnableDaprServer.java @@ -0,0 +1,22 @@ +package io.openkunlun.javadsl.springboot3; + +import io.openkunlun.javadsl.springboot3.client.DaprClientConfigurator; +import io.openkunlun.javadsl.springboot3.server.DaprFailureDetectorRegistrar; +import io.openkunlun.javadsl.springboot3.server.DaprHandlerRegistrar; +import io.openkunlun.javadsl.springboot3.server.DaprResolverRegistrar; +import io.openkunlun.javadsl.springboot3.server.DaprServerConfigurator; +import org.springframework.context.annotation.Import; + +import java.lang.annotation.*; + +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE}) +@Documented +@Import({DaprHandlerRegistrar.class, DaprResolverRegistrar.class, DaprFailureDetectorRegistrar.class, DaprClientConfigurator.class, DaprServerConfigurator.class}) +public @interface EnableDaprServer { + + /** + * @return + */ + String[] basePackages() default {}; +} diff --git a/sdk-springboot3/src/main/java/io/openkunlun/javadsl/springboot3/client/DaprClientConfigurator.java b/sdk-springboot3/src/main/java/io/openkunlun/javadsl/springboot3/client/DaprClientConfigurator.java new file mode 100644 index 0000000000000000000000000000000000000000..83eaf26a7c2afdbe02b22e1eadd0262519641524 --- /dev/null +++ b/sdk-springboot3/src/main/java/io/openkunlun/javadsl/springboot3/client/DaprClientConfigurator.java @@ -0,0 +1,42 @@ +package io.openkunlun.javadsl.springboot3.client; + +import io.openkunlun.javadsl.client.DaprClient; +import io.openkunlun.javadsl.serialization.DaprSerializer; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Lazy; +import org.springframework.context.annotation.Role; + +import javax.annotation.Resource; + +@Configuration +@Role(BeanDefinition.ROLE_INFRASTRUCTURE) +@EnableConfigurationProperties(DaprClientProperties.class) +public class DaprClientConfigurator { + + @Resource + private DaprClientProperties properties; + + @Lazy + @Bean(destroyMethod = "close") + @ConditionalOnMissingBean(DaprClient.class) + DaprClient client() { + return new DaprClient( + properties.getHost(), + properties.getPort(), + properties.getTimeout(), + properties.getMaxMessageBytes(), + properties.getMaxMetadataBytes() + ); + } + + @Lazy + @Bean + @ConditionalOnMissingBean(DaprSerializer.class) + DaprSerializer serializer() { + return DaprSerializer.CBOR; + } +} diff --git a/sdk-springboot3/src/main/java/io/openkunlun/javadsl/springboot3/client/DaprClientProperties.java b/sdk-springboot3/src/main/java/io/openkunlun/javadsl/springboot3/client/DaprClientProperties.java new file mode 100644 index 0000000000000000000000000000000000000000..5943ddd118b3931e901d3ed0ca7d611904445e4c --- /dev/null +++ b/sdk-springboot3/src/main/java/io/openkunlun/javadsl/springboot3/client/DaprClientProperties.java @@ -0,0 +1,18 @@ +package io.openkunlun.javadsl.springboot3.client; + +import io.openkunlun.javadsl.client.DaprClient; +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; + +@Data +@ConfigurationProperties(prefix = "dapr.client") +public class DaprClientProperties { + + private String host = DaprClient.DEFAULT_HOST; + private int port = DaprClient.DEFAULT_PORT; + private int timeout = DaprClient.DEFAULT_TIMEOUT; + + private int maxMessageBytes = DaprClient.DEFAULT_MAX_MESSAGE_BYTES; + private int maxMetadataBytes = DaprClient.DEFAULT_MAX_METADATA_BYTES; + +} diff --git a/sdk-springboot3/src/main/java/io/openkunlun/javadsl/springboot3/client/DaprStubFactoryBean.java b/sdk-springboot3/src/main/java/io/openkunlun/javadsl/springboot3/client/DaprStubFactoryBean.java new file mode 100644 index 0000000000000000000000000000000000000000..0200f4f8013048c867b7f24939acc546d19eb7e2 --- /dev/null +++ b/sdk-springboot3/src/main/java/io/openkunlun/javadsl/springboot3/client/DaprStubFactoryBean.java @@ -0,0 +1,41 @@ +package io.openkunlun.javadsl.springboot3.client; + +import io.openkunlun.javarpc.RpcStub; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.FactoryBean; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; + +import java.util.List; +import java.util.stream.Collectors; + +public class DaprStubFactoryBean implements FactoryBean, ApplicationContextAware { + + private final Class type; + private final List> fields; + private ApplicationContext applicationContext; + + public DaprStubFactoryBean(Class type, List> fields) { + this.type = type; + this.fields = fields; + } + + @Override + public RpcStub getObject() throws Exception { + List params = fields.stream().map(it -> applicationContext.getBean(it)).collect(Collectors.toList()); + RpcStub instance = this.type.getDeclaredConstructor(fields.toArray(new Class[]{})).newInstance(params.toArray(new Object[]{})); + applicationContext.getAutowireCapableBeanFactory().autowireBean(instance); + return instance; + } + + @Override + public Class getObjectType() { + return type; + } + + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + this.applicationContext = applicationContext; + } + +} diff --git a/sdk-springboot3/src/main/java/io/openkunlun/javadsl/springboot3/client/DaprStubRegistrar.java b/sdk-springboot3/src/main/java/io/openkunlun/javadsl/springboot3/client/DaprStubRegistrar.java new file mode 100644 index 0000000000000000000000000000000000000000..6c69c12c8ab5c2331df639dc4a47ce4208dd6ad4 --- /dev/null +++ b/sdk-springboot3/src/main/java/io/openkunlun/javadsl/springboot3/client/DaprStubRegistrar.java @@ -0,0 +1,108 @@ +package io.openkunlun.javadsl.springboot3.client; + +import com.google.common.collect.Lists; +import io.openkunlun.javadsl.springboot3.EnableDaprClient; +import io.openkunlun.javarpc.RpcStub; +import org.springframework.beans.factory.BeanInitializationException; +import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.support.AbstractBeanDefinition; +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.context.EnvironmentAware; +import org.springframework.context.ResourceLoaderAware; +import org.springframework.context.annotation.ClassPathBeanDefinitionScanner; +import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; +import org.springframework.core.annotation.AnnotationAttributes; +import org.springframework.core.env.Environment; +import org.springframework.core.io.ResourceLoader; +import org.springframework.core.type.AnnotationMetadata; +import org.springframework.core.type.filter.AssignableTypeFilter; + +import java.lang.reflect.Field; +import java.util.*; +import java.util.stream.Collectors; + +public class DaprStubRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware, EnvironmentAware { + + private Environment environment; + private ResourceLoader resourceLoader; + + @Override + public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) { + + if (!metadata.hasAnnotation(EnableDaprClient.class.getName())) { + return; + } + + Map annotationAttributesMap = metadata.getAnnotationAttributes(EnableDaprClient.class.getName()); + AnnotationAttributes annotationAttributes = Optional.ofNullable(AnnotationAttributes.fromMap(annotationAttributesMap)).orElseGet(AnnotationAttributes::new); + Set packages = retrievePackagesName(metadata, annotationAttributes); + ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(registry, false, environment, resourceLoader); + scanner.addIncludeFilter(new AssignableTypeFilter(RpcStub.class)); + for (String needScanPackage : packages) { + Set candidateComponents = scanner.findCandidateComponents(needScanPackage); + try { + registerCandidateComponents(registry, candidateComponents); + } catch (ClassNotFoundException e) { + throw new BeanInitializationException("DaprStub registration failed.", e); + } + } + } + + private Set retrievePackagesName(AnnotationMetadata annotationMetadata, AnnotationAttributes attributes) { + String[] packages = attributes.getStringArray("basePackages"); + Set packagesToScan = new LinkedHashSet<>(Arrays.asList(packages)); + if (packagesToScan.isEmpty()) { + packagesToScan.add(getPackageName(annotationMetadata.getClassName())); + } + return packagesToScan; + } + + private void registerCandidateComponents(BeanDefinitionRegistry registry, Set candidateComponents) throws ClassNotFoundException { + for (BeanDefinition candidateComponent : candidateComponents) { + + if (candidateComponent instanceof AnnotatedBeanDefinition) { + AnnotatedBeanDefinition annotatedBeanDefinition = (AnnotatedBeanDefinition) candidateComponent; + AnnotationMetadata annotationMetadata = annotatedBeanDefinition.getMetadata(); + Class clazz = Class.forName(annotationMetadata.getClassName()); + List> fields = Lists.newArrayList(clazz.getDeclaredFields()).stream().map(Field::getType).collect(Collectors.toList()); + AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(DaprStubFactoryBean.class) + .addConstructorArgValue(clazz) + .addConstructorArgValue(fields) + .setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE) + .setRole(BeanDefinition.ROLE_INFRASTRUCTURE) + .setPrimary(true) + .getBeanDefinition(); + registry.registerBeanDefinition(clazz.getName(), beanDefinition); + } + } + } + + @Override + public void setEnvironment(Environment environment) { + this.environment = environment; + } + + @Override + public void setResourceLoader(ResourceLoader resourceLoader) { + this.resourceLoader = resourceLoader; + } + + static String getPackageName(String className) { + if (null == className || className.isEmpty()) { + return ""; + } else { + while (className.charAt(0) == '[') { + className = className.substring(1); + } + + if (className.charAt(0) == 'L' && className.charAt(className.length() - 1) == ';') { + className = className.substring(1); + } + + int i = className.lastIndexOf(46); + return i == -1 ? "" : className.substring(0, i); + } + } +} diff --git a/sdk-springboot3/src/main/java/io/openkunlun/javadsl/springboot3/server/DaprFailureDetectorRegistrar.java b/sdk-springboot3/src/main/java/io/openkunlun/javadsl/springboot3/server/DaprFailureDetectorRegistrar.java new file mode 100644 index 0000000000000000000000000000000000000000..f9704439412de1da73552ba83c26a1ed9e88c77e --- /dev/null +++ b/sdk-springboot3/src/main/java/io/openkunlun/javadsl/springboot3/server/DaprFailureDetectorRegistrar.java @@ -0,0 +1,19 @@ +package io.openkunlun.javadsl.springboot3.server; + +import io.openkunlun.javadsl.server.FailureDetector; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Role; + +@Configuration +@Role(BeanDefinition.ROLE_INFRASTRUCTURE) +public class DaprFailureDetectorRegistrar { + + @Bean(name = "daprFailureDetector") + @ConditionalOnMissingBean + FailureDetector failureDetector() { + return FailureDetector.AVAILABLE; + } +} diff --git a/sdk-springboot3/src/main/java/io/openkunlun/javadsl/springboot3/server/DaprHandlerFactoryBean.java b/sdk-springboot3/src/main/java/io/openkunlun/javadsl/springboot3/server/DaprHandlerFactoryBean.java new file mode 100644 index 0000000000000000000000000000000000000000..9f898456efbb5df8c11ac312c21f6946b7c15b6e --- /dev/null +++ b/sdk-springboot3/src/main/java/io/openkunlun/javadsl/springboot3/server/DaprHandlerFactoryBean.java @@ -0,0 +1,67 @@ +package io.openkunlun.javadsl.springboot3.server; + +import io.openkunlun.javadsl.server.DaprHandler; +import io.openkunlun.javarpc.RpcImplement; +import io.openkunlun.javarpc.RpcStub; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.FactoryBean; +import org.springframework.beans.factory.NoSuchBeanDefinitionException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; + +import java.lang.reflect.Field; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +public class DaprHandlerFactoryBean implements FactoryBean, ApplicationContextAware { + + private final Class type; + private final List fields; + private final List> args; + private ApplicationContext applicationContext; + + /** + * @param type + * @param fields + */ + public DaprHandlerFactoryBean(Class type, List fields) { + this.args = fields.stream().map(Field::getType).collect(Collectors.toList()); + this.fields = fields; + this.type = type; + } + + @Override + public DaprHandler getObject() throws Exception { + List params = fields.stream().map(this::applicationContextBean).collect(Collectors.toList()); + DaprHandler instance = this.type.getDeclaredConstructor(args.toArray(new Class[]{})).newInstance(params.toArray(new Object[]{})); + applicationContext.getAutowireCapableBeanFactory().autowireBean(instance); + return instance; + } + + @Override + public Class getObjectType() { + return type; + } + + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + this.applicationContext = applicationContext; + } + + private Object applicationContextBean(Field field) { + Class clazz = field.getType(); + RpcImplement implement = field.getAnnotation(RpcImplement.class); + if (implement != null) { + Map beans = applicationContext.getBeansOfType(clazz); + for (Object t : beans.values()) { + if (!(t instanceof RpcStub)) { + return t; + } + } + throw new NoSuchBeanDefinitionException(clazz); + } else { + return applicationContext.getBean(clazz); + } + } +} diff --git a/sdk-springboot3/src/main/java/io/openkunlun/javadsl/springboot3/server/DaprHandlerRegistrar.java b/sdk-springboot3/src/main/java/io/openkunlun/javadsl/springboot3/server/DaprHandlerRegistrar.java new file mode 100644 index 0000000000000000000000000000000000000000..68e24f8b78c6fdcbf58ce335b99466b7b4831f6e --- /dev/null +++ b/sdk-springboot3/src/main/java/io/openkunlun/javadsl/springboot3/server/DaprHandlerRegistrar.java @@ -0,0 +1,107 @@ +package io.openkunlun.javadsl.springboot3.server; + +import com.google.common.collect.Lists; +import io.openkunlun.javadsl.springboot3.EnableDaprServer; +import io.openkunlun.javarpc.RpcHandler; +import org.springframework.beans.factory.BeanInitializationException; +import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.support.AbstractBeanDefinition; +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.context.EnvironmentAware; +import org.springframework.context.ResourceLoaderAware; +import org.springframework.context.annotation.ClassPathBeanDefinitionScanner; +import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; +import org.springframework.core.annotation.AnnotationAttributes; +import org.springframework.core.env.Environment; +import org.springframework.core.io.ResourceLoader; +import org.springframework.core.type.AnnotationMetadata; +import org.springframework.core.type.filter.AssignableTypeFilter; + +import java.lang.reflect.Field; +import java.util.*; + +public class DaprHandlerRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware, EnvironmentAware { + + private Environment environment; + private ResourceLoader resourceLoader; + + @Override + public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) { + + if (!metadata.hasAnnotation(EnableDaprServer.class.getName())) { + return; + } + + Map annotationAttributesMap = metadata.getAnnotationAttributes(EnableDaprServer.class.getName()); + AnnotationAttributes annotationAttributes = Optional.ofNullable(AnnotationAttributes.fromMap(annotationAttributesMap)).orElseGet(AnnotationAttributes::new); + Set packages = retrievePackagesName(metadata, annotationAttributes); + ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(registry, false, environment, resourceLoader); + scanner.addIncludeFilter(new AssignableTypeFilter(RpcHandler.class)); + + for (String needScanPackage : packages) { + Set candidateComponents = scanner.findCandidateComponents(needScanPackage); + try { + registerCandidateComponents(registry, candidateComponents); + } catch (ClassNotFoundException e) { + throw new BeanInitializationException("DaprHandler registration failed.", e); + } + } + } + + private Set retrievePackagesName(AnnotationMetadata annotationMetadata, AnnotationAttributes attributes) { + String[] packages = attributes.getStringArray("basePackages"); + Set packagesToScan = new LinkedHashSet<>(Arrays.asList(packages)); + if (packagesToScan.isEmpty()) { + packagesToScan.add(getPackageName(annotationMetadata.getClassName())); + } + return packagesToScan; + } + + private void registerCandidateComponents(BeanDefinitionRegistry registry, Set candidateComponents) throws ClassNotFoundException { + for (BeanDefinition candidateComponent : candidateComponents) { + if (candidateComponent instanceof AnnotatedBeanDefinition) { + AnnotatedBeanDefinition annotatedBeanDefinition = (AnnotatedBeanDefinition) candidateComponent; + AnnotationMetadata annotationMetadata = annotatedBeanDefinition.getMetadata(); + Class clazz = Class.forName(annotationMetadata.getClassName()); + List fields = Lists.newArrayList(clazz.getDeclaredFields()); + AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(DaprHandlerFactoryBean.class) + .addConstructorArgValue(clazz) + .addConstructorArgValue(fields) + .setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE) + .setRole(BeanDefinition.ROLE_INFRASTRUCTURE) + .getBeanDefinition(); + registry.registerBeanDefinition(clazz.getName(), beanDefinition); + } + } + } + + + @Override + public void setEnvironment(Environment environment) { + this.environment = environment; + } + + @Override + public void setResourceLoader(ResourceLoader resourceLoader) { + this.resourceLoader = resourceLoader; + } + + static String getPackageName(String className) { + if (null == className || className.isEmpty()) { + return ""; + } else { + while (className.charAt(0) == '[') { + className = className.substring(1); + } + + if (className.charAt(0) == 'L' && className.charAt(className.length() - 1) == ';') { + className = className.substring(1); + } + + int i = className.lastIndexOf(46); + return i == -1 ? "" : className.substring(0, i); + } + } +} diff --git a/sdk-springboot3/src/main/java/io/openkunlun/javadsl/springboot3/server/DaprResolverRegistrar.java b/sdk-springboot3/src/main/java/io/openkunlun/javadsl/springboot3/server/DaprResolverRegistrar.java new file mode 100644 index 0000000000000000000000000000000000000000..210496a63c7d0915d45c127f6e12642ea64889c4 --- /dev/null +++ b/sdk-springboot3/src/main/java/io/openkunlun/javadsl/springboot3/server/DaprResolverRegistrar.java @@ -0,0 +1,19 @@ +package io.openkunlun.javadsl.springboot3.server; + +import io.openkunlun.javadsl.DaprExceptionResolver; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Role; + +@Configuration +@Role(BeanDefinition.ROLE_INFRASTRUCTURE) +public class DaprResolverRegistrar { + + @Bean(name = "daprExceptionResolver") + @ConditionalOnMissingBean + DaprExceptionResolver resolver() { + return DaprExceptionResolver.DEFAULT; + } +} diff --git a/sdk-springboot3/src/main/java/io/openkunlun/javadsl/springboot3/server/DaprServerConfigurator.java b/sdk-springboot3/src/main/java/io/openkunlun/javadsl/springboot3/server/DaprServerConfigurator.java new file mode 100644 index 0000000000000000000000000000000000000000..24d92351844028a0e4255b4a78adcc16f6de1846 --- /dev/null +++ b/sdk-springboot3/src/main/java/io/openkunlun/javadsl/springboot3/server/DaprServerConfigurator.java @@ -0,0 +1,66 @@ +package io.openkunlun.javadsl.springboot3.server; + +import io.openkunlun.javadsl.DaprExceptionResolver; +import io.openkunlun.javadsl.client.DaprClient; +import io.openkunlun.javadsl.server.DaprHandler; +import io.openkunlun.javadsl.server.DaprServer; +import io.openkunlun.javadsl.server.FailureDetector; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Role; + +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; +import javax.annotation.Resource; +import java.io.IOException; +import java.util.Map; + +@Configuration +@Role(BeanDefinition.ROLE_INFRASTRUCTURE) +@EnableConfigurationProperties(DaprServerProperties.class) +public class DaprServerConfigurator { + + @Resource + private ApplicationContext applicationContext; + @Resource + private DaprServerProperties properties; + + @Resource + private DaprClient daprClient; + private DaprServer daprServer; + + @PostConstruct + public void init() throws IOException { + Map handlers = applicationContext.getBeansOfType(DaprHandler.class); + DaprExceptionResolver errorHandler = applicationContext.getBean(DaprExceptionResolver.class); + FailureDetector failureDetector = applicationContext.getBean(FailureDetector.class); + daprServer = DaprServer + .forAddress(daprClient, properties.getHost(), properties.getPort()) + .setId(properties.getId()) + .setTtl(properties.getTtl()) + .setWeight(properties.getWeight()) + .setWarmup(properties.getWarmup()) + .failureDetector(failureDetector) + .addHandlers(handlers.values().toArray(new DaprHandler[]{})) + .errorHandler(errorHandler) + .build(); + daprServer.start(); + } + + @PreDestroy + public void destroy() { + if (daprServer != null) { + daprServer.stop(); + } + } + + @Bean(name = "daprServerListener") + @ConditionalOnMissingBean + DaprServerListener listener() { + return new DaprServerListener(); + } +} diff --git a/sdk-springboot3/src/main/java/io/openkunlun/javadsl/springboot3/server/DaprServerListener.java b/sdk-springboot3/src/main/java/io/openkunlun/javadsl/springboot3/server/DaprServerListener.java new file mode 100644 index 0000000000000000000000000000000000000000..49496fa7f7fe90b33f05f8fbd1b49f9587612460 --- /dev/null +++ b/sdk-springboot3/src/main/java/io/openkunlun/javadsl/springboot3/server/DaprServerListener.java @@ -0,0 +1,112 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.openkunlun.javadsl.springboot3.server; + +import org.springframework.boot.context.event.ApplicationReadyEvent; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationEvent; +import org.springframework.context.ApplicationListener; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.event.ContextClosedEvent; +import org.springframework.context.event.SmartApplicationListener; +import org.springframework.util.ClassUtils; + +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * Awaiting Non-Web Spring Boot {@link ApplicationListener} + */ +final class DaprServerListener implements SmartApplicationListener { + + private static final Integer UNDEFINED_ID = -1; + private static final String[] WEB_APPLICATION_CONTEXT_CLASSES = new String[]{"org.springframework.web.context.WebApplicationContext", "org.springframework.boot.web.reactive.context.ReactiveWebApplicationContext"}; + private static final List> SUPPORTED_APPLICATION_EVENTS = Arrays.asList(ApplicationReadyEvent.class, ContextClosedEvent.class); + + /** + * Target the application id + */ + private final AtomicInteger applicationContextId = new AtomicInteger(UNDEFINED_ID); + + @Override + public int getOrder() { + return LOWEST_PRECEDENCE; + } + + @Override + public boolean supportsEventType(Class eventType) { + return SUPPORTED_APPLICATION_EVENTS.contains(eventType); + } + + @Override + public boolean supportsSourceType(Class sourceType) { + return true; + } + + @Override + public void onApplicationEvent(ApplicationEvent event) { + if (event instanceof ApplicationReadyEvent) { + onApplicationReadyEvent((ApplicationReadyEvent) event); + } + } + + private void onApplicationReadyEvent(ApplicationReadyEvent event) { + + final ConfigurableApplicationContext applicationContext = event.getApplicationContext(); + if (!isRootApplicationContext(applicationContext) || isWebApplicationContext(applicationContext)) { + return; + } + + if (applicationContextId.compareAndSet(UNDEFINED_ID, applicationContext.hashCode())) { + final CountDownLatch signal = new CountDownLatch(1); + Runnable guard = () -> { + try { + signal.await(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + }; + new Thread(guard).start(); + Runtime.getRuntime().addShutdownHook(new Thread(signal::countDown)); + } + } + + private boolean isRootApplicationContext(ApplicationContext applicationContext) { + return applicationContext.getParent() == null; + } + + private boolean isWebApplicationContext(ApplicationContext applicationContext) { + boolean webApplication = false; + for (String contextClass : WEB_APPLICATION_CONTEXT_CLASSES) { + if (isAssignable(contextClass, applicationContext.getClass(), applicationContext.getClassLoader())) { + webApplication = true; + break; + } + } + return webApplication; + } + + private static boolean isAssignable(String target, Class type, ClassLoader classLoader) { + try { + return ClassUtils.resolveClassName(target, classLoader).isAssignableFrom(type); + } catch (Throwable ex) { + return false; + } + } +} diff --git a/sdk-springboot3/src/main/java/io/openkunlun/javadsl/springboot3/server/DaprServerProperties.java b/sdk-springboot3/src/main/java/io/openkunlun/javadsl/springboot3/server/DaprServerProperties.java new file mode 100644 index 0000000000000000000000000000000000000000..72e279711626c81df431a9e3c97b0b90cf18e844 --- /dev/null +++ b/sdk-springboot3/src/main/java/io/openkunlun/javadsl/springboot3/server/DaprServerProperties.java @@ -0,0 +1,74 @@ +package io.openkunlun.javadsl.springboot3.server; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; + +import java.net.InetAddress; +import java.util.UUID; + +@Data +@ConfigurationProperties(prefix = "dapr.server") +public class DaprServerProperties { + + public static final String DEFAULT_HOST = ""; + public static final int DEFAULT_PORT = 9000; + public static final int DEFAULT_TTL = 15; + public static final int DEFAULT_WEIGHT = 100; + public static final int DEFAULT_WARMUP = 15_000; + + private String id; + private String host = DEFAULT_HOST; + private int port = DEFAULT_PORT; + private int ttl = DEFAULT_TTL; + private int weight = DEFAULT_WEIGHT; + private int warmup = DEFAULT_WARMUP; + + public String getId() { + if (null == id || id.isEmpty()) { + id = UUID.randomUUID().toString().replace("-", ""); + } + return id; + } + + public String getHost() { + try { + if ("".equals(host)) { + return InetAddress.getLocalHost().getHostAddress(); + } + + if ("".equals(host)) { + return InetAddress.getLocalHost().getHostName(); + } + + return host; + } catch (Exception e) { + return host; + } + } + + public DaprServerProperties setHost(String host) { + this.host = host; + return this; + } + + public int getTtl() { + if (ttl <= 0) { + ttl = DEFAULT_TTL; + } + return ttl; + } + + public int getWeight() { + if (weight <= 0) { + weight = DEFAULT_WEIGHT; + } + return weight; + } + + public int getWarmup() { + if (warmup <= 0) { + warmup = DEFAULT_WARMUP; + } + return warmup; + } +} diff --git a/sdk-springboot3/src/main/resources/application.yml b/sdk-springboot3/src/main/resources/application.yml new file mode 100644 index 0000000000000000000000000000000000000000..d14b08afaefd5ab76063a8ee90b3ae6fc8960d10 --- /dev/null +++ b/sdk-springboot3/src/main/resources/application.yml @@ -0,0 +1,4 @@ +dapr: + server: + host: 172.16.1.113 + port: 50051 \ No newline at end of file