1. 程式人生 > 其它 >Java web專案建立筆記27 之《整合dubbo》

Java web專案建立筆記27 之《整合dubbo》

技術標籤:JAVA WEB建立筆記

dubbo是一個rpc框架,提供了遠端方法呼叫的功能
需要3個角色:註冊中心、服務提供方、服務消費方
註冊中心用:nacos
服務提供方名稱:dubbo-provider-demo
服務消費方名稱:dubbo-consumer-demo
dubbo使用spring裝配有兩種配置方法,註解驅動和spring xml檔案配置,這裡使用xml檔案

1、pom檔案新增依賴

<dubbo.version>2.6.9</dubbo.version>
<dubbo.spring.version>1.0.11</dubbo.spring.version>
<dubbo.registry.nacos.version>2.6.7</dubbo.registry.nacos.version>
<!-- dubbo依賴 -->
<dependency>
	<groupId>com.alibaba</groupId>
	<artifactId>dubbo</artifactId>
	<version>${dubbo.version}</version>
</dependency>
<!-- dubbo使用spring裝配方式 -->
<dependency>
	<groupId>com.alibaba.spring</groupId>
	<artifactId>spring-context-support</artifactId>
	<version>${dubbo.spring.version}</version>
</dependency>
<!-- dubbo nacos registry依賴 -->
<dependency>
	<groupId>com.alibaba</groupId>
	<artifactId>dubbo-registry-nacos</artifactId>
	<version>${dubbo.registry.nacos.version}</version>
</dependency>

2、在webapp2_module1模組
1)新增包com.study.module1.dubbo.resource
2)在該包下,新增服務介面,DemoService.java

package com.study.module1.dubbo.resource;

public interface DemoService {
	
	String echo(String msg);
}

3)新增包com.study.module1.dubbo.resource.impl
4)在該包下,新增服務介面實現類,DemoServiceImpl.java

package com.study.module1.dubbo.resource.impl;

import com.alibaba.dubbo.rpc.RpcContext;
import com.study.module1.dubbo.resource.DemoService;

public class DemoServiceImpl implements DemoService {

	@Override
	public String echo(String msg) {
		RpcContext rpcContext = RpcContext.getContext();
		// 獲取當前服務配置資訊
		String application = RpcContext.getContext().getUrl().getParameter("application");
		return String.format("Service [name :%s , port : %d] %s say : Hello,%s", 
				application, 
				rpcContext.getLocalPort(),
				rpcContext.getMethodName(), msg);
	}

}

3、webapp2_web模組src/main/resources
1)新增服務提供方配置檔案,spring-dubbo-provider.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd
           http://dubbo.apache.org/schema/dubbo
           http://dubbo.apache.org/schema/dubbo/dubbo.xsd">

    <!-- 提供方應用資訊,用於計算依賴關係 -->
    <dubbo:application name="dubbo-provider-demo"/>

    <!-- 使用 Nacos 註冊中心 -->
    <dubbo:registry address="nacos://172.0.0.1:8848"/>
    <!-- 如果要使用自己建立的名稱空間可以使用下面配置 -->
    <!-- <dubbo:registry address="nacos://127.0.0.1:8848?namespace=5cbb70a5-xxx-xxx-xxx-d43479ae0932" /> -->

    <!-- 用dubbo協議在隨機埠暴露服務 -->
    <dubbo:protocol name="dubbo" port="-1"/>

    <!-- 宣告需要暴露的服務介面 -->
    <dubbo:service interface="com.study.module1.dubbo.resource.DemoService" ref="demoService" version="1.0.0"/>

    <!-- 和本地bean一樣實現服務 -->
    <bean id="demoService" class="com.study.module1.dubbo.resource.impl.DemoServiceImpl"/>
</beans>

2)新增服務消費方配置檔案,spring-dubbo-consumer.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd
           http://dubbo.apache.org/schema/dubbo
           http://dubbo.apache.org/schema/dubbo/dubbo.xsd">

    <!-- 提供方應用資訊,用於計算依賴關係 -->
    <dubbo:application name="dubbo-consumer-demo"/>

    <!-- 使用 Nacos 註冊中心 -->
    <dubbo:registry address="nacos://127.0.0.1:8848"/>
    <!-- 如果要使用自己建立的名稱空間可以使用下面配置 -->
    <!-- <dubbo:registry address="nacos://127.0.0.1:8848?namespace=5cbb70a5-xxx-xxx-xxx-d43479ae0932" /> -->

    <!-- 引用服務介面 -->
    <dubbo:reference id="dubboConsumer" interface="com.study.module1.dubbo.resource.DemoService" version="1.0.0"/>

</beans>

3)applicationContext.xml新增檔案引用

<import resource="classpath:/spring-dubbo-provider.xml"/>
<import resource="classpath:/spring-dubbo-consumer.xml"/>

注:實際只能配置使用一個,要麼服務方要麼消費方

4、在src/test/java下新增測試類,DubboTest.java

package webapp;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;

import com.study.base.util.ApplicationContextHolder;
import com.study.module1.dubbo.resource.DemoService;

@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration(locations = { "classpath:applicationContext.xml", "classpath:spring-mvc.xml" })
@ActiveProfiles("dev")
public class DubboTest {

	@Test
	public void test() throws Exception {
		DemoService demo = ApplicationContextHolder.getBean("dubboConsumer", DemoService.class);
		String result = demo.echo("我是誰");
		System.out.println(result);
        System.out.println("111111111111111111111111");
		Thread.sleep(60 * 1000);
	}
}

5、測試方法
1)起一個服務,配置為服務提供方,放到tomcat中啟動
2)本地專案配置為服務消費方,執行測試方法
日誌打印出:Service [name :dubbo-provider-demo , port : 20880] echo say : Hello,我是誰
檢視nacos控制檯,都註冊上了:

6、遇到的問題
1)pom檔案中
<!-- dubbo nacos registry依賴 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo-registry-nacos</artifactId>
<version>${dubbo.registry.nacos.version}</version>
</dependency>
版本不能用2.6.9,因為會報錯,原因是這個版本沒有自動依賴nacos-client包。。。

java.lang.IllegalStateException: Failed to load ApplicationContext
	at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:124)
	at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:83)
	at org.springframework.test.context.web.ServletTestExecutionListener.setUpRequestContextIfNecessary(ServletTestExecutionListener.java:189)
	at org.springframework.test.context.web.ServletTestExecutionListener.prepareTestInstance(ServletTestExecutionListener.java:131)
	at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:230)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:228)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:287)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:289)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:247)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94)
	at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
	at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
	at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
	at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
	at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191)
	at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:89)
	at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:41)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:542)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:770)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:464)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:210)
Caused by: java.lang.IllegalStateException: Failed to load extension class(interface: interface com.alibaba.dubbo.registry.RegistryFactory, class line: com.alibaba.dubbo.registry.nacos.NacosRegistryFactory) in jar:file:/C:/Users/User/.m2/repository/com/alibaba/dubbo-registry-nacos/2.6.9/dubbo-registry-nacos-2.6.9.jar!/META-INF/dubbo/com.alibaba.dubbo.registry.RegistryFactory, cause: com/alibaba/nacos/api/exception/NacosException
	at com.alibaba.dubbo.common.extension.ExtensionLoader.loadResource(ExtensionLoader.java:634)
	at com.alibaba.dubbo.common.extension.ExtensionLoader.loadDirectory(ExtensionLoader.java:604)
	at com.alibaba.dubbo.common.extension.ExtensionLoader.loadExtensionClasses(ExtensionLoader.java:586)
	at com.alibaba.dubbo.common.extension.ExtensionLoader.getExtensionClasses(ExtensionLoader.java:561)
	at com.alibaba.dubbo.common.extension.ExtensionLoader.getExtensionClass(ExtensionLoader.java:549)
	at com.alibaba.dubbo.common.extension.ExtensionLoader.hasExtension(ExtensionLoader.java:333)
	at com.alibaba.dubbo.config.AbstractInterfaceConfig.loadRegistries(AbstractInterfaceConfig.java:185)
	at com.alibaba.dubbo.config.ServiceConfig.doExportUrls(ServiceConfig.java:358)
	at com.alibaba.dubbo.config.ServiceConfig.doExport(ServiceConfig.java:319)
	at com.alibaba.dubbo.config.ServiceConfig.export(ServiceConfig.java:217)
	at com.alibaba.dubbo.config.spring.ServiceBean.export(ServiceBean.java:266)
	at com.alibaba.dubbo.config.spring.ServiceBean.onApplicationEvent(ServiceBean.java:106)
	at com.alibaba.dubbo.config.spring.ServiceBean.onApplicationEvent(ServiceBean.java:53)
	at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:172)
	at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:165)
	at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:139)
	at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:393)
	at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:347)
	at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:883)
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:545)
	at org.springframework.test.context.web.AbstractGenericWebContextLoader.loadContext(AbstractGenericWebContextLoader.java:130)
	at org.springframework.test.context.web.AbstractGenericWebContextLoader.loadContext(AbstractGenericWebContextLoader.java:61)
	at org.springframework.test.context.support.AbstractDelegatingSmartContextLoader.delegateLoading(AbstractDelegatingSmartContextLoader.java:281)
	at org.springframework.test.context.support.AbstractDelegatingSmartContextLoader.loadContext(AbstractDelegatingSmartContextLoader.java:249)
	at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:98)
	at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:116)
	... 26 more
Caused by: java.lang.NoClassDefFoundError: com/alibaba/nacos/api/exception/NacosException
	at java.lang.Class.forName0(Native Method)
	at java.lang.Class.forName(Class.java:348)
	at com.alibaba.dubbo.common.extension.ExtensionLoader.loadResource(ExtensionLoader.java:631)
	... 51 more
Caused by: java.lang.ClassNotFoundException: com.alibaba.nacos.api.exception.NacosException
	at java.net.URLClassLoader.findClass(URLClassLoader.java:382)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
	at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:349)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
	... 54 more

2)在實際使用中服務提供方和服務消費方是兩個不同的專案
那麼服務消費方如何獲取這個服務介面類,DemoService.class?引入對方的jar包?
3)nacos控制檯-服務管理,下面分為服務列表和訂閱者列表,這個訂閱者列表是幹什麼的呢?

這個訂閱者列表不是指消費者列表,而是指主動向Nacos Server發起事件監聽的訂閱者,比如健康檢查、服務變更等事件監聽的訂閱者,具體可檢視NacosDiscoveryEndpoint.nacosDiscovery()方法中是通過EventDispatcher去獲取訂閱者列表和釋出事件。新版本才加了這麼個訂閱者列表,老版本可以訂閱預設端點檢視訂閱者列表:http://127.0.0.1:9000/actuator/nacos-discovery

參考資料:
https://nacos.io/zh-cn/docs/use-nacos-with-dubbo.html

注:最新程式碼上傳至https://github.com/csj50/webapp2.git