Use dubbo in Spring Boot, originally is a very simple thing, but the real world is so complex, today I use a personal experience of the pit and pit filling things to tell the triple realm in Spring Boot using high version of Dubbo (down devil modified version).

1. Use an official starter

Simple integration with Spring Boot using dubbo Starter is still fairly straightforward.

Introduce dubbo’s starter in springBoot2’s POM.xml

<dependency> <groupId>com.alibaba.spring.boot</groupId> <artifactId>dubbo-spring-boot-starter</artifactId> The < version > 2.0.0 < / version > < / dependency >Copy the code

Add the @enableDubBoConfiguration annotation to the startup class

@EnableDubboConfiguration @SpringBootApplication public class DubbodemoApplication { public static void main(String[] args) { SpringApplication.run(DubbodemoApplication.class, args); }}Copy the code

Write the configuration for Dubbo in application.properties

spring.dubbo.application.name=mydubbostarterdemo
spring.dubbo.server=trueSpring. Dubbo. Protocol. The name = dubbo spring. The dubbo. Registry. Address = zookeeper: / / 127.0.0.1:2181Copy the code

As a service provider, we publish a service

public interface IHelloService {
	public String hello(String str);
}Copy the code
import com.alibaba.dubbo.config.annotation.Service; // This service annotation is dubbo's service, @Service(interfaceClass = iHelloService.class) @Component public class HelloServiceImpl implements IHelloService { @Override public String hello(String str) { StringreturnStr = "Hello "+str;
		return returnStr; }}Copy the code

Then run DubbodemoApplication to publish the service.

Similarly, on the consumer side, we can refer to the service directly with the @Reference annotation

    @Reference
	private IHelloService helloService;
	@GetMapping("/hello/{name}")
    public String hello(@PathVariable("name") String name) {
       String str = helloService.hello(name);
       System.out.println(str);
       return str;
    }Copy the code

Remember to add the IHelloService interface class to the consumer project.

This will be a pleasant call

Is it easy? Is it easy? But the world is complicated, and if we look at the POM file, we can see that the version of Dubbo referenced in it is 2.6.0

The latest version of dubbo is 2.8.4. If the service provider uses this version, then the consumer still uses this method, and an error will be reported

2019-12-05 11:51:28.094 ERROR 17808 -- [niO-8088-exec-1] O.A.C.C.C. [.[.[/].[dispatcherServlet] : servlet.service ()for servlet [dispatcherServlet] incontext with path [] threw exception [Request processing failed;  nested exception is com.alibaba.dubbo.rpc.RpcException: Failed to invoke the method helloin the service com.skyblue.dubbodemo.service.IHelloService. Tried 3 timesOf the providers [192.168.1.103:20880] (1/1) from the registry 115.29.199.6:2181 on the consumer 192.168.1.103 using the Dubbo version 2.6.0. Last error is: Failed to invoke remote method: Hello, provider: Dubbo: / / 192.168.1.103:20880 / com. Skyblue. Dubbodemo. Service. IHelloService? anyhost=true&application=mydubbostarterdemo&check=false& dubbo = 2.8.4 a&generic =false& interface = com. Skyblue. Dubbodemo. Service. IHelloService&methods = hello&pid = 17808 & register. IP = 192.168.1.103 & remote. The timestam p=1575517827193&side=consumer&timestamp=1575517879746, cause: Fail to decode request due to: RpcInvocation [methodName=hello, parameterTypes=null, arguments=null, Attachments = {path = com. Skyblue. Dubbodemo. Service. IHelloService, input = 223, dubbo = server, Version = 0.0.0}]] with the root cause of com. Alibaba. Dubbo. Remoting. RemotingException: Fail to decode the request due to: RpcInvocation [methodName=hello, parameterTypes=null, arguments=null, Attachments = {path = com. Skyblue. Dubbodemo. Service. IHelloService, input = 223, dubbo = server, Version = 0.0.0}] at com. Alibaba. Dubbo, remoting. Exchange. Support. DefaultFuture. ReturnFromResponse (DefaultFuture. Java: 218) ~ [dubbo - server. The jar: server] at the alibaba. The dubbo, remoting. Exchange. Support. DefaultFuture. Get (DefaultFuture. Java: 137) ~ [dubbo - server. The jar: server] at the alibaba. The dubbo, remoting. Exchange. Support. DefaultFuture. Get (DefaultFuture. Java: 111) ~ [dubbo - server. The jar: server] at the alibaba. Dubbo.. RPC protocol. The dubbo. DubboInvoker. DoInvoke (DubboInvoker. Java: 95) ~ [dubbo - server. The jar: server] at the alibaba. Dubbo.. RPC protocol. The AbstractInvoker. Invoke (AbstractInvoker. Java: 142) ~ [dubbo - server. The jar: server]...Copy the code

Similarly, the server provides an error

2019-12-05 12:00:55.144 WARN 7412 -- [w I/O worker#7] c.a.d.r.p.dubbo.DecodeableRpcInvocation : [DUBBO] Decode rpc invocation failed: expected integer at 0x12 java.lang.String (Ljava/lang/String;) , dubbo version: 2.8.4a, current host: 192.168.1.103

com.alibaba.com.caucho.hessian.io.HessianProtocolException: expected integerat 0x12 java.lang.String (Ljava/lang/String;) The at com.alibaba.com.caucho.hessian.io.Hessian2Input.error (Hessian2Input. Java: 2720) ~ [dubbo - 2.8.4 a. ar: 2.8.4 a] the at Com.alibaba.com.caucho.hessian.io.Hessian2Input.expect Hessian2Input. Java: (2691) ~ [dubbo - 2.8.4 a. ar: 2.8.4 a] the at Com.alibaba.com.caucho.hessian.io.Hessian2Input.readInt Hessian2Input. Java: (773) ~ [dubbo - 2.8.4 a. ar: 2.8.4 a] the at com.alibaba.dubbo.common.serialize.support.hessian.Hessian2ObjectInput.readInt(Hessian2ObjectInput.java:58) ~ [dubbo - 2.8.4 a. ar: 2.8.4 a] the at com.alibaba.dubbo.rpc.protocol.dubbo.DecodeableRpcInvocation.decode(DecodeableRpcInvocation.java:106) ~ [dubbo - 2.8.4 a. ar: 2.8.4 a]Copy the code

The first thing THAT came to my mind was to upgrade the consumer dubbo starter to 2.8.4, but this version was not made by Alibaba, so alibaba’s official starter will remain firmly in the latest version of 2.0.0. Dubbo 2.6.0 is only supported.

Look at the mountain is not a mountain, return to the tradition, do not use starter

The first thing I actually tried was to force-reference version 2.8.4 directly from Starter

<dependency> <groupId>com.alibaba.spring.boot</groupId> <artifactId>dubbo-spring-boot-starter</artifactId> <version>2.0.0</version> <exclusions> <groupId>com.alibaba</groupId> <artifactId>dubbo</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>dubbo</artifactId> The < version > 2.8.4 < / version > < / dependency >Copy the code

Unfortunately, it failed shamefully, and the error was reported when starting the consumer end

12:12:01. 733 ERROR [main] org. Springframework. Boot. SpringApplication - Application run failed java.lang.NoClassDefFoundError: com/alibaba/dubbo/qos/server/DubboLogo at com.alibaba.dubbo.spring.boot.context.event.DubboBannerApplicationListener.buildBannerText(DubboBannerApplicationListene r.java:49) at com.alibaba.dubbo.spring.boot.context.event.DubboBannerApplicationListener.onApplicationEvent(DubboBannerApplicationList ener.java:39) at com.alibaba.dubbo.spring.boot.context.event.DubboBannerApplicationListener.onApplicationEvent(DubboBannerApplicationList ener.java:23) at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.j ava:172) at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.jav a:165) at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.jav a:139) at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.jav a:127) at org.springframework.boot.context.event.EventPublishingRunListener.environmentPrepared(EventPublishingRunListener.java:76 ) at org.springframework.boot.SpringApplicationRunListeners.environmentPrepared(SpringApplicationRunListeners.java:53) at org.springframework.boot.SpringApplication.prepareEnvironment(SpringApplication.java:345) at org.springframework.boot.SpringApplication.run(SpringApplication.java:308) at org.springframework.boot.SpringApplication.run(SpringApplication.java:1226) at org.springframework.boot.SpringApplication.run(SpringApplication.java:1215) at com.skyblue.dubbodemo.DubbodemoClientApplication.main(DubbodemoClientApplication.java:13)Copy the code

There is a DubboLogo error, which we’ll talk about later. Starter: Dubbo2.6.0 has been changed in dubbo2.8.4, so we can’t call starter.

Starter <dependency> <groupId>com.alibaba</groupId> <artifactId>dubbo</artifactId> <version>2.8.4</version> </dependency>Copy the code

Add a dubo-consumer.xml file in the resources/ Spring directory

<? 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://code.alibabatech.com/schema/dubbo"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://code.alibabatech.com/schema/dubbo
http://code.alibabatech.com/schema/dubbo/dubbo.xsd">

    <dubbo:application name="mydubbodemo"/ > <! -- Registry configuration, using the ZooKeeper registry to expose service address --> <dubbo:registry id="registry1" address=Zookeeper: / / "127.0.0.1:2181" timeout="60000" />

    <dubbo:consumer timeout="120000" retries="0" check="false"/>
    <dubbo:reference interface="com.skyblue.dubbodemo.service.IHelloService" registry="registry1" id="helloService"/>
</beans>Copy the code

Then add the XML file to the startup file on the consumer side

@SpringBootApplication
@ImportResource("classpath:spring/dubbo-consumer.xml") class DubbodemoClientApplication{ public static void main(String[] args) { SpringApplication.run(DubbodemoClientApplication.class, args); }}Copy the code

The class that calls the service changes to the traditional import method

   @Autowired
    private IHelloService helloService;Copy the code

This will allow you to use dubbo version 2.8.4.

However, this method requires that I explicitly declare the service I need to invoke in XML, and it is much less convenient than invoking the service directly with the @reference annotation. Although it is now available, I still miss starter…

A starter is a mountain or a mountain

If you read my previous article, you should know that starter is a very simple specification that allows developers to customize their own starter. Since the official does not support it, we can change a starter by ourselves. I took the official dubbo starter version 2.0.0 to change. Clone a copy of the official version here.

The first thing you need to do is upgrade the POM.xml dubbo version to 2.8.4, but when you do, you’ll see an error. Is this class DubboBannerApplicationListener error

bannerTextBuilder.append(DubboSpringBootStarterConstants.LINE_SEPARATOR).append(DubboLogo.dubbo)
        .append(" :: Dubbo :: (v").append(Version.getVersion()).append(")")
        .append(DubboSpringBootStarterConstants.LINE_SEPARATOR);Copy the code

The DubboLogo class was removed from the console in the background, so there is an error. We forced the dubbo update on the consumer side, which is the same error that launched The Times.

Then we changed the POM.xml file again, upgrading the Spring Boot and JDK versions as well

<properties> ... < Java version > 1.8 < / Java version > < spring - the boot. Version > 2.2.1. RELEASE < / spring - the boot. Version > < dubbo version > 2.8.4 a < / dubbo version >... </properties>Copy the code

This completes the transformation of a Dubbo Starter that can be used under version 2.8.4a.

4. Use it

Dubo-spring-boot-starter -2.8.4a.jar (MVN package) However, this method is not commonly used in software development nowadays. Most of the method is published to Maven’s Nexus private server. The first step is to change pom.xml

<distributionManagement> <snapshotRepository> <id>snapshots</id> The < url > http:// private servers IP: port/nexus/content/repositories/snapshots < / url > < / snapshotRepository > < repository > < id > releases < / id > The < url > http:// private servers IP: port/nexus/content/repositories/releases < / url > < / repository > < / distributionManagement >Copy the code

The maven setting. XML file should also be configured:

< Servers > <server> < ID > Releases </ ID > <username> Account </username> < Password > Password </password> </server> <server> <id>snapshots</id> <username>admin</username> <password>admin123</password> </server> </servers>Copy the code

Then execute MVN deploy to publish to private server. If Deploy has reported this error

[ERROR] Failed to execute goal. Org. Apache maven. Plugins: maven GPG -- plugin: 1.6: sign (sign - artifacts) on the project dubbo-spring-boot-starter: Unable to execute gpgcommand: Error while executing process. Cannot run program "gpg.exe": CreateProcess Error =2, the system cannot find the specified file. -> [Help 1]Copy the code

Because the GPG signature was called when deploy was deployed, we don’t need it on private servers, so I just removed it from pom.xml

<plugin>
				<artifactId>maven-gpg-plugin</artifactId>
				<version>${maven-gpg-plugin.version}</version>
				<configuration>
					<skip>false</skip>
				</configuration>
				<executions>
					<execution>
						<id>sign-artifacts</id>
						<phase>verify</phase>
						<goals>
							<goal>sign</goal>
						</goals>
					</execution>
				</executions>
			</plugin>Copy the code

This section is removed and can be referenced directly in the project’s POM.xml after successful publication.

Modified starter source code