美文网首页Java Spring MVC
基于注解方式的dubbo+spring mvc整合

基于注解方式的dubbo+spring mvc整合

作者: 木子小三金 | 来源:发表于2017-11-06 17:12 被阅读65次

    最近项目使用了dubbo进行服务治理,搭建了一套基于注解方式的dubbo+spring mvc的框架,注册中心使用zookeeper。
    关于dubbo的介绍就不多说了,网上有很多可以自行搜索,直接上代码。

    项目使用的maven,采用多模块方式。先看一下示例项目框架。


    image.png

    其中dubbo-config模块管理所有项目所需的配置文件,在打包时打入对应的服务内。

    一、项目包依赖 pom.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
    
        <groupId>com.sanjinbest.dubbo</groupId>
        <artifactId>sanjinbest.dubbo</artifactId>
        <packaging>pom</packaging>
        <version>1.0-SNAPSHOT</version>
        <modules>
            <module>user-service</module>
            <module>dubbo-web</module>
            <module>dubbo-config</module>
        </modules>
    
        <properties>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
            <servlet.version>3.0.1</servlet.version>
            <springframework.version>4.3.7.RELEASE</springframework.version>
            <junit.version>4.12</junit.version>
            <zookeeper.version>0.2</zookeeper.version>
            <dubbo.version>2.5.4</dubbo.version>
        </properties>
    
        <dependencyManagement>
            <dependencies>
                <!-- Dubbo相关 -->
                <dependency>
                    <groupId>com.alibaba</groupId>
                    <artifactId>dubbo</artifactId>
                    <version>${dubbo.version}</version>
                    <exclusions>
                        <exclusion>
                            <groupId>org.springframework</groupId>
                            <artifactId>spring</artifactId>
                        </exclusion>
                    </exclusions>
                </dependency>
    
                <!-- ZK-client -->
                <dependency>
                    <groupId>com.101tec</groupId>
                    <artifactId>zkclient</artifactId>
                    <version>${zookeeper.version}</version>
                </dependency>
    
                <!-- servlet -->
                <dependency>
                    <groupId>javax.servlet</groupId>
                    <artifactId>javax.servlet-api</artifactId>
                    <version>${servlet.version}</version>
                </dependency>
                <dependency>
                    <groupId>junit</groupId>
                    <artifactId>junit</artifactId>
                    <version>${junit.version}</version>
                    <scope>test</scope>
                </dependency>
    
                <dependency>
                    <groupId>org.hamcrest</groupId>
                    <artifactId>hamcrest-core</artifactId>
                    <version>1.3</version>
                </dependency>
    
                <!-- spring -->
                <dependency>
                    <groupId>org.springframework</groupId>
                    <artifactId>spring-core</artifactId>
                    <version>${springframework.version}</version>
                </dependency>
                <dependency>
                    <groupId>org.springframework</groupId>
                    <artifactId>spring-context</artifactId>
                    <version>${springframework.version}</version>
                </dependency>
                <dependency>
                    <groupId>org.springframework</groupId>
                    <artifactId>spring-web</artifactId>
                    <version>${springframework.version}</version>
                </dependency>
                <dependency>
                    <groupId>org.springframework</groupId>
                    <artifactId>spring-beans</artifactId>
                    <version>${springframework.version}</version>
                </dependency>
                <dependency>
                    <groupId>org.springframework</groupId>
                    <artifactId>spring-aop</artifactId>
                    <version>${springframework.version}</version>
                </dependency>
                <dependency>
                    <groupId>org.springframework</groupId>
                    <artifactId>spring-expression</artifactId>
                    <version>${springframework.version}</version>
                </dependency>
                <dependency>
                    <groupId>org.springframework</groupId>
                    <artifactId>spring-aspects</artifactId>
                    <version>${springframework.version}</version>
                </dependency>
                <dependency>
                    <groupId>org.springframework</groupId>
                    <artifactId>spring-context-support</artifactId>
                    <version>${springframework.version}</version>
                </dependency>
                <dependency>
                    <groupId>org.springframework</groupId>
                    <artifactId>spring-tx</artifactId>
                    <version>${springframework.version}</version>
                </dependency>
                <dependency>
                    <groupId>org.springframework</groupId>
                    <artifactId>spring-webmvc</artifactId>
                    <version>${springframework.version}</version>
                </dependency>
                <dependency>
                    <groupId>org.springframework</groupId>
                    <artifactId>spring-test</artifactId>
                    <version>${springframework.version}</version>
                </dependency>
                <dependency>
                    <groupId>org.springframework.mobile</groupId>
                    <artifactId>spring-mobile-device</artifactId>
                    <version>${spring.mobile.version}</version>
                </dependency>
                <dependency>
                    <groupId>org.springframework</groupId>
                    <artifactId>spring-jdbc</artifactId>
                    <version>${springframework.version}</version>
                </dependency>
            </dependencies>
        </dependencyManagement>
    </project
    

    二、dubbo服务端

    1、服务端配置

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
           xmlns="http://www.springframework.org/schema/beans"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
        http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
    
        <!-- 提供方应用信息,用于计算依赖关系 -->
        <dubbo:application name="user-provider"/>
    
        <!-- 使用zookeeper注册中心暴露服务地址 -->
        <dubbo:registry protocol="zookeeper" address="${dubbo.user.registry.server}" />
    
        <!-- 使用dubbo协议,所以请求响应都使用线程池管理 -->
        <dubbo:protocol name="dubbo" dispatcher="all" port="${dubbo.user.protocol.port}"/>
    
        <!-- 声明需要暴露的服务接口 -->
        <dubbo:annotation/>
    
        <!-- 延迟加载,等待spring初始化完成后暴露服务 -->
        <dubbo:provider delay="-1" timeout="${dubbo.user.timeout}" retries="${dubbo.user.retries}" />
    
    </beans>
    

    这里使用的注册中心是zookeeper。

    2、服务端applicationContext.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:context="http://www.springframework.org/schema/context"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context.xsd">
    
        <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
            <property name="ignoreUnresolvablePlaceholders" value="true"/>
            <property name="locations">
                <list>
                    <value>classpath*:dubbo.properties</value>
                </list>
            </property>
        </bean>
        <!-- dubbo 服务 -->
        <import resource="classpath*:dubbo/user-provider.xml"/>
        <!-- 开启注解 -->
        <context:annotation-config/>
        <!-- 自动扫描 -->
        <context:component-scan base-package="com.sanjinbest.dubbo.user" />
    
    </beans>
    

    3、服务接口类

    package com.sanjinbest.dubbo.user.api;
    
    /**
     * <li></li>
     *
     * @author lixin
     * @create 2017/11/3
     */
    public interface IUserInfoService {
    
        String getName();
    
        int getAge();
    }
    

    这里提供了一个返回name 和 age的方法。当发布服务给第三方的时候,只需要将该接口打成jar包发布即可。

    4、接口实现类

    package com.sanjinbest.dubbo.user.provider;
    
    import com.sanjinbest.dubbo.user.api.IUserInfoService;
    
    /**
     * <li></li>
     *
     * @author lixin
     * @create 2017/11/3
     */
    
    @com.alibaba.dubbo.config.annotation.Service
    @org.springframework.stereotype.Service
    public class UserInfoServiceProvider implements IUserInfoService{
    
        @Override
        public String getName() {
            return "sanjinbest";
        }
    
        @Override
        public int getAge() {
            return 29;
        }
    }
    

    这里有一个需要注意的地方,该实现类内使用了2个service注解:
    @com.alibaba.dubbo.config.annotation.Service dubbo服务对外暴露服务
    @org.springframework.stereotype.Service spring容器注入

    5、dubbo本地测试启动

    package mock;
    
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    import java.io.IOException;
    
    /**
     * <li></li>
     *
     * @author lixin
     * @create 2017/9/18
     */
    public class UserProviderMock {
    
        public static void main(String[] args) {
            ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"classpath*:spring/applicationContext.xml"});
    
            System.out.println("user provider start...");
            context.start();
            try {
                System.in.read();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    

    如果是线上使用,可以使用运行jar包的方式运行,下面是打jar包的配置:

    <!-- 打包 -->
        <build>
            <!-- 与服务模块名称一致 -->
            <finalName>user-provider</finalName>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-jar-plugin</artifactId>
                    <version>3.0.2</version>
                    <configuration>
                        <classesDirectory>${project.build.directory}/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>
    
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-dependency-plugin</artifactId>
                    <executions>
                        <execution>
                            <id>copy-dependencies</id>
                            <phase>package</phase>
                            <goals>
                                <goal>copy-dependencies</goal>
                            </goals>
                            <configuration>
                                <type>jar</type>
                                <includeTypes>jar</includeTypes>
                                <outputDirectory>
                                    ${project.build.directory}/lib
                                </outputDirectory>
                                <excludeTransitive>false</excludeTransitive>
                                <overWriteReleases>true</overWriteReleases>
                                <overWriteSnapshots>true</overWriteSnapshots>
                                <overWriteIfNewer>true</overWriteIfNewer>
                                <stripVersion>false</stripVersion>
                            </configuration>
                        </execution>
                    </executions>
                </plugin>
            </plugins>
    
            <resources>
                <resource>
                    <directory>../../dubbo-config/config/</directory>
                </resource>
                <!--recources文件夹下的所有文件都打进jar包-->
                <resource>
                    <targetPath>${project.build.directory}/classes</targetPath>
                    <directory>src/main/resources</directory>
                    <filtering>true</filtering>
                    <includes>
                        <include>**/*.xml</include>
                        <include>**/*.properties</include>
                    </includes>
                </resource>
                <!-- 由于com.alibaba.dubbo.container.Main默认寻找META-INF下的applicationContext.xml,固将 applicationContext.xml文件拷贝到META-INF目录下-->
                <resource>
                    <targetPath>${project.build.directory}/classes/META-INF/spring</targetPath>
                    <directory>src/main/resources/spring</directory>
                    <filtering>true</filtering>
                    <includes>
                        <include>applicationContext.xml</include>
                    </includes>
                </resource>
            </resources>
        </build>
    

    最后看一下dubbo的配置参数:

    #服务注册中心(如果注册中心为集群,这里需要使用“,”分隔)
    dubbo.user.registry.server=127.0.0.1:2181
    #服务暴露端口
    dubbo.user.protocol.port=20080
    #请求超时时间
    dubbo.user.timeout=3000
    #请求失败重试次数
    dubbo.user.retries=0
    #客户端(如果订阅的服务为集群,这里需要使用“,”分隔)
    dubbo.user.client=127.0.0.1:2181
    

    到此,一个简单的dubbo服务就搭建好了,我们启动一下看看。
    直接运行类UserProviderMock.java

    image.png

    如果看到"user provider start..."就证明启动成功了!
    下面我们来看一下dubbo的客户端。

    三、dubbo客户端

    1、dubbo客户端配置

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
           xmlns="http://www.springframework.org/schema/beans"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
           http://code.alibabatech.com/schema/dubbo
           http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
    
        <!-- 提供方应用信息,用于计算依赖关系 -->
        <dubbo:application name="fund-baby-reference"/>
    
        <!-- 使用zookeeper注册中心暴露服务地址,如果使用多个服务,需要配置多个客户端 -->
        <dubbo:registry id="account-client" protocol="zookeeper" address="${dubbo.user.client}" />
    
        <!-- 设置所有服务的启动时检查 (依赖服务不可用时会抛出异常): -->
        <dubbo:consumer check="true" />
    
        <dubbo:annotation/>
    </beans>
    

    然后将其import进入applicationContext.xml即可。
    先跑一下单元测试。

    2、单元测试

    package com.sanjinbest.dubbo.mock;
    
    import com.alibaba.dubbo.config.annotation.Reference;
    import com.sanjinbest.dubbo.user.api.IUserInfoService;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    
    /**
     * <li></li>
     *
     * @author lixin
     * @create 2017/9/18
     */
    @RunWith(SpringJUnit4ClassRunner.class)  //使用junit4进行测试
    @ContextConfiguration(locations={"classpath*:spring/applicationContext.xml"}) //加载配置文件
    public class MockDubbo {
    
        @Reference
        private IUserInfoService iUserInfoService;
    
        @Test
        public void test(){
            System.out.println("Hello : " + iUserInfoService.getName());
            System.out.println("age : " + iUserInfoService.getAge());
        }
    }
    
    image.png

    3、与spring mvc结合

    完成了单元测试,在尝试与spring mvc进行结合使用。与spring mvc的结合用其实非常简单,spring mvc的配置不变,只需要将spring-mvc与dubbo配置都交给applictionContext.xml进行管理就好。
    spring-mvc.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:p="http://www.springframework.org/schema/p"
           xmlns:context="http://www.springframework.org/schema/context"
           xmlns:mvc="http://www.springframework.org/schema/mvc"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
                            http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
                            http://www.springframework.org/schema/context
                            http://www.springframework.org/schema/context/spring-context-3.1.xsd
                            http://www.springframework.org/schema/mvc
                            http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd">
    
        <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping" />
        <bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor" />
    
        <!-- 开启注解 -->
        <mvc:annotation-driven/>
    
        <!-- 定义跳转的文件的前后缀 ,视图模式配置-->
        <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
            <!-- 这里的配置我的理解是自动给后面action的方法return的字符串加上前缀和后缀,变成一个 可用的url地址 -->
            <property name="prefix" value="/WEB-INF/pages/" />
            <property name="suffix" value=".jsp" />
        </bean>
    
    </beans>
    

    applictionContext.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:context="http://www.springframework.org/schema/context"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context.xsd">
    
        <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
            <property name="ignoreUnresolvablePlaceholders" value="true"/>
            <property name="locations">
                <list>
                    <value>classpath*:dubbo.properties</value>
                </list>
            </property>
        </bean>
    
        <!-- dubbo 服务客户端 -->
        <import resource="classpath*:spring/fund-baby-reference.xml" />
        <!-- spring mvc 配置 -->
        <import resource="classpath*:spring/spring-mvc.xml" />
    
        <!-- 开启注解 -->
        <context:annotation-config/>
        <!--自动扫描-->
        <context:component-scan base-package="com.sanjinbest.dubbo" />
    </beans>
    

    web.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xmlns="http://java.sun.com/xml/ns/javaee
    http://www.springmodules.org/schema/cache/springmodules-cache.xsd
    http://www.springmodules.org/schema/cache/springmodules-ehcache.xsd"
             xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
    http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
             metadata-complete="true">
    
      <filter>
        <filter-name>encodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <async-supported>true</async-supported>
        <init-param>
          <param-name>encoding</param-name>
          <param-value>UTF-8</param-value>
        </init-param>
      </filter>
      <filter-mapping>
        <filter-name>encodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
      </filter-mapping>
    
      <servlet>
        <servlet-name>SpringMVC</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!-- 此处直接加载applicationContext.xml spring-mvc.xml在applicationContext.xml内加载 -->
        <init-param>
          <param-name>contextConfigLocation</param-name>
          <param-value>classpath*:spring/applicationContext.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
        <async-supported>true</async-supported>
      </servlet>
      <servlet-mapping>
        <servlet-name>SpringMVC</servlet-name>
        <url-pattern>/</url-pattern>
      </servlet-mapping>
    
      <display-name>Archetype Created Web Application</display-name>
    
    </web-app>
    
    

    在看一下测试的controller和service

    package com.sanjinbest.dubbo.controller;
    
    import com.sanjinbest.dubbo.service.IndexService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    import org.springframework.web.bind.annotation.ResponseBody;
    
    /**
     * <li></li>
     *
     * @author lixin
     * @create 2017/11/6
     */
    @Controller
    public class IndexController{
    
        @Autowired
        private IndexService indexService;
    
        @RequestMapping(value="/user",method = RequestMethod.GET)
        @ResponseBody
        public String user(){
            return indexService.userInfo();
        }
    
    }
    

    controller的写法没有特殊变化,主要看一下service的。

    package com.sanjinbest.dubbo.service;
    
    import com.alibaba.dubbo.config.annotation.Reference;
    import com.sanjinbest.dubbo.user.api.IUserInfoService;
    import org.springframework.stereotype.Service;
    
    /**
     * <li></li>
     *
     * @author lixin
     * @create 2017/11/6
     */
    @Service
    public class IndexService {
    
        @Reference
        private IUserInfoService iUserInfoService;
    
        public String userInfo(){
            return iUserInfoService.getName() + "," + iUserInfoService.getAge();
        }
    }
    
    

    service这里注入dubbo接口,需要使用注解@Reference
    启动后看一下测试结果:

    image.png

    最后,我们看一下dubbo-admin后台。
    dubbo-admin.war可以在dubbo的官网上下载,下载后放到tomcat webapps内,解压war包,修改配置文件webapps/dubbo-admin/WEB-INF/dubbo.properties
    设置dubbo.registry.address参数,我使用的是本地的zookeeper。

      dubbo.registry.address=zookeeper://127.0.0.1:2181
      dubbo.admin.root.password=root
      dubbo.admin.guest.password=guest
    

    启动tomcat,然后请求地址http://127.0.0.1:8080/dubbo-admin/
    用户名和密码都是root。
    dubbo-admin的功能有很多,就不作详细说明了,到此一个使用dubbo服务的spring mvc示例就介绍结束。
    本文只对dubbo的搭建作一个初步的介绍,后续会有一些dubbo的线上使用介绍。
    示例项目下载地址 : https://pan.baidu.com/s/1nvj3XpB 密码: 46vr

    写的比较粗糙,可能会存在一些错误。欢迎大家反馈交流。

    相关文章

      网友评论

        本文标题:基于注解方式的dubbo+spring mvc整合

        本文链接:https://www.haomeiwen.com/subject/rilapxtx.html