[root@kolla ~]# tree dubbo-samples-annotation/ dubbo-samples-annotation/ ├── pom.xml ├── README.md └── src ├── main │ ├── java │ │ └── org │ │ └── apache │ │ └── dubbo │ │ └── samples │ │ └── annotation │ │ ├── action │ │ │ └── AnnotationAction.java │ │ ├── AnnotationConstants.java │ │ ├── AnnotationConsumerBootstrap.java │ │ ├── AnnotationProviderBootstrap.java │ │ ├── api │ │ │ ├── GreetingService.java │ │ │ ├── HelloService.java │ │ │ └── Notify.java │ │ ├── config │ │ │ ├── ConsumerConfiguration.java │ │ │ └── ProviderConfiguration.java │ │ ├── EmbeddedZooKeeper.java │ │ └── impl │ │ ├── AnnotationGreetingServiceImpl.java │ │ ├── AnnotationHelloServiceImpl.java │ │ └── NotifyImpl.java │ └── resources │ ├── log4j.properties │ └── spring │ ├── dubbo-consumer.properties │ └── dubbo-provider.properties └── test └── java └── org └── apache └── dubbo └── samples └── annotation └── AnnotationServicesIT.java 21 directories, 19 files [root@kolla ~]# 一 AnnotationAction.java package org.apache.dubbo.samples.annotation.action; import org.apache.dubbo.config.annotation.Method; import org.apache.dubbo.config.annotation.Reference; import org.apache.dubbo.samples.annotation.AnnotationConstants; import org.apache.dubbo.samples.annotation.api.GreetingService; import org.apache.dubbo.samples.annotation.api.HelloService; import org.springframework.stereotype.Component; @Component("annotationAction") public class AnnotationAction { @Reference(interfaceClass = HelloService.class, version = AnnotationConstants.VERSION /*, methods = { @Method( name = "sayHello", oninvoke = "notify.oninvoke", onreturn = "notify.onreturn", onthrow = "notify.onthrow") } */ ) private HelloService helloService; @Reference(interfaceClass = GreetingService.class, version = AnnotationConstants.VERSION, timeout = 1000, methods = {@Method(name = "greeting", timeout = 3000, retries = 1)}) private GreetingService greetingService; public String doSayHello(String name) { try { return helloService.sayHello(name); } catch (Exception e) { e.printStackTrace(); return "Throw Exception"; } } public String doSayGoodbye(String name) { try { return helloService.sayGoodbye(name); } catch (Exception e) { e.printStackTrace(); return "Throw Exception"; } } public String doGreeting(String name) { try { return greetingService.greeting(name); } catch (Exception e) { e.printStackTrace(); return "Throw Exception"; } } public String replyGreeting(String name) { try { return greetingService.replyGreeting(name); } catch (Exception e) { e.printStackTrace(); return "Throw Exception"; } } } 二 AnnotationConstants.java package org.apache.dubbo.samples.annotation; public interface AnnotationConstants { String VERSION = "1.0.0_annotation"; #变量 }AnnotationServicesIT 三 AnnotationConsumerBootstrap.java 四 AnnotationProviderBootstrap.java 五 GreetingService.java package org.apache.dubbo.samples.annotation.api; import java.util.concurrent.CompletableFuture; public interface GreetingService { String greeting(String name); default String replyGreeting(String name) { return "Fine, " + name; } /*使用一个预定义的结果创建一个完成的CompletableFuture,通常我们会在计算的开始阶段使用它。*/ default CompletableFuture<String> greeting(String name, byte signal) { return CompletableFuture.completedFuture(greeting(name)); } } 代码解析------------------------------------------------------------------------ import java.util.concurrent.CompletableFuture;包解析 1依赖条件 <dependency> <groupId>com.twitter</groupId> <artifactId>util-core_2.13</artifactId> <version>20.3.0</version> </dependency> import com.sun.xml.internal.ws.util.CompletedFuture; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; /* * 并行获取各个数据源的数据合并成一个数据组合 * */ public class ParallelTest { /*获取基本信息*/ public String getProductBaseInfo(String productId){ return productId + "商品基础信息"; } /*获取详情信息*/ public String getProductdetailInfo(String productId){ return productId + "商品详情信息"; } /*获取sku信息*/ public String getProductSkuInfo(String productId){ return productId+"商品sku信息"; } /* * 取得一个商品的所有信息(基础,详情,sku) * */ public String getAllInfoByProductId(String productId) { CompletableFuture<String> f1 = CompletableFuture.supplyAsync(() -> getProductBaseInfo(productId)); CompletableFuture<String> f2 = CompletableFuture.supplyAsync(() -> getProductDetailInfo(productId)); CompletableFuture<String> f3 = CompletableFuture.supplyAsync(() -> getProductSkuInfo(productId)); //等待三个数据源都返回后,再组装数据。这里会有一个线程阻塞 CompletableFuture.allOf(f1, f2, f3).join(); try { String baseInfo = f1.get(); String detailInfo = f2.get(); String skuInfo = f3.get(); return baseInfo + "" + detailInfo + skuInfo; } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } return null; } /** * 并行获取数据的计算 */ @Test public void testGetAllInfoParalleByProductId() throws ExecutionException, InterruptedException { ParallelTest test = new ParallelTest(); String info = test.getAllInfoByProductId("1111"); Assertions.assertNotNull(info); } /** * 同步获取执行的处理 */ @Test public void testGetAllInfoDirectly() throws ExecutionException, InterruptedException { ParallelTest test = new ParallelTest(); String info1 = getProductBaseInfo("1111"); String info2 = getProductDetailInfo("1111"); String info3 = getProductSkuInfo("1111"); String info=baseInfo + "" + detailInfo + skuInfo; Assertions.assertNotNull(info); } } allOf是等待所有任务完成,接触阻塞,获取各个数据源的数据。 于上面的例子,使用了默认的线程池,线程数为cpu核数-1。这个并不能很好地利用资源。下面为线程数计算的公式: 服务器端最佳线程数量=((线程等待时间+线程cpu时间)/线程cpu时间) * cpu数量 下面例子中也将executor线程池暴露出来,方便配置线程数和做一些其他处理。 public class ParallelTest { ExecutorService executor = Executors.newFixedThreadPool(100); /** * 取得一个商品的所有信息(基础、详情、sku) * * @param productId * @return */ public String getAllInfoByProductId(String productId) { CompletableFuture<String> f1 = CompletableFuture.supplyAsync(() -> getProductBaseInfo(productId),executor); CompletableFuture<String> f2 = CompletableFuture.supplyAsync(() -> getProductDetailInfo(productId),executor); CompletableFuture<String> f3 = CompletableFuture.supplyAsync(() -> getProductSkuInfo(productId),executor); try { String baseInfo = f1.get(); String detailInfo = f2.get(); String skuInfo = f3.get(); return baseInfo + "" + detailInfo + skuInfo; } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } return null; } } ---------------------------------------------------------------------------- 六 HelloService.java public interface HelloService { //定义一个抽象方法 String sayHello(String name); //JDK 1.8 以后,接口里可以有静态方法和方法体了,默认方法 //接口中,增加default方法,是为了机油的成千上万的Java类增加新的功能,且不必对这些类重新设计。 default String sayGoodbye(String name) { return "Goodbye, " + name; } } --------------------------------------------------------------------------------- 代码案例 (1)文件InterfaceA.java package org.apache.dubbo.samples.provider; public interface InterfaceA { //接口中的所有成员变量都默认是由public static final修饰的。 //接口中的所有方法都默认是由public abstract修饰的。 /*静态方法*/ /*注意,实现接口的类或者子接口不会继承接口中的静态方法*/ static void showStatic() {System.out.println("InterfaceA ++ showStatic");} /*默认方法*/ default void showDefault() {System.out.println("InterfaceA ++ showDefault");} } (2)文件InterfaceAImpl.java package org.apache.dubbo.samples.provider; public class InterfaceAImpl implements InterfaceA{} --------------------------------------- 如果接口中的默认方法不能满足某个实现类需要,那么实现类可以覆盖默认方法。 实现单一接口,重写接口中的default方法 public class InterfaceAImpl implements InterfaceA{ /**跟接口default方法一致,但不能再加default修饰符 运行结果如下 InterfaceA++showStatic InterfaceAImpl++ defaultShow */ @Override public void showDefault(){ System.out.println("InterfaceAImpl++ defaultShow"); } } (3)文件test1.java package org.apache.dubbo.samples.provider; public class test1 { public static void main(String[] args) throws Exception{ InterfaceA.showStatic(); /*注意,实现接口的类或者子接口不会继承接口中的静态方法*/ new InterfaceAImpl().showDefault(); } } (4)运行结果 InterfaceA ++ showStatic InterfaceA ++ showDefault 七 Notify.java package org.apache.dubbo.samples.annotation.api; import java.util.List; import java.util.Map; public interface Notify { //通知 void oninvoke(String request); void onreturn(String response, String request); void onthrow(Throwable ex, String request); List<String> getInvokes(); Map<String, String> getReturns(); Map<String, Throwable> getExceptions(); } 八 ConsumerConfiguration.java package org.apache.dubbo.samples.annotation.config; //注解配置 import org.apache.dubbo.config.spring.context.annotation.EnableDubbo; //上下文,背景,环境,语境 import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.PropertySource; @Configuration @EnableDubbo(scanBasePackages = "org.apache.dubbo.samples.annotation.action") @PropertySource("classpath:/spring/dubbo-consumer.properties") @ComponentScan(value = {"org.apache.dubbo.samples.annotation.action"}) public class ConsumerConfiguration { } 注解解释 @Configuration:相当于标签,一个配置类可以有多个bean, 但是只能有一个 @PropertySource:注释加载外部资源和自动装配,外面资源文件,用于引入外部属性配置,和Environment配合一起使用,其中ignoreResourceNotFound表示没有找到文件是否会报错, 默认为false, 就是会报错,一般开发情况应该使用默认值,设置为true相当于生吞异常,增加排查问题的复杂性 @ComponentScan 开启注解扫描,扫描路径下的所有方法 引入PropertySource,注入Environment,然后就能用environment 获取配置文件中的value值 九 ProviderConfiguration.java package org.apache.dubbo.samples.annotation.config; import org.apache.dubbo.config.ProviderConfig; import org.apache.dubbo.config.spring.context.annotation.EnableDubbo; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.PropertySource; @Configuration @EnableDubbo(scanBasePackages = "org.apache.dubbo.samples.annotation.impl") @PropertySource("classpath:/spring/dubbo-provider.properties") public class ProviderConfiguration { @Bean public ProviderConfig providerConfig() { ProviderConfig providerConfig = new ProviderConfig(); providerConfig.setTimeout(1000); return providerConfig; } } 代码解析: (1)Bean是啥 1Java面向对象,对象有方法和属性,那么就需要对象实例来调用方法和属性(即实例化); 2凡是有方法或属性的类都需要实例化,这样才能去使用这些方法和属性 3规律:凡是子类以带有方法或属性的类都要加上注册Bean到Spring IoC的注解 4Bean理解为类的代理或代言人(实际上确实是通过反射,代理来实现,这样它就能代表类拥有该拥有的东西了) 5我们都在微博上@过某某,对方会优先看到这条信息,并给你反馈,那么在Spring中,你标识一个@符号,那么Spring就会来看看,并且从这里拿到一个Bean或者给出一个Bean 二、注解分为两类: 1、一类是使用Bean,即是把已经在xml文件中配置好的Bean拿来用,完成属性、方法的组装;比如@Autowired , @Resource,可以通过byTYPE(@Autowired)、byNAME(@Resource)的方式获取Bean; 2、一类是注册Bean,@Component , @Repository , @ Controller , @Service , @Configration这些注解都是把你要实例化的对象转化成一个Bean,放在IoC容器中,等你要用的时候,它会和上面的@Autowired , @Resource配合到一起,把对象、属性、方法完美组装。 @Bean明确地指示了一种方法,产生一个bean的方法,并且交给Spring容器管理;明确地告诉被注释的方法, 你给我产生了一个Bean, 然后交给Spring容器,剩下的就不用管了 总结为: 1凡是子类及带属性,方法的类都注册Bean到Spring重,交给它管理; 2@Bean用在方法上,告诉spring容器,你可以从下面方法中拿到一个Bean 十 EmbeddedZooKeeper.java 十一 AnnotationGreetingServiceImpl.java @Service(version = AnnotationConstants.VERSION) public class AnnotationGreetingServiceImpl implements GreetingService { @Override public String greeting(String name) { System.out.println("provider received invoke of greeting: " + name); sleepWhile(); return "Annotation, greeting " + name; } public String replyGreeting(String name) { System.out.println("provider received invoke of replyGreeting: " + name); sleepWhile(); return "Annotation, fine " + name; } private void sleepWhile() { try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } } 十二 AnnotationHelloServiceImpl.java import org.apache.dubbo.config.annotation.Method; import org.apache.dubbo.config.annotation.Service; import org.apache.dubbo.samples.annotation.AnnotationConstants; import org.apache.dubbo.samples.annotation.api.HelloService; @Service(version = AnnotationConstants.VERSION, methods = {@Method(name = "sayGoodbye", timeout = 250, retries = 0)}) public class AnnotationHelloServiceImpl implements HelloService { @Override public String sayHello(String name) { System.out.println("provider received invoke of sayHello: " + name); sleepWhile(); return "Annotation, hello " + name; } public String sayGoodbye(String name) { System.out.println("provider received invoke of sayGoodbye: " + name); sleepWhile(); return "Goodbye, " + name; } private void sleepWhile() { try { Thread.sleep(300); } catch (InterruptedException e) { e.printStackTrace(); } } } 十三 NotifyImpl.java @Component("notify") public class NotifyImpl implements Notify { private List<String> invokes = new ArrayList<>(); private Map<String, String> returns = new HashMap<>(); private Map<String, Throwable> exceptions = new HashMap<>(); @Override public void oninvoke(String request) { System.out.println("oninvoke - request: " + request); invokes.add(request); } @Override public void onreturn(String response, String request) { System.out.println("onreturn - req: " + request + ", res: " + response); returns.put(request, response); } @Override public void onthrow(Throwable ex, String request) { System.out.println("onthrow - request: " + request + ", exception: " + ex); exceptions.put(request, ex); } @Override public List<String> getInvokes() { return invokes; } @Override public Map<String, String> getReturns() { return returns; } @Override public Map<String, Throwable> getExceptions() { return exceptions; } } 十四 log4j.properties ###set log levels### log4j.rootLogger=info, stdout ###output to the console### log4j.appender.stdout=org.apache.log4j.ConsoleAppender #输出到控制台,附加物 log4j.appender.stdout.Target=System.out log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=[%d{dd/MM/yy hh:mm:ss:sss z}] %t %5p %c{2}: %m%n 十五 dubbo-consumer.properties dubbo.application.name=samples-annotation-consumer dubbo.registry.address=zookeeper://${zookeeper.address:127.0.0.1}:2181 dubbo.consumer.timeout=1000 十六 dubbo-provider.properties dubbo.application.name=samples-annotation-provider dubbo.registry.address=zookeeper://${zookeeper.address:127.0.0.1}:2181 dubbo.protocol.name=dubbo dubbo.protocol.port=20880 十七 AnnotationServicesIT.java package org.apache.dubbo.samples.annotation; import org.apache.dubbo.samples.annotation.action.AnnotationAction; import org.apache.dubbo.samples.annotation.config.ConsumerConfiguration; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; //@RunWith就是一个运行器 //@RunWith(Junit4.class)就是指用JUnit4来运行 //@RunWith(SpringJUint4ClassRunner.class),让测试运行于Spring测试环境 //@RunWith(Suti.class)一套测试集合 //@ContextConfiguration Spring整合JUnit4测试时,使用注解引入多个配置文件 //单个文件 //@ContextConfiguration(Location="classpath: applicationContext.xml") //@ContextConfiguration(classes=SimpleConfiguration.class) //多个文件,可用 //ContextConfiguration(locations={"classpath:spring1.xml", "classpath:spring2.xml"}) @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = {ConsumerConfiguration.class}) public class AnnotationServicesIT { //@Autowired注释,可以对类成员变量,方法以及构造函数进行标注完成自动装配的工作,通过@Authowired的使用来消除set,get方法 //#@Autowired 注释对在哪里和如何完成自动连接提供了更多的细微的控制。 //#@Autowired 注释可以在 setter 方法中被用于自动连接 bean,就像 @Autowired 注释,容器,一个属性或者任意命名的可能带有多个参数的方法 @Autowired private AnnotationAction annotationAction; //首先需要导入import org.junit.test这个jar包,@Test注解要写在你要测试的方法上面 //test()方法里面写你需要测试的方法就可以了 @Test public void testSayHello() throws Exception { //Assert.assertEquals();及其重载方法1:如果两者一致,程序继续往下运行,2,如果两者不一致,终端测试方法, //抛出异常信息AssertionFailedError Assert.assertEquals("Annotation, hello dubbo", annotationAction.doSayHello("dubbo")); } @Test public void testSayGoodbye() throws Exception { Assert.assertEquals("Throw Exception", annotationAction.doSayGoodbye("dubbo")); } @Test public void testGreeting() throws Exception { Assert.assertEquals("Annotation, greeting dubbo", annotationAction.doGreeting("dubbo")); } @Test public void testReplyGreeting() throws Exception { Assert.assertEquals("Throw Exception", annotationAction.replyGreeting("dubbo")); } }