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