一个完整的dubbo服务应该是由服务提供者、服务消费者、服务接口API三者构成的,我在做dubbo服务的demo 的时候把服务提供者和服务消费者作为两个web工程,而服务接口API作为一个普通的maven 工程,把它打成jar 包由另外两个工程引用,服务消费者web工程里面有处理http 请求的操作,是一个标准的spring mvc 工程,服务提供者web工程是一个spring mvc+mybatis 的工程,在服务提供者web 工程中并没有使用spring mvc 的功能,web.xml 中配置了spring 上下文监听器用来读取对应的配置,这样的dubbo服务放在web 服务器(tomcat)下面运行是没有任何问题的。但是感觉把这样一个dubbo服务提供者作为一个web工程来运行有点鸡肋,因为web服务器只是作为dubbo服务启动的入口而已,那么为何不能把这样的dubbo服务做成一个普通的java 工程,然后提供启动的入口来运行呢?
其实dubbo 源码中已经有对应的例子,例如dubbo-monitor-simple这个简单的监控器,他就是一个可执行的java应用,解压build后的
dubbo-monitor-simple-2.5.4-SNAPSHOT-assembly.tar.gz 文件,我们发现目录结构如下:
bin 目录下面存放的是这个dubbo服务启动的配置文件(windows/linux),conf目录下面只有一个dubbo.properties属性文件用来更改dubbo服务的配置,lib下面是包括这个project build后的jar和maven 所依赖的jar,bin 目录下面的文件见:
在windows 下面双击start.bat文件,这个服务就能启动起来,下面来构建自己的工程。
做这个之前我们需要了解另外一个dubbo源码的demo,它就是:dubbo-demo-provider 工程,这个工程也是一个可执行的java应用,而且我们可以通过eclipse来直接启动这个dubbo服务,见:
通过运行DemoProvider.java 这个文件,这个dubbo服务起来了,其中有这样一句demo:
com.alibaba.dubbo.container.Main.main(args);
额,这句话明显是调用dubbo自己写的类的一个方法,打开这个类看到:
public class Main {
public static final String CONTAINER_KEY = "dubbo.container";
public static final String SHUTDOWN_HOOK_KEY = "dubbo.shutdown.hook";
private static final Logger logger = LoggerFactory.getLogger(Main.class);
private static final ExtensionLoader<Container> loader = ExtensionLoader.getExtensionLoader(Container.class);
private static volatile boolean running = true;
public static void main(String[] args) {
try {
if (args == null || args.length == 0) {
String config = ConfigUtils.getProperty(CONTAINER_KEY, loader.getDefaultExtensionName());
args = Constants.COMMA_SPLIT_PATTERN.split(config);
}
final List<Container> containers = new ArrayList<Container>();
for (int i = 0; i < args.length; i ++) {
containers.add(loader.getExtension(args[i]));
}
.................................................................................................................................
这个里面加载dubbo一个容器,但是我们调用的时候并没有指定哪个容器,看过dubbo SPI机制就知道这个容器肯定是spring容器,而且
dubbo-demo-provider 工程的src\main\resources\META-INF\spring存放了dubbo服务的配置文件,在看看dubbo spring容器的加载文件位置:
/*
* Copyright 1999-2011 Alibaba Group.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.dubbo.container.spring;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.alibaba.dubbo.common.extension.ExtensionLoader;
import com.alibaba.dubbo.common.logger.Logger;
import com.alibaba.dubbo.common.logger.LoggerFactory;
import com.alibaba.dubbo.common.utils.ConfigUtils;
import com.alibaba.dubbo.container.Container;
/**
* SpringContainer. (SPI, Singleton, ThreadSafe)
*
* @author william.liangf
*/
public class SpringContainer implements Container {
private static final Logger logger = LoggerFactory.getLogger(SpringContainer.class);
public static final String SPRING_CONFIG = "dubbo.spring.config";
public static final String DEFAULT_SPRING_CONFIG = "classpath*:META-INF/spring/*.xml";
static ClassPathXmlApplicationContext context;
public static ClassPathXmlApplicationContext getContext() {
return context;
}
public void start() {
String configPath = ConfigUtils.getProperty(SPRING_CONFIG);
if (configPath == null || configPath.length() == 0) {
configPath = DEFAULT_SPRING_CONFIG;
}
context = new ClassPathXmlApplicationContext(configPath.split("[,\\s]+"));
context.start();
}
public void stop() {
try {
if (context != null) {
context.stop();
context.close();
context = null;
}
} catch (Throwable e) {
logger.error(e.getMessage(), e);
}
}
}
这个spring容器加载配置文件的默认位置就是 src\main\resources\META-INF\spring目录下面的文件,当然也可以在dubbo.properties文件中修改加载文件的位置,通过添加: dubbo.spring.config=XXX 来指定。
明白以上原理后我们来建立一个基于spring的dubbo服务就简单了,下面是建立步骤:
1、创建一个普通的Maven java project。
2、添加maven 依赖,编写业务处理逻辑。
3、配置project 相关的配置文件,例如数据库连接、系统配置文件,dubbo服务配置文件,这些文件应该放在src\main\resources\META-INF\spring 目录下面。
这样就基本完成了,但是maven build后只是打成了jar 包,并没有dubbo 源代码例子中的XXXX-assembly.tar.gz文件,那怎样实现这个呢?这个需要maven-assembly-plugin 插件完成,pom.xml配置如下
<!-- build属性设置 --> <build> <finalName>yt-service-application-user</finalName> <sourceDirectory>src/main/java</sourceDirectory> <plugins> <plugin> <artifactId>maven-compiler-plugin</artifactId> <version>3.1</version> <configuration> <source>1.7</source> <target>1.7</target> <encoding>UTF-8</encoding> <compilerArguments> <verbose /> <bootclasspath>${java.home}/lib/rt.jar;${java.home}/lib/jce.jar</bootclasspath> </compilerArguments> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-dependency-plugin</artifactId> <executions> <execution> <id>unpack</id> <phase>package</phase> <goals> <goal>unpack</goal> </goals> <configuration> <artifactItems> <artifactItem> <groupId>com.hzlh</groupId> <artifactId>yt-common-config</artifactId> <version>0.0.1-SNAPSHOT</version> <type>jar</type> <overWrite>true</overWrite> <outputDirectory>${basedir}/src/main/resources/META-INF</outputDirectory> <includes>**/system/*.properties,**/spring/*.xml</includes> </artifactItem> <artifactItem> <groupId>com.hzlh</groupId> <artifactId>yt-service-application-user</artifactId> <version>0.0.1-SNAPSHOT</version> <outputDirectory>${project.build.directory}/dubbo</outputDirectory> <includes>META-INF/assembly/**</includes> </artifactItem> </artifactItems> </configuration> </execution> </executions> </plugin> <plugin> <artifactId>maven-assembly-plugin</artifactId> <configuration> <descriptor>src/main/assembly/assembly.xml</descriptor> </configuration> <executions> <execution> <id>make-assembly</id> <phase>package</phase> <goals> <goal>single</goal> </goals> </execution> </executions> </plugin> </plugins> <resources> <resource> <directory>src/main/resources</directory> <includes> <include>**/*.properties</include> <include>**/*.xml</include> <include>**/*.tld</include> </includes> <filtering>false</filtering> </resource> <resource> <directory>src/main/java</directory> <includes> <include>**/*.properties</include> <include>**/*.xml</include> <include>**/*.tld</include> </includes> <filtering>false</filtering> </resource> </resources> </build>
其中红色部分配置就是插件配置,橙色部分配置是解压一个jar包中的配置文件到当前目录下面,应为我把配置文件单独作为一个工程抽出来,在这个工程里面引用了配置文件工程的jar包,所以需要解压。
来看看红色部分的配置:它需要
<descriptor>src/main/assembly/assembly.xml</descriptor>
这个目录下面的描述文件,我们可以把dubbo-monitor-simple这个工程下面这个文件copy 过来,打开assembly.xml 文件如下:
<!-- - Copyright 1999-2011 Alibaba Group. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. --> <assembly> <id>assembly</id> <formats> <format>tar.gz</format> </formats> <includeBaseDirectory>true</includeBaseDirectory> <fileSets> <fileSet> <directory>${basedir}/src/main/resources/assembly/bin</directory> <outputDirectory>bin</outputDirectory> <fileMode>0755</fileMode> </fileSet> <fileSet> <directory>src/main/assembly/conf</directory> <outputDirectory>conf</outputDirectory> <fileMode>0644</fileMode> </fileSet> </fileSets> <dependencySets> <dependencySet> <outputDirectory>lib</outputDirectory> </dependencySet> </dependencySets> </assembly>
这里指定可执行文件的存放位置,配置文件的存放位置,以及依赖的jar存放的位置。${basedir}/src/main/resources/assembly/bin 这里指定了可执行文件读取的位置,我们的project中是没有这些文件的,可以直接从dubbo-monitor-simple目录下面copy过来,然后整个项目的结构如下:
在用maven install 后就会发现在target目录下面有对应的可执行文件包。