diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..40a6a7e --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +/target +/.settings +/.project +/.classpath diff --git a/README.md b/README.md new file mode 100644 index 0000000..125794c --- /dev/null +++ b/README.md @@ -0,0 +1,98 @@ +spring-boot-starter-dubbo +=================================== + +[中文版文档](https://github.com/alibaba/spring-boot-starter-dubbo/blob/master/README_zh.md) + +Spring Boot with dubbo support. Dubbo is an RPC framework. + +Support jdk version 1.6 or 1.6+ + +(please import googlestyle-java.xml if you want to modify the code) + +### How to publish dubbo + +* add Dependencies: + +```xml + + com.alibaba + spring-boot-starter-dubbo + 1.0.0-SNAPSHOT + +``` +* add dubbo configuration in application.properties, demo: + +```properties +spring.dubbo.appname=spring-boot-starter-dubbo-provider-test +spring.dubbo.registry=multicast://224.0.0.0:1111 +spring.dubbo.protocol=dubbo +``` + +* then add `@EnableDubboConfiguration` on Spring Boot Application, indicates that dubbo is enabled.(web or non-web application can use dubbo provider) + +```java +@SpringBootApplication +@EnableDubboConfiguration +public class DubboProviderLauncher { + //... +} +``` + +* code your dubbo service, add `@Service`(import com.alibaba.dubbo.config.annotation.Service) on your service class, and interfaceClass is the interface which will be published. + +```java +@Service(interfaceClass = IHelloService.class) +public class HelloServiceImpl implements IHelloService { + //... +} +``` + +* start Spring Boot. + + +### How to consume Dubbo + +* add Dependencies: + +```xml + + com.alibaba + spring-boot-starter-dubbo + 1.0.0-SNAPSHOT + +``` + +* add dubbo configuration in application.properties, demo: + +```properties +spring.dubbo.appname=spring-boot-starter-dubbo-consumer-test +spring.dubbo.registry=multicast://224.0.0.0:1111 +spring.dubbo.protocol=dubbo +``` + +* then add `@EnableDubboConfiguration` on Spring Boot Application + +```java +@SpringBootApplication +@EnableDubboConfiguration +public class DubboConsumerLauncher { + //... +} +``` + +* injection interface by the `@DubboConsumer` annotation. + +```java +@Component +public class HelloConsumer { + @DubboConsumer + private IHelloService iHelloService; + +} +``` + +### Reference + +* dubbo: http://dubbo.io/ +* spring-boot: http://projects.spring.io/spring-boot/ +* spring-boot-starter-dubbo: https://github.com/linux-china/spring-boot-dubbo diff --git a/README_zh.md b/README_zh.md new file mode 100644 index 0000000..b608e5a --- /dev/null +++ b/README_zh.md @@ -0,0 +1,98 @@ +spring-boot-starter-dubbo +=================================== + +[English](https://github.com/alibaba/spring-boot-starter-dubbo/blob/master/README.md) + +Spring Boot with dubbo support. dubbo是一个RPC框架。 + +支持jdk版本为1.6或者1.6+ + +(在修改源码前,请导入googlestyle-java.xml以保证一致的代码格式) + +### 如何发布dubbo服务 + +* 添加依赖: + +```xml + + com.alibaba + spring-boot-starter-dubbo + 1.0.0-SNAPSHOT + +``` + +* 在application.properties添加dubbo的相关配置信息,样例配置如下: + +```properties +spring.dubbo.appname=spring-boot-starter-dubbo-provider-test +spring.dubbo.registry=multicast://224.0.0.0:1111 +spring.dubbo.protocol=dubbo +``` + +* 接下来在Spring Boot Application的上添加`@EnableDubboConfiguration`, 表示要开启dubbo功能. (dubbo provider服务可以使用或者不使用web容器) + +```java +@SpringBootApplication +@EnableDubboConfiguration +public class DubboProviderLauncher { + //... +} +``` + +* 编写你的dubbo服务,只需要添加要发布的服务实现上添加`@Service`(import com.alibaba.dubbo.config.annotation.Service)注解 ,其中interfaceClass是要发布服务的接口. + +```java +@Service(interfaceClass = IHelloService.class) +public class HelloServiceImpl implements IHelloService { + //... +} +``` + +* 启动你的Spring Boot应用,观察控制台,可以看到dubbo启动相关信息. + + +### 如何消费Dubbo服务 + +* 添加依赖: + +```xml + + com.alibaba + spring-boot-starter-dubbo + 1.0.0-SNAPSHOT + +``` + +* 在application.properties添加dubbo的相关配置信息,样例配置如下: + +```properties +spring.dubbo.appname=spring-boot-starter-dubbo-consumer-test +spring.dubbo.registry=multicast://224.0.0.0:1111 +spring.dubbo.protocol=dubbo +``` + +* 开启`@EnableDubboConfiguration` + +```java +@SpringBootApplication +@EnableDubboConfiguration +public class DubboConsumerLauncher { + //... +} +``` + +* 通过`@DubboConsumer`注入需要使用的interface. + +```java +@Component +public class HelloConsumer { + @DubboConsumer + private IHelloService iHelloService; +} +``` + +### 参考文档 + +* dubbo 介绍: http://dubbo.io/ +* spring-boot 介绍: http://projects.spring.io/spring-boot/ +* spring-boot-starter-dubbo 参考: https://github.com/linux-china/spring-boot-dubbo diff --git a/googlestyle-java.xml b/googlestyle-java.xml new file mode 100644 index 0000000..bf0ba90 --- /dev/null +++ b/googlestyle-java.xml @@ -0,0 +1,291 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..b00835c --- /dev/null +++ b/pom.xml @@ -0,0 +1,105 @@ + + 4.0.0 + + com.alibaba + spring-boot-starter-dubbo + 1.0.0-SNAPSHOT + jar + + spring-boot-starter-dubbo + https://github.com/xionghuiCoder/spring-boot-starter-dubbo + + + UTF-8 + 1.6 + 2.5.3 + 1.3.5.RELEASE + + + + + com.alibaba + dubbo + ${dubbo.version} + + + org.springframework + spring + + + + + org.springframework.boot + spring-boot-starter-actuator + + + org.springframework.boot + spring-boot-starter-web + true + + + org.springframework.boot + spring-boot-starter + true + + + junit + junit + test + + + + + + + org.springframework.boot + spring-boot-dependencies + ${spring-boot-dependencies.version} + pom + import + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.3 + + ${project.build.sourceEncoding} + ${java.version} + ${java.version} + true + + + + + + + scm:git:git@github.com:xionghuiCoder/spring-boot-starter-dubbo.git + scm:git:git@github.com:xionghuiCoder/spring-boot-starter-dubbo.git + https://github.com/xionghuiCoder/spring-boot-starter-dubbo + + + + + jackxiong + 熊辉 + xionghui.xh@alibaba-inc.com + + developer + + + + Tom + 孙忠英 + zhongying.sun@alibaba-inc.com + + developer + + + + diff --git a/src/main/java/com/alibaba/boot/dubbo/DubboAutoConfiguration.java b/src/main/java/com/alibaba/boot/dubbo/DubboAutoConfiguration.java new file mode 100644 index 0000000..0fec854 --- /dev/null +++ b/src/main/java/com/alibaba/boot/dubbo/DubboAutoConfiguration.java @@ -0,0 +1,77 @@ +package com.alibaba.boot.dubbo; + +import org.springframework.beans.factory.annotation.Autowired; +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 com.alibaba.boot.dubbo.endpoint.DubboEndpoint; +import com.alibaba.boot.dubbo.endpoint.DubboOperationEndpoint; +import com.alibaba.boot.dubbo.health.DubboHealthIndicator; +import com.alibaba.boot.dubbo.metrics.DubboMetrics; +import com.alibaba.dubbo.config.ApplicationConfig; +import com.alibaba.dubbo.config.ProtocolConfig; +import com.alibaba.dubbo.config.RegistryConfig; + +/** + * Dubbo common configuration + * + * @author xionghui + * @email xionghui.xh@alibaba-inc.com + * @since 1.0.0 + */ +@Configuration +@EnableConfigurationProperties(DubboProperties.class) +public class DubboAutoConfiguration { + @Autowired + private DubboProperties properties; + + @Bean + @ConditionalOnMissingBean + public ApplicationConfig dubboApplicationConfig() { + ApplicationConfig appConfig = new ApplicationConfig(); + appConfig.setName(this.properties.getAppname()); + return appConfig; + } + + @Bean + @ConditionalOnMissingBean + public ProtocolConfig dubboProtocolConfig() { + ProtocolConfig protocolConfig = new ProtocolConfig(); + protocolConfig.setName(this.properties.getProtocol()); + protocolConfig.setPort(this.properties.getPort()); + protocolConfig.setThreads(this.properties.getThreads()); + return protocolConfig; + } + + @Bean + @ConditionalOnMissingBean + public RegistryConfig dubboRegistryConfig() { + RegistryConfig registryConfig = new RegistryConfig(); + registryConfig.setAddress(this.properties.getRegistry()); + return registryConfig; + } + + @Bean + public DubboHealthIndicator dubboHealthIndicator() { + return new DubboHealthIndicator(); + } + + @Bean + public DubboEndpoint dubboEndpoint() { + return new DubboEndpoint(); + } + + @Bean + public DubboMetrics dubboConsumerMetrics() { + return new DubboMetrics(); + } + + + @Bean + public DubboOperationEndpoint dubboOperationEndpoint() { + return new DubboOperationEndpoint(); + } + +} diff --git a/src/main/java/com/alibaba/boot/dubbo/DubboConsumerAutoConfiguration.java b/src/main/java/com/alibaba/boot/dubbo/DubboConsumerAutoConfiguration.java new file mode 100644 index 0000000..86d467f --- /dev/null +++ b/src/main/java/com/alibaba/boot/dubbo/DubboConsumerAutoConfiguration.java @@ -0,0 +1,179 @@ +package com.alibaba.boot.dubbo; + +import java.lang.reflect.Field; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.BeanCreationException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.config.BeanPostProcessor; +import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +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 com.alibaba.boot.dubbo.annotation.DubboConsumer; +import com.alibaba.boot.dubbo.annotation.EnableDubboConfiguration; +import com.alibaba.boot.dubbo.domain.ClassIdBean; +import com.alibaba.dubbo.config.ApplicationConfig; +import com.alibaba.dubbo.config.RegistryConfig; +import com.alibaba.dubbo.config.annotation.Service; +import com.alibaba.dubbo.config.spring.ReferenceBean; + +/** + * DubboConsumerAutoConfiguration, use {@link Service#version} and {@link Service#timeout} + * properties. + * + * @author xionghui + * @email xionghui.xh@alibaba-inc.com + * @since 1.0.0 + */ +@Configuration +@ConditionalOnClass(Service.class) +@ConditionalOnBean(annotation = EnableDubboConfiguration.class) +@AutoConfigureAfter(DubboAutoConfiguration.class) +@EnableConfigurationProperties(DubboProperties.class) +public class DubboConsumerAutoConfiguration { + public static final Map DUBBO_REFERENCES_MAP = + new ConcurrentHashMap(); + + @Autowired + private ApplicationContext applicationContext; + + @Autowired + private DubboProperties properties; + + @Autowired + private ApplicationConfig applicationConfig; + @Autowired + private RegistryConfig registryConfig; + + @Bean + public BeanPostProcessor beanPostProcessor() { + return new BeanPostProcessor() { + @Override + public Object postProcessBeforeInitialization(Object bean, String beanName) + throws BeansException { + Class objClz = bean.getClass(); + if (org.springframework.aop.support.AopUtils.isAopProxy(bean)) { + objClz = org.springframework.aop.support.AopUtils.getTargetClass(bean); + } + + try { + for (Field field : objClz.getDeclaredFields()) { + DubboConsumer dubboConsumer = field.getAnnotation(DubboConsumer.class); + if (dubboConsumer != null) { + Class type = field.getType(); + ReferenceBean consumerBean = + DubboConsumerAutoConfiguration.this.getConsumerBean(type, dubboConsumer); + String group = consumerBean.getGroup(); + String version = consumerBean.getVersion(); + ClassIdBean classIdBean = new ClassIdBean(type, group, version); + Object dubboReference = + DubboConsumerAutoConfiguration.DUBBO_REFERENCES_MAP.get(classIdBean); + if (dubboReference == null) { + synchronized (this) { + // double check + dubboReference = + DubboConsumerAutoConfiguration.DUBBO_REFERENCES_MAP.get(classIdBean); + if (dubboReference == null) { + consumerBean.setApplicationContext( + DubboConsumerAutoConfiguration.this.applicationContext); + consumerBean + .setApplication(DubboConsumerAutoConfiguration.this.applicationConfig); + RegistryConfig registry = consumerBean.getRegistry(); + if (registry == null) { + consumerBean.setRegistry(DubboConsumerAutoConfiguration.this.registryConfig); + } + consumerBean + .setApplication(DubboConsumerAutoConfiguration.this.applicationConfig); + consumerBean.afterPropertiesSet(); + // 理论上dubboReference不能为空,否则就会抛NullPointerException了 + dubboReference = consumerBean.getObject(); + DubboConsumerAutoConfiguration.DUBBO_REFERENCES_MAP.put(classIdBean, + dubboReference); + } + } + } + field.setAccessible(true); + field.set(bean, dubboReference); + field.setAccessible(false); + } + } + } catch (Exception e) { + throw new BeanCreationException(beanName, e); + } + return bean; + } + + @Override + public Object postProcessAfterInitialization(Object bean, String beanName) + throws BeansException { + return bean; + } + }; + } + + /** + * 设置相关配置信息, @see DubboConsumer + * + * @param interfaceClazz + * @param dubboConsumer + * @return + * @throws BeansException + */ + private ReferenceBean getConsumerBean(Class interfaceClazz, DubboConsumer dubboConsumer) + throws BeansException { + ReferenceBean consumerBean = new ReferenceBean(); + consumerBean.setInterface(interfaceClazz); + String canonicalName = interfaceClazz.getCanonicalName(); + consumerBean.setId(canonicalName); + String registry = dubboConsumer.registry(); + if (registry != null && registry.length() > 0) { + RegistryConfig registryConfig = new RegistryConfig(); + registryConfig.setAddress(registry); + consumerBean.setRegistry(registryConfig); + } + String group = dubboConsumer.group(); + if (group == null || "".equals(group)) { + group = this.properties.getGroup(); + } + if (group != null && !"".equals(group)) { + consumerBean.setGroup(group); + } + String version = dubboConsumer.version(); + if (version == null || "".equals(version)) { + version = this.properties.getVersion(); + } + if (version != null && !"".equals(version)) { + consumerBean.setVersion(version); + } + int timeout = dubboConsumer.timeout(); + consumerBean.setTimeout(timeout); + String client = dubboConsumer.client(); + consumerBean.setClient(client); + String url = dubboConsumer.url(); + consumerBean.setUrl(url); + String protocol = dubboConsumer.protocol(); + consumerBean.setProtocol(protocol); + boolean check = dubboConsumer.check(); + consumerBean.setCheck(check); + boolean lazy = dubboConsumer.lazy(); + consumerBean.setLazy(lazy); + int retries = dubboConsumer.retries(); + consumerBean.setRetries(retries); + int actives = dubboConsumer.actives(); + consumerBean.setActives(actives); + String loadbalance = dubboConsumer.loadbalance(); + consumerBean.setLoadbalance(loadbalance); + boolean async = dubboConsumer.async(); + consumerBean.setAsync(async); + boolean sent = dubboConsumer.sent(); + consumerBean.setSent(sent); + return consumerBean; + } +} diff --git a/src/main/java/com/alibaba/boot/dubbo/DubboProperties.java b/src/main/java/com/alibaba/boot/dubbo/DubboProperties.java new file mode 100644 index 0000000..f3533d2 --- /dev/null +++ b/src/main/java/com/alibaba/boot/dubbo/DubboProperties.java @@ -0,0 +1,107 @@ +package com.alibaba.boot.dubbo; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * dubbo properties + * + * @author xionghui + * @email xionghui.xh@alibaba-inc.com + * @since 1.0.0 + */ +@ConfigurationProperties(prefix = "spring.dubbo") +public class DubboProperties { + /** + * dubbo application name + */ + private String appname; + /** + * dubbo registry address + */ + private String registry; + /** + * communication protocol, default is dubbo + */ + private String protocol = "dubbo"; + /** + * dubbo listen port, default 20800 + */ + private int port = 20800; + /** + * dubbo thread count, default 200 + */ + private int threads = 200; + + /** + * dubbo version, may override by {@link com.alibaba.dubbo.config.annotation.Service#version()} + */ + private String version = ""; + + /** + * dubbo group, may override by {@link com.alibaba.dubbo.config.annotation.Service#group()} + */ + private String group = ""; + + public String getAppname() { + return this.appname; + } + + public void setAppname(String appname) { + this.appname = appname; + } + + public String getRegistry() { + return this.registry; + } + + public void setRegistry(String registry) { + this.registry = registry; + } + + public String getProtocol() { + return this.protocol; + } + + public void setProtocol(String protocol) { + this.protocol = protocol; + } + + public int getPort() { + return this.port; + } + + public void setPort(int port) { + this.port = port; + } + + public int getThreads() { + return this.threads; + } + + public void setThreads(int threads) { + this.threads = threads; + } + + public String getVersion() { + return this.version; + } + + public void setVersion(String version) { + this.version = version; + } + + public String getGroup() { + return this.group; + } + + public void setGroup(String group) { + this.group = group; + } + + @Override + public String toString() { + return "DubboProperties [appname=" + this.appname + ", registry=" + this.registry + + ", protocol=" + this.protocol + ", port=" + this.port + ", threads=" + this.threads + + ", version=" + this.version + ", group=" + this.group + "]"; + } +} diff --git a/src/main/java/com/alibaba/boot/dubbo/DubboProviderAutoConfiguration.java b/src/main/java/com/alibaba/boot/dubbo/DubboProviderAutoConfiguration.java new file mode 100644 index 0000000..30271fb --- /dev/null +++ b/src/main/java/com/alibaba/boot/dubbo/DubboProviderAutoConfiguration.java @@ -0,0 +1,92 @@ +package com.alibaba.boot.dubbo; + +import java.util.Map; + +import javax.annotation.PostConstruct; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Configuration; + +import com.alibaba.boot.dubbo.annotation.EnableDubboConfiguration; +import com.alibaba.dubbo.config.ApplicationConfig; +import com.alibaba.dubbo.config.ProtocolConfig; +import com.alibaba.dubbo.config.RegistryConfig; +import com.alibaba.dubbo.config.annotation.Service; +import com.alibaba.dubbo.config.spring.ServiceBean; + +/** + * DubboProviderAutoConfiguration + * + * @author xionghui + * @email xionghui.xh@alibaba-inc.com + * @since 1.0.0 + */ +@Configuration +@ConditionalOnClass(Service.class) +@ConditionalOnBean(annotation = EnableDubboConfiguration.class) +@AutoConfigureAfter(DubboAutoConfiguration.class) +@EnableConfigurationProperties(DubboProperties.class) +public class DubboProviderAutoConfiguration { + @Autowired + private ApplicationContext applicationContext; + + @Autowired + private DubboProperties properties; + + @Autowired + private ApplicationConfig applicationConfig; + + @Autowired + private ProtocolConfig protocolConfig; + @Autowired + private RegistryConfig registryConfig; + + @PostConstruct + public void init() throws Exception { + Map beans = this.applicationContext.getBeansWithAnnotation(Service.class); + for (Map.Entry entry : beans.entrySet()) { + this.initProviderBean(entry.getKey(), entry.getValue()); + } + } + + public void initProviderBean(String beanName, Object bean) throws Exception { + Service service = this.applicationContext.findAnnotationOnBean(beanName, Service.class); + ServiceBean serviceConfig = new ServiceBean(service); + if (void.class.equals(service.interfaceClass()) && "".equals(service.interfaceName())) { + if (bean.getClass().getInterfaces().length > 0) { + serviceConfig.setInterface(bean.getClass().getInterfaces()[0]); + } else { + throw new IllegalStateException("Failed to export remote service class " + + bean.getClass().getName() + + ", cause: The @Service undefined interfaceClass or interfaceName, and the service class unimplemented any interfaces."); + } + } + String version = service.version(); + if (version == null || "".equals(version)) { + version = this.properties.getVersion(); + } + if (version != null && !"".equals(version)) { + serviceConfig.setVersion(version); + } + String group = service.group(); + if (group == null || "".equals(group)) { + group = this.properties.getGroup(); + } + if (group != null && !"".equals(group)) { + serviceConfig.setGroup(group); + } + serviceConfig.setApplicationContext(this.applicationContext); + serviceConfig.setApplication(this.applicationConfig); + serviceConfig.setProtocol(this.protocolConfig); + serviceConfig.setRegistry(this.registryConfig); + serviceConfig.afterPropertiesSet(); + serviceConfig.setRef(bean); + serviceConfig.export(); + } + +} diff --git a/src/main/java/com/alibaba/boot/dubbo/annotation/DubboConsumer.java b/src/main/java/com/alibaba/boot/dubbo/annotation/DubboConsumer.java new file mode 100644 index 0000000..c83df91 --- /dev/null +++ b/src/main/java/com/alibaba/boot/dubbo/annotation/DubboConsumer.java @@ -0,0 +1,61 @@ +package com.alibaba.boot.dubbo.annotation; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * dubbo consumer + * + * @author xionghui + * @email xionghui.xh@alibaba-inc.com + * @since 1.0.0 + */ +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface DubboConsumer { + + // 版本 + String version() default ""; + + // 远程调用超时时间(毫秒) + int timeout() default 0; + + // 注册中心 + String registry() default ""; + + // 服务分组 + String group() default ""; + + // 客户端类型 + String client() default ""; + + // 点对点直连服务提供地址 + String url() default ""; + + String protocol() default ""; + + // 检查服务提供者是否存在 + boolean check() default true; + + // lazy create connection + boolean lazy() default false; + + // 重试次数 + int retries() default 0; + + // 最大并发调用 + int actives() default 0; + + // 负载均衡 + String loadbalance() default ""; + + // 是否异步 + boolean async() default false; + + // 异步发送是否等待发送成功 + boolean sent() default false; +} diff --git a/src/main/java/com/alibaba/boot/dubbo/annotation/EnableDubboConfiguration.java b/src/main/java/com/alibaba/boot/dubbo/annotation/EnableDubboConfiguration.java new file mode 100644 index 0000000..1959f27 --- /dev/null +++ b/src/main/java/com/alibaba/boot/dubbo/annotation/EnableDubboConfiguration.java @@ -0,0 +1,21 @@ +package com.alibaba.boot.dubbo.annotation; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Enable Dubbo (for provider or consumer) for spring boot application + * + * @author xionghui + * @email xionghui.xh@alibaba-inc.com + * @since 1.0.0 + */ +@Target({ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface EnableDubboConfiguration { + +} diff --git a/src/main/java/com/alibaba/boot/dubbo/domain/ClassIdBean.java b/src/main/java/com/alibaba/boot/dubbo/domain/ClassIdBean.java new file mode 100644 index 0000000..13038d6 --- /dev/null +++ b/src/main/java/com/alibaba/boot/dubbo/domain/ClassIdBean.java @@ -0,0 +1,82 @@ +package com.alibaba.boot.dubbo.domain; + +import java.io.Serializable; + +/** + * 标示唯一一个class + * + * @author xionghui + * @email xionghui.xh@alibaba-inc.com + * @since 1.0.0 + */ +public class ClassIdBean implements Serializable { + private static final long serialVersionUID = 3744915458507135546L; + + private Class clazz; + private String group; + private String version; + + public ClassIdBean(Class clazz, String group, String version) { + this.clazz = clazz; + this.group = group; + this.version = version; + } + + public Class getClazz() { + return this.clazz; + } + + public void setClazz(Class clazz) { + this.clazz = clazz; + } + + public String getGroup() { + return this.group; + } + + public void setGroup(String group) { + this.group = group; + } + + public String getVersion() { + return this.version; + } + + public void setVersion(String version) { + this.version = version; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof ClassIdBean)) { + return false; + } + ClassIdBean classIdBean = (ClassIdBean) obj; + if (this.clazz == null ? classIdBean.clazz != null : !this.clazz.equals(classIdBean.clazz)) { + return false; + } + if (this.group == null ? classIdBean.group != null : !this.group.equals(classIdBean.group)) { + return false; + } + return this.version == null ? classIdBean.version == null + : this.version.equals(classIdBean.version); + } + + @Override + public int hashCode() { + int hashCode = 17; + hashCode = 31 * hashCode + (this.clazz == null ? 0 : this.clazz.hashCode()); + hashCode = 31 * hashCode + (this.group == null ? 0 : this.group.hashCode()); + hashCode = 31 * hashCode + (this.version == null ? 0 : this.version.hashCode()); + return hashCode; + } + + @Override + public String toString() { + return "ClassIdBean [clazz=" + this.clazz + ", group=" + this.group + ", version=" + + this.version + "]"; + } +} diff --git a/src/main/java/com/alibaba/boot/dubbo/domain/SpringBootStarterDobboConstants.java b/src/main/java/com/alibaba/boot/dubbo/domain/SpringBootStarterDobboConstants.java new file mode 100644 index 0000000..71e0367 --- /dev/null +++ b/src/main/java/com/alibaba/boot/dubbo/domain/SpringBootStarterDobboConstants.java @@ -0,0 +1,16 @@ +package com.alibaba.boot.dubbo.domain; + +/** + * 常量定义 + * + * @author xionghui + * @email xionghui.xh@alibaba-inc.com + * @since 1.0.0 + */ +public class SpringBootStarterDobboConstants { + + public static final String GROUP = "group"; + + public static final String VERSION = "version"; + +} diff --git a/src/main/java/com/alibaba/boot/dubbo/endpoint/DubboEndpoint.java b/src/main/java/com/alibaba/boot/dubbo/endpoint/DubboEndpoint.java new file mode 100644 index 0000000..dc30b76 --- /dev/null +++ b/src/main/java/com/alibaba/boot/dubbo/endpoint/DubboEndpoint.java @@ -0,0 +1,145 @@ +package com.alibaba.boot.dubbo.endpoint; + +import java.lang.reflect.Method; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.actuate.endpoint.AbstractEndpoint; +import org.springframework.boot.actuate.metrics.Metric; +import org.springframework.stereotype.Component; + +import com.alibaba.boot.dubbo.DubboProperties; +import com.alibaba.boot.dubbo.domain.ClassIdBean; +import com.alibaba.boot.dubbo.listener.ConsumerSubscribeListener; +import com.alibaba.boot.dubbo.listener.ProviderExportListener; +import com.alibaba.boot.dubbo.listener.StaticsFilterHelper; +import com.alibaba.boot.dubbo.metrics.DubboMetrics; + +/** + * dubbo endpoint for provider and subscriber + * + * @author xionghui + * @email xionghui.xh@alibaba-inc.com + * @since 1.0.0 + */ +@Component +public class DubboEndpoint extends AbstractEndpoint> { + @Autowired + private DubboProperties dubboProperties; + + @Autowired + private DubboMetrics dubboMetrics; + + @Override + public Map invoke() { + Map result = new HashMap(); + result.put("endpoint", this.buildEndpoint()); + result.put("metrics", this.getMetrics()); + result.put("config", this.getConfig()); + result.put("runtime", this.getRuntime()); + return result; + } + + private Object buildEndpoint() { + Map result = new HashMap(); + result.put("name", this.getName()); + result.put("version", this.getVersion()); + result.put("authors", this.getAuthors()); + result.put("docs", this.getDocs()); + result.put("scm", this.getScm()); + return result; + } + + public DubboEndpoint() { + super("dubbo"); + } + + public String getName() { + return "dubbo"; + } + + public String getVersion() { + return "1.0.0"; + } + + public List getAuthors() { + return Collections.singletonList("jackxiong "); + } + + public String getDocs() { + return "http://dubbo.io/Developer+Guide-zh.htm"; + } + + public String getScm() { + return "git@github.com:xionghuiCoder/spring-boot-starter-dubbo.git"; + } + + public DubboProperties getConfig() { + return this.dubboProperties; + } + + public Map getRuntime() { + Map runtimeMap = new HashMap(); + + runtimeMap.put("appname", this.dubboProperties.getAppname()); + runtimeMap.put("registry", this.dubboProperties.getRegistry()); + runtimeMap.put("protocol", this.dubboProperties.getProtocol()); + runtimeMap.put("port", this.dubboProperties.getPort()); + runtimeMap.put("threads", this.dubboProperties.getThreads()); + + // published services + Map> publishedInterfaceList = + new HashMap>(); + Set publishedInterfaceSet = ProviderExportListener.EXPORTEDINTERFACES_SET; + for (ClassIdBean classIdBean : publishedInterfaceSet) { + Class clazz = classIdBean.getClazz(); + String interfaceClassCanonicalName = clazz.getCanonicalName(); + if (!interfaceClassCanonicalName.equals("void")) { + Map methodNames = new HashMap(); + for (Method method : clazz.getMethods()) { + methodNames.put(method.getName(), + StaticsFilterHelper.getValue(classIdBean, method.getName())); + } + publishedInterfaceList.put(classIdBean, methodNames); + } + } + if (!publishedInterfaceList.isEmpty()) { + runtimeMap.put("publishedInterfaces", publishedInterfaceList); + } + + // subscribed services + Set subscribedInterfaceSet = ConsumerSubscribeListener.SUBSCRIBEDINTERFACES_SET; + Map> subscribedInterfaceList = + new HashMap>(); + for (ClassIdBean classIdBean : subscribedInterfaceSet) { + Map methodNames = new HashMap(); + Class clazz = classIdBean.getClazz(); + for (Method method : clazz.getMethods()) { + methodNames.put(method.getName(), + StaticsFilterHelper.getValue(classIdBean, method.getName())); + } + subscribedInterfaceList.put(classIdBean, methodNames); + } + if (!subscribedInterfaceList.isEmpty()) { + runtimeMap.put("subscribedInterfaces", subscribedInterfaceList); + } + + // consumer connections + runtimeMap.put("connections", ConsumerSubscribeListener.CONNECTION_MAP); + return runtimeMap; + } + + public Map getMetrics() { + Map metricsMap = new HashMap(); + Collection> metrics = this.dubboMetrics.metrics(); + for (Metric metric : metrics) { + metricsMap.put(metric.getName(), metric.toString()); + } + return metricsMap; + } +} diff --git a/src/main/java/com/alibaba/boot/dubbo/endpoint/DubboOperationEndpoint.java b/src/main/java/com/alibaba/boot/dubbo/endpoint/DubboOperationEndpoint.java new file mode 100644 index 0000000..23d8671 --- /dev/null +++ b/src/main/java/com/alibaba/boot/dubbo/endpoint/DubboOperationEndpoint.java @@ -0,0 +1,93 @@ +package com.alibaba.boot.dubbo.endpoint; + +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.actuate.endpoint.Endpoint; +import org.springframework.boot.actuate.endpoint.mvc.MvcEndpoint; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.alibaba.boot.dubbo.DubboProperties; +import com.alibaba.boot.dubbo.listener.ProviderExportListener; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.extension.ExtensionLoader; +import com.alibaba.dubbo.registry.Registry; +import com.alibaba.dubbo.registry.RegistryFactory; + +/** + * dubbo operation endpoint + * + * @author xionghui + * @email xionghui.xh@alibaba-inc.com + * @since 1.0.0 + */ +@RestController +public class DubboOperationEndpoint implements MvcEndpoint { + @Autowired + private DubboProperties dubboProperties; + + private Registry registry; + + @RequestMapping("/online") + public List> online() { + List> serviceInterfaceList = new LinkedList>(); + if (!ProviderExportListener.EXPORTED_URL.isEmpty()) { + this.init(); + for (URL url : ProviderExportListener.EXPORTED_URL) { + this.registry.register(url); + Map map = url.toMap(); + serviceInterfaceList.add(map); + } + } + return serviceInterfaceList; + } + + @RequestMapping("/offline") + public List> offline() { + List> serviceInterfaceList = new LinkedList>(); + if (!ProviderExportListener.EXPORTED_URL.isEmpty()) { + this.init(); + for (URL url : ProviderExportListener.EXPORTED_URL) { + this.registry.unregister(url); + Map map = url.toMap(); + serviceInterfaceList.add(map); + } + } + return serviceInterfaceList; + } + + /** + * 初始化registry + */ + private void init() { + if (this.registry == null) { + synchronized (DubboOperationEndpoint.class) { + if (this.registry == null) { + ExtensionLoader extensionLoader = + ExtensionLoader.getExtensionLoader(RegistryFactory.class); + URL url = URL.valueOf(this.dubboProperties.getRegistry()); + RegistryFactory registryFactory = extensionLoader.getDefaultExtension(); + this.registry = registryFactory.getRegistry(url); + } + } + } + } + + @Override + public String getPath() { + return "dubbo"; + } + + @Override + public boolean isSensitive() { + return false; + } + + @Override + public Class> getEndpointType() { + return null; + } +} diff --git a/src/main/java/com/alibaba/boot/dubbo/health/DubboHealthIndicator.java b/src/main/java/com/alibaba/boot/dubbo/health/DubboHealthIndicator.java new file mode 100644 index 0000000..c49348c --- /dev/null +++ b/src/main/java/com/alibaba/boot/dubbo/health/DubboHealthIndicator.java @@ -0,0 +1,35 @@ +package com.alibaba.boot.dubbo.health; + +import org.springframework.boot.actuate.health.AbstractHealthIndicator; +import org.springframework.boot.actuate.health.Health; +import org.springframework.stereotype.Component; + +import com.alibaba.boot.dubbo.DubboConsumerAutoConfiguration; +import com.alibaba.boot.dubbo.domain.ClassIdBean; +import com.alibaba.boot.dubbo.listener.ConsumerSubscribeListener; +import com.alibaba.dubbo.rpc.service.EchoService; + +/** + * dubbo health indicator + * + * @author xionghui + * @email xionghui.xh@alibaba-inc.com + * @since 1.0.0 + */ +@Component +public class DubboHealthIndicator extends AbstractHealthIndicator { + + @Override + protected void doHealthCheck(Health.Builder builder) throws Exception { + for (ClassIdBean classIdBean : ConsumerSubscribeListener.SUBSCRIBEDINTERFACES_SET) { + Object service = DubboConsumerAutoConfiguration.DUBBO_REFERENCES_MAP.get(classIdBean); + EchoService echoService = (EchoService) service; + if (echoService != null) { + echoService.$echo("Hello"); + builder.withDetail(classIdBean.toString(), true); + } + } + builder.up(); + } + +} diff --git a/src/main/java/com/alibaba/boot/dubbo/listener/ConsumerInvokeStaticsFilter.java b/src/main/java/com/alibaba/boot/dubbo/listener/ConsumerInvokeStaticsFilter.java new file mode 100644 index 0000000..bfdaf80 --- /dev/null +++ b/src/main/java/com/alibaba/boot/dubbo/listener/ConsumerInvokeStaticsFilter.java @@ -0,0 +1,35 @@ +package com.alibaba.boot.dubbo.listener; + +import com.alibaba.boot.dubbo.domain.ClassIdBean; +import com.alibaba.boot.dubbo.domain.SpringBootStarterDobboConstants; +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.extension.Activate; +import com.alibaba.dubbo.rpc.Invocation; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.Result; +import com.alibaba.dubbo.rpc.RpcException; + +/** + * consumer invoke statics filter + * + * @author xionghui + * @email xionghui.xh@alibaba-inc.com + * @since 1.0.0 + */ +@Activate(group = Constants.CONSUMER) +public class ConsumerInvokeStaticsFilter extends StaticsFilterHelper { + + @Override + public Result invoke(Invoker invoker, Invocation invocation) throws RpcException { + Invoker invocationInvoker = invocation.getInvoker(); + Class anInterface = invocationInvoker.getInterface(); + URL url = invocationInvoker.getUrl(); + String group = url.getParameter(SpringBootStarterDobboConstants.GROUP); + String version = url.getParameter(SpringBootStarterDobboConstants.VERSION); + ClassIdBean classIdBean = new ClassIdBean(anInterface, group, version); + increase(classIdBean, invocation.getMethodName()); + return invoker.invoke(invocation); + } +} + diff --git a/src/main/java/com/alibaba/boot/dubbo/listener/ConsumerSubscribeListener.java b/src/main/java/com/alibaba/boot/dubbo/listener/ConsumerSubscribeListener.java new file mode 100644 index 0000000..eb874fb --- /dev/null +++ b/src/main/java/com/alibaba/boot/dubbo/listener/ConsumerSubscribeListener.java @@ -0,0 +1,65 @@ +package com.alibaba.boot.dubbo.listener; + +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +import com.alibaba.boot.dubbo.domain.ClassIdBean; +import com.alibaba.boot.dubbo.domain.SpringBootStarterDobboConstants; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.extension.Activate; +import com.alibaba.dubbo.common.utils.ConcurrentHashSet; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.RpcException; +import com.alibaba.dubbo.rpc.listener.InvokerListenerAdapter; + +/** + * dubbo client invoker listener + * + * @author xionghui + * @email xionghui.xh@alibaba-inc.com + * @since 1.0.0 + */ +@Activate +public class ConsumerSubscribeListener extends InvokerListenerAdapter { + // subscribe interfaces + public static final Set SUBSCRIBEDINTERFACES_SET = + new ConcurrentHashSet(); + + // connection interface name + public static final Map> CONNECTION_MAP = + new ConcurrentHashMap>(); + + @Override + public void referred(Invoker invoker) throws RpcException { + Class anInterface = invoker.getInterface(); + URL url = invoker.getUrl(); + String group = url.getParameter(SpringBootStarterDobboConstants.GROUP); + String version = url.getParameter(SpringBootStarterDobboConstants.VERSION); + ClassIdBean classIdBean = new ClassIdBean(anInterface, group, version); + SUBSCRIBEDINTERFACES_SET.add(classIdBean); + Set connectionSet = CONNECTION_MAP.get(classIdBean); + if (connectionSet == null) { + connectionSet = new ConcurrentHashSet(); + CONNECTION_MAP.put(classIdBean, connectionSet); + } + connectionSet.add(invoker.getUrl().toString()); + } + + @Override + public void destroyed(Invoker invoker) { + Class anInterface = invoker.getInterface(); + URL url = invoker.getUrl(); + String group = url.getParameter(SpringBootStarterDobboConstants.GROUP); + String version = url.getParameter(SpringBootStarterDobboConstants.VERSION); + ClassIdBean classIdBean = new ClassIdBean(anInterface, group, version); + SUBSCRIBEDINTERFACES_SET.remove(classIdBean); + Set connectionSet = CONNECTION_MAP.get(classIdBean); + if (connectionSet != null) { + connectionSet.remove(invoker.getUrl().toString()); + } + if (connectionSet == null || connectionSet.size() == 0) { + CONNECTION_MAP.remove(classIdBean); + } + } +} diff --git a/src/main/java/com/alibaba/boot/dubbo/listener/ProviderExportListener.java b/src/main/java/com/alibaba/boot/dubbo/listener/ProviderExportListener.java new file mode 100644 index 0000000..8e6eaca --- /dev/null +++ b/src/main/java/com/alibaba/boot/dubbo/listener/ProviderExportListener.java @@ -0,0 +1,58 @@ +package com.alibaba.boot.dubbo.listener; + +import java.util.Set; + +import com.alibaba.boot.dubbo.domain.ClassIdBean; +import com.alibaba.boot.dubbo.domain.SpringBootStarterDobboConstants; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.extension.Activate; +import com.alibaba.dubbo.common.utils.ConcurrentHashSet; +import com.alibaba.dubbo.rpc.Exporter; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.RpcException; +import com.alibaba.dubbo.rpc.listener.ExporterListenerAdapter; + +/** + * provider export listener + * + * @author xionghui + * @email xionghui.xh@alibaba-inc.com + * @since 1.0.0 + */ +@Activate +public class ProviderExportListener extends ExporterListenerAdapter { + // exported interfaces + public static final Set EXPORTEDINTERFACES_SET = + new ConcurrentHashSet(); + + // exported urls + public static final Set EXPORTED_URL = new ConcurrentHashSet(); + + @Override + public void exported(Exporter exporter) throws RpcException { + Invoker invoker = exporter.getInvoker(); + Class anInterface = invoker.getInterface(); + URL url = invoker.getUrl(); + String group = url.getParameter(SpringBootStarterDobboConstants.GROUP); + String version = url.getParameter(SpringBootStarterDobboConstants.VERSION); + ClassIdBean classIdBean = new ClassIdBean(anInterface, group, version); + EXPORTEDINTERFACES_SET.add(classIdBean); + if (!url.getProtocol().equals("injvm")) { + EXPORTED_URL.add(url); + } + } + + @Override + public void unexported(Exporter exporter) { + Invoker invoker = exporter.getInvoker(); + Class anInterface = invoker.getInterface(); + URL url = invoker.getUrl(); + String group = url.getParameter(SpringBootStarterDobboConstants.GROUP); + String version = url.getParameter(SpringBootStarterDobboConstants.VERSION); + ClassIdBean classIdBean = new ClassIdBean(anInterface, group, version); + EXPORTEDINTERFACES_SET.remove(classIdBean); + if (!url.getProtocol().equals("injvm")) { + EXPORTED_URL.remove(url); + } + } +} diff --git a/src/main/java/com/alibaba/boot/dubbo/listener/ProviderInvokeStaticsFilter.java b/src/main/java/com/alibaba/boot/dubbo/listener/ProviderInvokeStaticsFilter.java new file mode 100644 index 0000000..def4151 --- /dev/null +++ b/src/main/java/com/alibaba/boot/dubbo/listener/ProviderInvokeStaticsFilter.java @@ -0,0 +1,33 @@ +package com.alibaba.boot.dubbo.listener; + +import com.alibaba.boot.dubbo.domain.ClassIdBean; +import com.alibaba.boot.dubbo.domain.SpringBootStarterDobboConstants; +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.extension.Activate; +import com.alibaba.dubbo.rpc.Invocation; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.Result; +import com.alibaba.dubbo.rpc.RpcException; + +/** + * provider invoke statics filter + * + * @author xionghui + * @email xionghui.xh@alibaba-inc.com + * @since 1.0.0 + */ +@Activate(group = Constants.PROVIDER) +public class ProviderInvokeStaticsFilter extends StaticsFilterHelper { + + @Override + public Result invoke(Invoker invoker, Invocation invocation) throws RpcException { + Class anInterface = invoker.getInterface(); + URL url = invoker.getUrl(); + String group = url.getParameter(SpringBootStarterDobboConstants.GROUP); + String version = url.getParameter(SpringBootStarterDobboConstants.VERSION); + ClassIdBean classIdBean = new ClassIdBean(anInterface, group, version); + increase(classIdBean, invocation.getMethodName()); + return invoker.invoke(invocation); + } +} diff --git a/src/main/java/com/alibaba/boot/dubbo/listener/StaticsFilterHelper.java b/src/main/java/com/alibaba/boot/dubbo/listener/StaticsFilterHelper.java new file mode 100644 index 0000000..9b8461a --- /dev/null +++ b/src/main/java/com/alibaba/boot/dubbo/listener/StaticsFilterHelper.java @@ -0,0 +1,56 @@ +package com.alibaba.boot.dubbo.listener; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicLong; + +import com.alibaba.boot.dubbo.domain.ClassIdBean; +import com.alibaba.dubbo.rpc.Filter; + +/** + * statics filter + * + * @author xionghui + * @email xionghui.xh@alibaba-inc.com + * @since 1.0.0 + */ +public abstract class StaticsFilterHelper implements Filter { + public static final Map> STATICS_DATA_MAP = + new ConcurrentHashMap>(); + + public static void increase(ClassIdBean classIdBean, String methodName) { + Map methodCountMap = STATICS_DATA_MAP.get(classIdBean); + if (methodCountMap == null) { + synchronized (StaticsFilterHelper.class) { + // double check + methodCountMap = STATICS_DATA_MAP.get(classIdBean); + if (methodCountMap == null) { + methodCountMap = new ConcurrentHashMap(); + STATICS_DATA_MAP.put(classIdBean, methodCountMap); + } + } + } + AtomicLong count = methodCountMap.get(methodName); + if (count == null) { + synchronized (StaticsFilterHelper.class) { + // double check + count = methodCountMap.get(methodName); + if (count == null) { + count = new AtomicLong(0); + methodCountMap.put(methodName, count); + } + } + } + count.incrementAndGet(); + } + + public static long getValue(ClassIdBean classIdBean, String methodName) { + Map methodCountMap = STATICS_DATA_MAP.get(classIdBean); + if (methodCountMap == null) { + return 0; + } + AtomicLong count = methodCountMap.get(methodName); + return count == null ? 0 : count.get(); + } +} + diff --git a/src/main/java/com/alibaba/boot/dubbo/metrics/DubboMetrics.java b/src/main/java/com/alibaba/boot/dubbo/metrics/DubboMetrics.java new file mode 100644 index 0000000..4d4d74f --- /dev/null +++ b/src/main/java/com/alibaba/boot/dubbo/metrics/DubboMetrics.java @@ -0,0 +1,49 @@ +package com.alibaba.boot.dubbo.metrics; + +import java.util.Collection; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.atomic.AtomicLong; + +import org.springframework.boot.actuate.endpoint.PublicMetrics; +import org.springframework.boot.actuate.metrics.Metric; +import org.springframework.stereotype.Component; + +import com.alibaba.boot.dubbo.domain.ClassIdBean; +import com.alibaba.boot.dubbo.listener.StaticsFilterHelper; + +/** + * dubbo metrics + * + * @author xionghui + * @email xionghui.xh@alibaba-inc.com + * @since 1.0.0 + */ +@Component +public class DubboMetrics implements PublicMetrics { + + @Override + public Collection> metrics() { + List> metrics = new LinkedList>(); + for (Map.Entry> entry : StaticsFilterHelper.STATICS_DATA_MAP + .entrySet()) { + ClassIdBean classIdBean = entry.getKey(); + Map countMap = entry.getValue(); + for (Map.Entry entry1 : countMap.entrySet()) { + metrics.add(new Metric("dubbo." + classIdBean + "." + entry1.getKey(), + entry1.getValue().get())); + } + } + for (Map.Entry> entry : StaticsFilterHelper.STATICS_DATA_MAP + .entrySet()) { + ClassIdBean classIdBean = entry.getKey(); + Map countMap = entry.getValue(); + for (Map.Entry entry1 : countMap.entrySet()) { + metrics.add(new Metric("dubbo." + classIdBean + "." + entry1.getKey(), + entry1.getValue().get())); + } + } + return metrics; + } +} diff --git a/src/main/resources/META-INF/dubbo/com.alibaba.dubbo.rpc.ExporterListener b/src/main/resources/META-INF/dubbo/com.alibaba.dubbo.rpc.ExporterListener new file mode 100644 index 0000000..c047928 --- /dev/null +++ b/src/main/resources/META-INF/dubbo/com.alibaba.dubbo.rpc.ExporterListener @@ -0,0 +1 @@ +dubboexport=com.alibaba.boot.dubbo.listener.ProviderExportListener \ No newline at end of file diff --git a/src/main/resources/META-INF/dubbo/com.alibaba.dubbo.rpc.Filter b/src/main/resources/META-INF/dubbo/com.alibaba.dubbo.rpc.Filter new file mode 100644 index 0000000..8842aee --- /dev/null +++ b/src/main/resources/META-INF/dubbo/com.alibaba.dubbo.rpc.Filter @@ -0,0 +1,2 @@ +dubboconsumerstatics=com.alibaba.boot.dubbo.listener.ConsumerInvokeStaticsFilter +dubboproviderstatics=com.alibaba.boot.dubbo.listener.ProviderInvokeStaticsFilter \ No newline at end of file diff --git a/src/main/resources/META-INF/dubbo/com.alibaba.dubbo.rpc.InvokerListener b/src/main/resources/META-INF/dubbo/com.alibaba.dubbo.rpc.InvokerListener new file mode 100644 index 0000000..e86b329 --- /dev/null +++ b/src/main/resources/META-INF/dubbo/com.alibaba.dubbo.rpc.InvokerListener @@ -0,0 +1 @@ +dubbosubscribe=com.alibaba.boot.dubbo.listener.ConsumerSubscribeListener \ No newline at end of file diff --git a/src/main/resources/META-INF/spring.factories b/src/main/resources/META-INF/spring.factories new file mode 100644 index 0000000..e0c6558 --- /dev/null +++ b/src/main/resources/META-INF/spring.factories @@ -0,0 +1,4 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ +com.alibaba.boot.dubbo.DubboAutoConfiguration,\ +com.alibaba.boot.dubbo.DubboProviderAutoConfiguration,\ +com.alibaba.boot.dubbo.DubboConsumerAutoConfiguration diff --git a/src/main/resources/META-INF/spring.provides b/src/main/resources/META-INF/spring.provides new file mode 100644 index 0000000..70c8d2c --- /dev/null +++ b/src/main/resources/META-INF/spring.provides @@ -0,0 +1 @@ +provides: spring-boot-starter-dubbo \ No newline at end of file diff --git a/src/test/java/com/alibaba/boot/dubbo/DubboProviderLauncher.java b/src/test/java/com/alibaba/boot/dubbo/DubboProviderLauncher.java new file mode 100644 index 0000000..af8b06f --- /dev/null +++ b/src/test/java/com/alibaba/boot/dubbo/DubboProviderLauncher.java @@ -0,0 +1,22 @@ +package com.alibaba.boot.dubbo; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +import com.alibaba.boot.dubbo.annotation.EnableDubboConfiguration; + +/** + * spring boot默认使用tomcat8,所以需要jdk7以上版本 + * + * @author xionghui + * @email xionghui.xh@alibaba-inc.com + * @since 1.0.0 + */ +@SpringBootApplication +@EnableDubboConfiguration +public class DubboProviderLauncher { + + public static void main(String[] args) { + SpringApplication.run(DubboProviderLauncher.class, args); + } +} diff --git a/src/test/java/com/alibaba/boot/dubbo/service/IHelloService.java b/src/test/java/com/alibaba/boot/dubbo/service/IHelloService.java new file mode 100644 index 0000000..6bc9351 --- /dev/null +++ b/src/test/java/com/alibaba/boot/dubbo/service/IHelloService.java @@ -0,0 +1,5 @@ +package com.alibaba.boot.dubbo.service; + +public interface IHelloService { + public String hello(); +} diff --git a/src/test/java/com/alibaba/boot/dubbo/service/impl/HelloServiceImpl.java b/src/test/java/com/alibaba/boot/dubbo/service/impl/HelloServiceImpl.java new file mode 100644 index 0000000..64f4229 --- /dev/null +++ b/src/test/java/com/alibaba/boot/dubbo/service/impl/HelloServiceImpl.java @@ -0,0 +1,16 @@ +package com.alibaba.boot.dubbo.service.impl; + +import org.springframework.stereotype.Component; + +import com.alibaba.boot.dubbo.service.IHelloService; +import com.alibaba.dubbo.config.annotation.Service; + +@Service(interfaceClass = IHelloService.class) +@Component +public class HelloServiceImpl implements IHelloService { + + @Override + public String hello() { + return "hello"; + } +} diff --git a/src/test/resources/application.properties b/src/test/resources/application.properties new file mode 100644 index 0000000..7d988a9 --- /dev/null +++ b/src/test/resources/application.properties @@ -0,0 +1,16 @@ +# 服务端口 +server.port=7001 + +# tomcat最大线程数,默认为200 +server.tomcat.max-threads=10 + +spring.http.encoding.charset=UTF-8 +spring.http.encoding.enabled=true + +# dubbo配置 +spring.dubbo.appname=spring-boot-starter-dubbo-test +spring.dubbo.protocol=dubbo +spring.dubbo.registry=multicast://224.0.0.0:1111 +spring.dubbo.port=20801 +spring.dubbo.group=test +spring.dubbo.version=1.0.0