结合本人不成熟的实际应用简单分析一下几种Dubbo服务运行的方式

使用Servlet容器

运行在Tomcat、Jetty等容器中,不需要做很多额外的处理,比较方便,但是比较浪费资源,本身容器的很多功能都是浪费,而且容器需要额外占用端口。

自建Main方法、Test方法

直接启动Spring容器,一般在测试环境下进行,结合Junit、Spring-test可以在开发的时候比较快速地把服务跑起来,启动也比较快,但是比较丑陋,不适用于实际应用环境。启动测试示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:spring-dao.xml",
"classpath:spring-trans.xml",
"classpath:spring-service.xml",
"classpath:spring-redis.xml"})
@WebAppConfiguration
public class ServiceTest {
@Autowired
WebApplicationContext context;

@Test
public void RunService() throws IOException {
System.out.println("服务已启动...");
Scanner sc = new Scanner(System.in);
sc.next();
System.out.println("服务已关闭...");
}
}

Dubbo提供的Main方法

Dubbo本身提供了一个启动的Main方法,比较突出的优点是使用ShutdownHook实现了优雅关机,而且加载内容可以扩展。

如果要使用这种方法需要对项目的打包做一些处理,打成jar包部署运行。以Maven为例,需要在POM文件中添加如下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
<build>  
<finalName>mydubbo-server</finalName>

<resources>
<resource>
<!-- 除了spring配置文件意外的其他资源文件打包 -->
<targetPath>${project.build.directory}/classes</targetPath>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<includes>
<include>others/*.xml</include>
<include>**/*.properties</include>
</includes>
</resource>
<resource>
<!-- spring配置文件打包路径,这个路径固定,在框架源码中可以看到 -->
<targetPath>${project.build.directory}/classes/META-INF/spring</targetPath>
<directory>src/main/resources/spring</directory>
<filtering>true</filtering>
<includes>
<include>spring-*.xml</include>
</includes>
</resource>
</resources>


<plugins>
<!-- 框架Main方法作为主类打包jar,配置manifest文件,加入lib包的jar依赖 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<classesDirectory>target/classes/</classesDirectory>
<archive>
<manifest>
<mainClass>com.alibaba.dubbo.container.Main</mainClass>
<!-- 打包时 MANIFEST.MF文件不记录的时间戳版本 -->
<useUniqueVersions>false</useUniqueVersions>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
</manifest>
<manifestEntries>
<Class-Path>.</Class-Path>
</manifestEntries>
</archive>
</configuration>
</plugin>
<!-- maven依赖插件,拷贝依赖的包到指定目录 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>copy-dependencies</id>
<!-- 指定在package之前执行 -->
<phase>prepare-package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<type>jar</type>
<includeTypes>jar</includeTypes>
<outputDirectory>${project.build.directory}/lib </outputDirectory>
<overWriteReleases>false</overWriteReleases>
<overWriteSnapshots>false</overWriteSnapshots>
<overWriteIfNewer>true</overWriteIfNewer>
<includeScope>compile</includeScope>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>

然后运行maven命令打出jar包,成功后可以在模块或者工程的target目录下看到生成的lib文件夹和生成的jar包。

如果是在windows下,可以在该目录下运行命令行,然后输入java -jar jar包名,回车可以看到服务开始启动,也可以在监控中心看到服务已经部署。如果是Linux可以写一个简单的启动脚本java -jar XXX.jar > "log.log" 2>&1来运行。

其实框架jar包里面的META-INF/assembly.bin目录下有已经写好的批处理和Bash文件可以直接拿来用。

最后是服务的停止,windows下看了看就是直接关闭命令窗口吧。Linux下使用Kill PID即可正常结束容器运行,注意不要使用kill -9 PID强制关闭,这样不会执行优雅停机。

总结

总的来说和网上大部分内容比较相似,做的时候也是一步一步查过来的。想看看为什么默认采用Spring的Container来运行容器,简单看了一下main方法,比较明显的是定义的CONTAINER_KEY(dubbo.container),但是包里并没有任何相关文件,尝试debug了一把流程,粗略看下来应该是从dubbo.internal目录下的com.alibaba.dubbo.common.extension.ExtensionFactory这个文件里读的内容最后得到了这个”spring”,不过没有继续深究下去。

至于其他的Jetty、log容器目前没有进一步尝试。