dubbo示例分析-3-dubbo-samples-annotation

勾岳
2023-12-01
[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"));
    }
}
 类似资料: