一、Dubbo的注解配置
在Dubbo 2.6.3及以上版本提供支持。
1、@Service(全路徑@org.apache.dubbo.config.annotation.Service)
配置服務提供方用以暴露服務,添加於api接口的實現類上,並可通過注解提供的屬性進一步定制化服務。
其中比較重要的屬性有:
- @Service只能定義在一個類上,用以提供一個服務的具體實現
- interfaceClass:指定服務提供方實現的interface的類
- interfaceName:指定服務提供方實現的interface的類名
- version
- group:指定服務分組
- export:是否暴露服務
- register:是否向注冊中心注冊服務
- application:應用配置
- module:模塊配置
- provider:服務提供方配置
- protocol:傳輸層協議配置
- monitor:監控中心配置
- registry:注冊中心配置
注意,8-13需要提供對應的spring bean的名字,bean的組裝可以通過傳統的XML配置方式完成,或者Java Config的方式配置(推薦使用)。
2、@Reference(全路徑@org.apache.dubbo,config.annotation.Reference)
服務消費方用以引用服務,通過動態代理來實現接口的引用,同樣可通過注解提供的屬性進一步定制化服務。
其中比較重要的屬性有:
- @Reference通常定義在一個字段上,表示一個服務的引用
- interfaceClass:指定服務的interface的類
- interfaceName:指定服務的interface的類名
- version
- group
- url:指定服務提供方的URL地址,繞過注冊中心直接發起調用
- application:應用配置
- module:模塊配置
- consumer:服務消費方配置
- protocol:協議配置
- monitor:監控中心配置
- registry:注冊中心配置
同上,7-12需要提供對應的spring bean的名字,推薦使用Java Config的方式進行組裝Bean。
3、@EnableDubbo(全路徑org.apache.dubbo.config.spring.context.annotation.EnableDubbo)
@EnableDubbo注解是@EnableDubboConfig和@DubboComponentScan兩者組合的便捷表達。
@EnableDubbo提供scanBasePackages和scanBasePackageClasses屬性,可以在指定的包名或者類中掃描Dubbo的服務提供者(@Service標注)和服務消費者(@Reference標注),掃描到服務的提供者或消費者后,對其進行相應的組裝並初始化, 最終完成服務的暴露或引用。
掃描提供者和消費者的功能@DubboComponnetScan也可以實現,@EnableDubboConfig提供外部化配置的支持。
二、Dubbo的API屬性配置
目前,通過@Service、@Reference、@EnableDubbo注解,實現了服務的暴露和發現引用,除此之外,還需要一些其他的屬性配置,諸如應用名、注冊中心、協議信息等。
1、Dubbo中配置類結構
2、注入這些配置屬性,有兩種方式,分別是采用配置文件和Java Config硬編碼的形式。
2.1、配置文件方式
在resources下創建xxx.properties文件,在其中添加各項屬性配置,形式如下:
dubbo.application.name=provider
dubbo.registry.address=zookeeper://127.0.0.1:2181
dubbo.protocol.name=dubbo
dubbo.protocol.port=20880
然后通過@PropertySource("classpath:/xxx.properties")注解導入配置;
導入屬性在啟動時,會被自動組裝成相應的配置類。
2.2、Java Config硬編碼方式
創建providerConfiguration類,標注@Configuration注解;
在該類中,通過@Beab的形式分別配置需要的配置類,如下:
1 @Bean 2 public ApplicationConfig applicationConfig() { 3 ApplicationConfig applicationConfig = new ApplicationConfig(); 4 applicationConfig.setName("provider"); 5 return applicationConfig; 6 } 7
8 @Bean 9 public ProtocolConfig protocolConfig() { 10 ProtocolConfig protocolConfig = new ProtocolConfig(); 11 protocolConfig.setName("dubbo"); 12 protocolConfig.setPort("20880"); 13 return protocolConfig; 14 } 15
16 @Bean 17 public RegistryConfig registryConfig() { 18 RegistryConfig registryConfig = new RegistryConfig(); 19 registryConfig.setProtocol("zookeeper"); 20 registryConfig.setAddress("localhost"); 21 registryConfig.setPort(2181); 22 return registryConfig; 23 }
在具體實現中,創建Config類,通過Java Config技術(@Configuration)和annotation掃描(@EnableDubbo)來發現、組裝服務提供者和消費者。
三、其他相關Spring注解
1、@Configuration(全路徑org.springframework.context.annotation.Configuration)
@Configuration注解用來定義配置類,可替換XML配置文件,被注解類內有多個@Bean標注方法,這些方法會被AnnotationConfigApplicationContext或者AnnotationConfigWebApplicationContext類進行掃描,用於構建bean並初始化spring容器。
@Configuration注解的配置類有以下要求:
-
- @Configuration注解的配置類不可以是final類型。
- 內部嵌套的內部Configuration類必須是靜態類。
1.1、@Configuration配置spring並啟動spring容器
起到為spring容器配置應用上下文的作用:
ApplicationContext context = new AnnotationConfigApplicationContext(TestConfiguration.class);
效果等價於用XML文件配置:
ApplicationContext context = new ClassPathXmlApplicationContext("test-spring-context.xml");
1.2、@Configuration啟動容器+@Bean注冊bean,@Bean下管理bean的生命周期
@Bean標注在方法上,作用相當於注冊Bean,注意:
-
- @Bean標注在返回實例的方法上,如果未通過@Bean指定bean的名稱,默認與標注方法名同名。
- @Bean標注默認bean作用域為單例singleton,可通過@Scope()設置。
- @Bean的作用是注冊bean,因此也可以用@Component、@Controller、@Service、@Repository等進行注冊,不過需要配置@ComponentScan注解進行自動掃描。
- 可以通過@Bean管理bean的生命周期。
1.3、組合多個配置來源
通過@ImportSource("classpath:/xxx.xml")導入XML配置文件;
通過@Import(TestConfiguration.class)導入其他配置類;
通過@Configuration嵌套(嵌套額Configuration類必須為靜態類)。
2、@Component、@Service、@Controller、@Repository、@RestController、@Bean
修飾的類均會被掃描到並注入到spring的bean容器中。
2.1、@Component
通用注解,可以被注入到spring容器進行管理。
2.2、@Service、@Controller、@Repository是針對不同使用場景采用的特定功能化的注解組件。
-
- @Service:作用於業務邏輯層
- @Controller:作用於表現層(springMVC注解),注解的bean會被spring-mvc框架使用,進行前端請求的處理、轉發、重定向,包括調用service層的方法
- @Repository:作用於持久層,表明該類是用來執行與數據庫相關的操作,並支持自動處理數據庫操作產生的異常
2.3、@Controller和@RestController
首先兩者都是表明該類可以接受HTTP請求,@RestController相當於@Controller+@ResponseBody的作用。
在@RestController中,返回的應該是一個對象,即使沒有前端界面的渲染,也可以看到返回的是該對象對應的json字符串,而前端的作用就是利用返回的json進行解析並渲染界面。
在@Controller中,返回的是一個字符串,或者代表與字符串匹配的模板名稱,與HTML頁面配合使用。
-
- 如果只是用@RestController注解,則Controller方法中無法返回jsp頁面,配置的視圖解析器InternalResourceViewResolver不起作用,返回的內容就是方法中return的值。
- 如需要指定返回某個頁面,則需要用@Controller配合視圖解析器InternalResourceViewResolver使用。
- 如果需要返回Json、XML或自定義的mediaType內容到頁面,@RestController直接就能做到,但在@Controller中需要在相應方法上加上@ResponseBody注解。
2.4、@Bean和@Component(@Service、@Controller、@Repository)的區別
- @Component注解表明一個類作為組件類,並告知spring為該類創建bean。
- @Bean注解告訴spring這個方法將返回一個對象,該對象要注冊為spring應用上下文中的bean。
兩者目的都是注冊bean到Spring容器中。
- @Component通常是通過類路徑掃描來自動偵測並自動裝配到spring容器中。作用於類。
- @Bean注解通常是我們在標有該注解的方法中自定義產生這個bean的邏輯。作用於方法。
3、@Autowired、@Resource
@Autowired默認按照類型裝配。
默認要求依賴的對象必須存在,若允許為NULL,可以設置required屬性為false。
@Resouce默認按照名稱裝配。
可以通過name屬性指定,指定了name屬性,就只能按照名稱裝配。
有兩個重要的屬性,name和人type,將name屬性解析為bean的名字,type解析為bean的類型。
使用了name屬性,則使用byName的自動注入策略;而使用type屬性,則使用byType的自動注入策略。
@Resouce的裝配順序:
- 同時指定了name和type屬性,從spring上下文找到唯一匹配的bean進行裝配,找不到則拋出異常。
- 指定了name屬性,從上下文查找名稱匹配的bean進行裝配,找不到則拋出異常。
- 指定了type屬性,從上下文查找類型匹配的唯一bean進行裝配,找不到或者找到多個則拋出異常。
- 屬性均未指定,則默認按照byName的方式進行查找裝配。
4、@PropertySource、@ImportResource
@ImportResource:導入spring的配置文件,如xxx.XML。
@PropertySource
@ConfigurationProperties是默認從全局配置文件中獲取指定的值,例如@ConfigurationProperties(prefix=“person”)是從application.yml(properties)中加載person的屬性並映射到對應類的屬性。
如果配置在xxx.properties中(非全局配置文件),就需要用@PropertySource(value={"classpath:/xxx.properties"})導入指定配置文件。
四、項目搭建流程
1、注冊中心Zookeeper搭建
Zookeeper的安裝不在此介紹,可參考:Zookeeper單點與集群安裝
2、項目框架搭建
創建maven項目hello_dubbo,刪掉其中的src文件夾,並添加對spring-boot的依賴,作為整個項目運行環境。
新建new module,依次為api(服務接口公共包)、provider(服務提供者模塊)、consumer(服務消費者模塊),。
此時項目結構如圖:
pom文件關鍵信息為:

1 <groupId>com.li</groupId> 2 <artifactId>hello_dubbo</artifactId> 3 <version>1.0-SNAPSHOT</version> 4 5 <parent> 6 <groupId>org.springframework.boot</groupId> 7 <artifactId>spring-boot-starter-parent</artifactId> 8 <version>2.1.9.RELEASE</version> 9 <relativePath/> 10 </parent> 11 12 <modules> 13 <module>api</module> 14 <module>provider</module> 15 <module>consumer</module> 16 </modules>
3、api包
在pom文件中配置依賴關系:

1 <parent> 2 <groupId>com.li</groupId> 3 <artifactId>hello_dubbo</artifactId> 4 <version>1.0-SNAPSHOT</version> 5 </parent> 6 7 <artifactId>api</artifactId>
在api包中創建要對外提供服務的接口類HelloAPI.java:

1 package com.li.api; 2 3 public interface HelloApi { 4 5 public String sayHello(String name); 6 }
此時的api模塊結構:
4、provider項目
1、修改pom文件,添加相關依賴:

1 <parent> 2 <groupId>com.li</groupId> 3 <artifactId>hello_dubbo</artifactId> 4 <version>1.0-SNAPSHOT</version> 5 </parent> 6 7 <artifactId>provider</artifactId> 8 <version>0.0.1-SNAPSHOT</version> 9 <name>provider</name> 10 11 <dependencies> 12 <!--web支持--> 13 <dependency> 14 <groupId>org.springframework.boot</groupId> 15 <artifactId>spring-boot-starter-web</artifactId> 16 </dependency> 17 <!--添加Zookeeper依賴--> 18 <dependency> 19 <groupId>org.apache.zookeeper</groupId> 20 <artifactId>zookeeper</artifactId> 21 <version>3.5.5</version> 22 <exclusions> 23 <exclusion> 24 <groupId>org.slf4j</groupId> 25 <artifactId>slf4j-log4j12</artifactId> 26 </exclusion> 27 </exclusions> 28 </dependency> 29 <!--添加Dubbo依賴,已並入apache--> 30 <dependency> 31 <groupId>org.apache.dubbo</groupId> 32 <artifactId>dubbo</artifactId> 33 <version>2.7.3</version> 34 </dependency> 35 <!--添加zookeeper客戶端框架Curator--> 36 <dependency> 37 <groupId>org.apache.curator</groupId> 38 <artifactId>curator-framework</artifactId> 39 <version>4.2.0</version> 40 </dependency> 41 <dependency> 42 <groupId>org.apache.curator</groupId> 43 <artifactId>curator-recipes</artifactId> 44 <version>4.2.0</version> 45 </dependency> 46 <dependency> 47 <groupId>org.springframework.boot</groupId> 48 <artifactId>spring-boot-starter-test</artifactId> 49 <scope>test</scope> 50 </dependency> 51 <!--添加對API模塊的依賴--> 52 <dependency> 53 <groupId>com.li</groupId> 54 <artifactId>api</artifactId> 55 <version>1.0-SNAPSHOT</version> 56 <scope>compile</scope> 57 </dependency> 58 </dependencies>
2、添加service包,在其中創建api接口的實現類,提供服務的具體實現,並用@Service暴露服務:

1 package com.li.provider.service; 2 3 import com.li.api.HelloApi; 4 import org.apache.dubbo.config.annotation.Service; 5 6 @Service 7 public class HelloService implements HelloApi { 8 9 @Override 10 public String sayHello(String name) { 11 return "hello " + name; 12 } 13 }
3、provider的配置注入方式選擇采用properties文件的形式。
在resources下添加provider.properties配置文件:

1 dubbo.application.name=helloP 2 dubbo.registry.address=zookeeper://127.0.0.1:2181 3 dubbo.protocol.name=dubbo 4 dubbo.protocol.port=20880 5 server.port=8001
在主目錄下創建Configuration類,作為配置類:

1 package com.li.provider; 2 3 import org.apache.dubbo.config.spring.context.annotation.EnableDubbo; 4 import org.springframework.context.annotation.Configuration; 5 import org.springframework.context.annotation.PropertySource; 6 7 @Configuration 8 @EnableDubbo(scanBasePackages = "com.li.provider.service") 9 @PropertySource("classpath:/provider.properties") 10 public class ProviderConfiguration { 11 }
4、啟動類選擇springBoot啟動:

1 package com.li.provider; 2 3 import org.springframework.boot.SpringApplication; 4 import org.springframework.boot.autoconfigure.SpringBootApplication; 5 6 @SpringBootApplication 7 public class ProviderApplication { 8 9 public static void main(String[] args) { 10 SpringApplication.run(ProviderApplication.class, args); 11 } 12 13 }
5、至此,Provider模塊完成,項目結構如下:
5、consumer項目
1、修改pom文件,添加相關依賴:

1 <parent> 2 <groupId>com.li</groupId> 3 <artifactId>hello_dubbo</artifactId> 4 <version>1.0-SNAPSHOT</version> 5 </parent> 6 7 <artifactId>consumer</artifactId> 8 <version>0.0.1-SNAPSHOT</version> 9 <name>consumer</name> 10 11 <dependencies> 12 <!--web支持--> 13 <dependency> 14 <groupId>org.springframework.boot</groupId> 15 <artifactId>spring-boot-starter-web</artifactId> 16 </dependency> 17 <!--添加Zookeeper依賴--> 18 <dependency> 19 <groupId>org.apache.zookeeper</groupId> 20 <artifactId>zookeeper</artifactId> 21 <version>3.5.5</version> 22 <exclusions> 23 <exclusion> 24 <groupId>org.slf4j</groupId> 25 <artifactId>slf4j-log4j12</artifactId> 26 </exclusion> 27 </exclusions> 28 </dependency> 29 <!--添加Dubbo依賴,已並入apache--> 30 <dependency> 31 <groupId>org.apache.dubbo</groupId> 32 <artifactId>dubbo</artifactId> 33 <version>2.7.3</version> 34 </dependency> 35 <!--添加zookeeper客戶端框架Curator--> 36 <dependency> 37 <groupId>org.apache.curator</groupId> 38 <artifactId>curator-framework</artifactId> 39 <version>4.2.0</version> 40 </dependency> 41 <dependency> 42 <groupId>org.apache.curator</groupId> 43 <artifactId>curator-recipes</artifactId> 44 <version>4.2.0</version> 45 </dependency> 46 <dependency> 47 <groupId>org.springframework.boot</groupId> 48 <artifactId>spring-boot-starter-test</artifactId> 49 <scope>test</scope> 50 </dependency> 51 <!--添加對API模塊的依賴--> 52 <dependency> 53 <groupId>com.li</groupId> 54 <artifactId>api</artifactId> 55 <version>1.0-SNAPSHOT</version> 56 <scope>compile</scope> 57 </dependency> 58 </dependencies>
2、創建action包,新增HelloAction類,作為MVC框架的service層,提供業務邏輯處理並利用@Reference提供對遠程服務的引用:

1 package com.li.consumer.action; 2 3 import com.li.api.HelloApi; 4 import org.apache.dubbo.config.annotation.Reference; 5 import org.springframework.stereotype.Service; 6 7 @Service //注意為spring的@Service注解,將其作為bean管理 8 public class HelloAction { 9 10 @Reference(check = false) 11 private HelloApi helloApi; 12 13 public String doHello(String name) { 14 return helloApi.sayHello(name); 15 } 16 }
3、創建controller包,新增HelloController類,作為MVC框架的controller層,提供前端請求的轉發,以及業務邏輯的調用:

1 package com.li.consumer.controller; 2 3 import com.li.consumer.action.HelloAction; 4 import org.springframework.beans.factory.annotation.Autowired; 5 import org.springframework.web.bind.annotation.GetMapping; 6 import org.springframework.web.bind.annotation.RequestParam; 7 import org.springframework.web.bind.annotation.RestController; 8 9 @RestController 10 public class HelloController { 11 12 @Autowired 13 private HelloAction action; 14 15 @GetMapping("/hello") 16 public String hello(@RequestParam("name")String name) { 17 return action.doHello(name); 18 } 19 }
4、consumer的配置注入方式選擇采用Java Config硬編碼的形式。
在resources下添加consumer.properties配置文件:

1 server.port=8002 //注冊對外提供服務的端口
在主目錄下創建Configuration類,作為配置類:

1 package com.li.consumer; 2 3 import org.apache.dubbo.config.ApplicationConfig; 4 import org.apache.dubbo.config.RegistryConfig; 5 import org.springframework.context.annotation.Bean; 6 import org.springframework.context.annotation.Configuration; 7 import org.springframework.context.annotation.PropertySource; 8 9 @Configuration 10 @PropertySource("classpath:/consumer.properties") 11 public class ConsumerConfiguration { 12 13 @Bean 14 public ApplicationConfig applicationConfig() { 15 ApplicationConfig config = new ApplicationConfig(); 16 config.setName("helloC"); 17 return config; 18 } 19 20 @Bean 21 public RegistryConfig registryConfig() { 22 RegistryConfig config = new RegistryConfig(); 23 config.setAddress("zookeeper://127.0.0.1:2181"); 24 return config; 25 } 26 }
5、啟動類選擇springBoot啟動:

1 package com.li.consumer; 2 3 import org.springframework.boot.SpringApplication; 4 import org.springframework.boot.autoconfigure.SpringBootApplication; 5 6 @SpringBootApplication 7 public class ConsumerApplication { 8 9 public static void main(String[] args) { 10 SpringApplication.run(ConsumerApplication.class, args); 11 } 12 13 }
6、至此,Consumer模塊完成,項目結構如下:
6、項目啟動
項目啟動時,首先啟動Zookeeper,命令行執行zkServer.cmd。
正常啟動順序應該先啟動提供者,然后啟動消費者,因為@Reference注解在啟動時默認會去注冊中心檢查所引用服務狀態是否正常提供服務,若想先啟動消費者,可選擇關閉檢查功能,@Reference(check=false)。
全部啟動后,可打開zk客戶端查看已注冊服務情況。
最后打開瀏覽器,訪問localhost:8002/hello?name=world發現正常引用服務。