前言: 本文将使用
springboot+dubbo+zookeeper+maven
搭建一套微服务。
需要提前在本地配置的环境:
- maven环境
- zookeeper环境(在我本地zookeeper在2181端口)
- jdk……
完成项目下载地址
user-module | user-app | user-service-api |
---|---|---|
用户模块(父目录) | 用户对外api子模块 | 程序内部调用的用户api模块(jar) |
注意: 其中 user-module父模块 和 user-service-api 自模块 不需要对外提供访问,所以不需要提供启动类,也不需要web和相关的依赖。 只有对外提供访问的 user-app才需要各种maven类,包括 web 、dubbo等。
说明: 这个模块的 配置文件等都是空的,也基本没有相关的maven依赖。对外本程序提供api。
注意: 本模块的输出类:即
vo
文件夹下的实体类,例如: UserVo.java。一定要实现:Serializable
序列化接口,另外这个类是和 user-app 中的实体类User.java
一模一样的。(只是名字不一样,UserVo实现了序列化接口,仅此而已,其他都一样)
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.2.2.RELEASEversion>
<relativePath/>
parent>
<groupId>com.itzhongzigroupId>
<artifactId>user-service-apiartifactId>
<version>0.0.1-SNAPSHOTversion>
<name>user-service-apiname>
<description>Demo project for Spring Bootdescription>
<properties>
<java.version>1.8java.version>
properties>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starterartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
<exclusions>
<exclusion>
<groupId>org.junit.vintagegroupId>
<artifactId>junit-vintage-engineartifactId>
exclusion>
exclusions>
dependency>
dependencies>
<build>
build>
project>
package com.itzhongzi.userserviceapi.service;
import com.itzhongzi.userserviceapi.vo.UserVo;
/**
* @description:
* @author: lihongwei
* @time: 2020/1/8 2:18 下午
*/
public interface IUserService {
public UserVo getUserById(Integer id);
}
package com.itzhongzi.userserviceapi.vo;
import java.io.Serializable;
/**
* @description:
* @author: lihongwei
* @time: 2020/1/8 2:19 下午
*/
public class UserVo implements Serializable {
private int age;
private String name;
private String sex;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
@Override
public String toString() {
return "User{" +
"age=" + age +
", name='" + name + '\'' +
", sex='" + sex + '\'' +
'}';
}
}
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.2.2.RELEASEversion>
<relativePath/>
parent>
<groupId>com.itzhongzigroupId>
<artifactId>user-appartifactId>
<version>0.0.1-SNAPSHOTversion>
<name>user-appname>
<description>Demo project for Spring Bootdescription>
<properties>
<java.version>1.8java.version>
properties>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-devtoolsartifactId>
<scope>runtimescope>
<optional>trueoptional>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
<exclusions>
<exclusion>
<groupId>org.junit.vintagegroupId>
<artifactId>junit-vintage-engineartifactId>
exclusion>
exclusions>
dependency>
<dependency>
<groupId>com.itzhongzigroupId>
<artifactId>user-service-apiartifactId>
<version>0.0.1-SNAPSHOTversion>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>druidartifactId>
<version>1.1.1version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>5.1.47version>
<optional>trueoptional>
dependency>
<dependency>
<groupId>org.mybatis.generatorgroupId>
<artifactId>mybatis-generator-coreartifactId>
<scope>testscope>
<version>1.3.2version>
<optional>trueoptional>
dependency>
<dependency>
<groupId>commons-iogroupId>
<artifactId>commons-ioartifactId>
<version>2.5version>
dependency>
<dependency>
<groupId>org.apache.commonsgroupId>
<artifactId>commons-lang3artifactId>
<version>3.1version>
dependency>
<dependency>
<groupId>org.mybatis.spring.bootgroupId>
<artifactId>mybatis-spring-boot-starterartifactId>
<version>1.3.0version>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
<dependency>
<groupId>org.apache.dubbogroupId>
<artifactId>dubboartifactId>
<version>2.7.2version>
<exclusions>
<exclusion>
<artifactId>springartifactId>
<groupId>org.springframeworkgroupId>
exclusion>
exclusions>
dependency>
<dependency>
<groupId>org.apache.zookeepergroupId>
<artifactId>zookeeperartifactId>
<version>3.4.10version>
<exclusions>
<exclusion>
<artifactId>slf4j-log4j12artifactId>
<groupId>org.slf4jgroupId>
exclusion>
exclusions>
dependency>
<dependency>
<groupId>com.github.sgroschupfgroupId>
<artifactId>zkclientartifactId>
<version>0.1version>
dependency>
<dependency>
<groupId>org.apache.curatorgroupId>
<artifactId>curator-recipesartifactId>
<version>4.0.1version>
dependency>
dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
plugin>
plugins>
build>
project>
project=dubbo
logdir=../logs/${project}
### set log levels ###
log4j.rootLogger = info,stdout,console
# config this project appender,log level:info,error #
log4j.logger.com.ts.report = info,error,bizInfo,bizError
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.Target=System.out
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=%d{yyy-MM-dd HH\:mm\:ss} %5p %c{1}\:%L - %m%n
## \u8F93\u51FA\u5230\u63A7\u5236\u53F0 ###
log4j.appender.stdout=org.apache.log4j.DailyRollingFileAppender
log4j.appender.stdout.File=${logdir}/all.log
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.DatePattern='_'yyyy-MM-dd
log4j.appender.stdout.layout.ConversionPattern=%d{yyy-MM-dd HH\:mm\:ss} %5p %c{1}\:%L - %m%n
# info log everyday file#
log4j.loger.bizInfo = info,bizInfo
log4j.appender.bizInfo=org.apache.log4j.DailyRollingFileAppender
log4j.appender.bizInfo.File=${logdir}/info.log
log4j.appender.bizInfo.layout=org.apache.log4j.PatternLayout
log4j.appender.bizInfo.DatePattern='_'yyyy-MM-dd
log4j.appender.bizInfo.layout.ConversionPattern=%d{yyy-MM-dd HH\:mm\:ss} %5p %c{1}\:%L - %m%n
log4j.appender.bizInfo.Threshold=INFO
#log4j.additivity.bizInfo=false
## error log ##
log4j.loger.bizError = info,bizError
log4j.appender.bizError = org.apache.log4j.DailyRollingFileAppender
log4j.appender.bizError.File = ${logdir}/error.log
log4j.appender.bizError.layout = org.apache.log4j.PatternLayout
log4j.appender.bizError.DatePattern='_'yyyy-MM-dd
log4j.appender.bizError.layout.ConversionPattern =%d{yyy-MM-dd HH\:mm\:ss} %5p %c{1}\:%L - %m%n
log4j.appender.bizError.Threshold = ERROR
#log4j.additivity.error=false
## error log ##
log4j.loger.error = info,error
log4j.appender.error = org.apache.log4j.DailyRollingFileAppender
log4j.appender.error.File = ${logdir}/sys_error.log
log4j.appender.error.layout = org.apache.log4j.PatternLayout
log4j.appender.error.DatePattern='_'yyyy-MM-dd
log4j.appender.error.layout.ConversionPattern =%d{yyy-MM-dd HH\:mm\:ss} %5p %c{1}\:%L - %m%n
log4j.appender.error.Threshold = ERROR
#log4j.additivity.error=false
server:
port: 8086
# dubbo 配置
dubbo:
application:
name: user-app
# 使用 zookeeper 注册中心暴露服务,注意要先开启 zookeeper
# 注册中心id
registry:
id: zookeeper-registry
# 注册中心协议
protocol: zookeeper
# 注册中心地址
address: 127.0.0.1:2181
# dubbo协议在20880端口暴露服务
# 协议名称
protocol:
name: dubbo
# 协议端口 对外提供访问的端口
port: 20880
# 协议访问log
accesslog: dubbo-access.log
# 重试次数
provider:
#重试次数
retries: 0
# 超时时间
timeout: 3000
# 注册监控中心
monitor:
protocol: registry
config-center:
protocol: zookeeper
address: 127.0.0.1:2181
package com.itzhongzi.userapp;
import org.apache.dubbo.config.spring.context.annotation.DubboComponentScan;
import org.apache.dubbo.config.spring.context.annotation.EnableDubboConfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@EnableDubboConfig
@DubboComponentScan("com.itzhongzi.userapp.service.dubbo")
@SpringBootApplication
public class UserAppApplication {
public static void main(String[] args) {
SpringApplication.run(UserAppApplication.class, args);
}
}
package com.itzhongzi.userapp.controller;
import com.itzhongzi.userapp.service.dubbo.UserService;
import com.itzhongzi.userserviceapi.vo.UserVo;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
/**
* @description:
* @author: lihongwei
* @time: 2020/1/8 2:28 下午
*/
@RestController
public class UserController {
@Resource
private UserService userService;
@RequestMapping("/get_user")
public UserVo getUserById(Integer id){
UserVo getUser = userService.getUserById(id);
return getUser;
}
}
package com.itzhongzi.userapp.domain;
/**
* @description:
* @author: lihongwei
* @time: 2020/1/8 2:15 下午
*/
public class User {
private int age;
private String name;
private String sex;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
@Override
public String toString() {
return "User{" +
"age=" + age +
", name='" + name + '\'' +
", sex='" + sex + '\'' +
'}';
}
}
注意: 这个类 实现了 另一个自定义模块
user-service-api
中的接口,初次引入会报错,等把另一个项目 user-service-api建好,并引入项目之后便不会报错。
package com.itzhongzi.userapp.service.dubbo;
import com.itzhongzi.userserviceapi.service.IUserService;
import com.itzhongzi.userserviceapi.vo.UserVo;
import org.apache.dubbo.config.annotation.Service;
/**
* @description:
* @author: lihongwei
* @time: 2020/1/8 2:20 下午
*/
@Service
public class UserService implements IUserService{
@Override
public UserVo getUserById(Integer id) {
UserVo user = null;
if(id == null || id == 0) {
user = new UserVo();
user.setName("new 李洪伟");
user.setAge(18);
user.setSex("男");
}
//去查询数据库 假装查到了数据
user = new UserVo();
user.setName("数据库 李洪伟");
user.setAge(id);
user.setSex("数据库 男");
return user;
}
}
注意: 要想用 UserService去继承 IUserService,一定要在 user-app中引入 user-service-api模块,如下图:
<dependency>
<groupId>com.itzhongzigroupId>
<artifactId>user-service-apiartifactId>
<version>0.0.1-SNAPSHOTversion>
dependency>
优惠券模块本质上就是把 user-module拷贝一份,然后 修改几个一下几个地方
- 各个pom.xml文件
- 修改 package的报名
- 修改类的入口
- 把不需要的类给删除
如果不知道怎么修改,就从头创建一个多么快的项目,效果是一样的。
coupon-module | coupon-app | coupon-service-api |
---|---|---|
优惠券模块(父目录) | 优惠券对外api子模块 | 程序内部调用的优惠券api模块(jar) |
user-service-api 模块 基本所有的内容都是空的,象征醒的剪了一个模块。maven配置如下
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.2.2.RELEASEversion>
<relativePath/>
parent>
<groupId>com.itzhongzigroupId>
<artifactId>coupon-service-apiartifactId>
<version>0.0.1-SNAPSHOTversion>
<name>coupon-service-apiname>
<description>Demo project for Spring Bootdescription>
<properties>
<java.version>1.8java.version>
properties>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starterartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
<exclusions>
<exclusion>
<groupId>org.junit.vintagegroupId>
<artifactId>junit-vintage-engineartifactId>
exclusion>
exclusions>
dependency>
dependencies>
<build>
build>
project>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.2.2.RELEASEversion>
<relativePath/>
parent>
<groupId>com.itzhongzigroupId>
<artifactId>coupon-appartifactId>
<version>0.0.1-SNAPSHOTversion>
<name>coupon-appname>
<description>Demo project for Spring Bootdescription>
<properties>
<java.version>1.8java.version>
properties>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-devtoolsartifactId>
<scope>runtimescope>
<optional>trueoptional>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
<exclusions>
<exclusion>
<groupId>org.junit.vintagegroupId>
<artifactId>junit-vintage-engineartifactId>
exclusion>
exclusions>
dependency>
<dependency>
<groupId>com.itzhongzigroupId>
<artifactId>coupon-service-apiartifactId>
<version>0.0.1-SNAPSHOTversion>
dependency>
<dependency>
<groupId>org.apache.dubbogroupId>
<artifactId>dubboartifactId>
<version>2.7.2version>
<exclusions>
<exclusion>
<artifactId>springartifactId>
<groupId>org.springframeworkgroupId>
exclusion>
exclusions>
dependency>
<dependency>
<groupId>org.apache.zookeepergroupId>
<artifactId>zookeeperartifactId>
<version>3.4.10version>
<exclusions>
<exclusion>
<artifactId>slf4j-log4j12artifactId>
<groupId>org.slf4jgroupId>
exclusion>
exclusions>
dependency>
<dependency>
<groupId>com.github.sgroschupfgroupId>
<artifactId>zkclientartifactId>
<version>0.1version>
dependency>
<dependency>
<groupId>org.apache.curatorgroupId>
<artifactId>curator-recipesartifactId>
<version>4.0.1version>
dependency>
<dependency>
<groupId>com.itzhongzigroupId>
<artifactId>user-service-apiartifactId>
<version>0.0.1-SNAPSHOTversion>
dependency>
dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
plugin>
plugins>
build>
project>
project=dubbo
logdir=../logs/${project}
### set log levels ###
log4j.rootLogger = info,stdout,console
# config this project appender,log level:info,error #
log4j.logger.com.ts.report = info,error,bizInfo,bizError
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.Target=System.out
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=%d{yyy-MM-dd HH\:mm\:ss} %5p %c{1}\:%L - %m%n
## \u8F93\u51FA\u5230\u63A7\u5236\u53F0 ###
log4j.appender.stdout=org.apache.log4j.DailyRollingFileAppender
log4j.appender.stdout.File=${logdir}/all.log
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.DatePattern='_'yyyy-MM-dd
log4j.appender.stdout.layout.ConversionPattern=%d{yyy-MM-dd HH\:mm\:ss} %5p %c{1}\:%L - %m%n
# info log everyday file#
log4j.loger.bizInfo = info,bizInfo
log4j.appender.bizInfo=org.apache.log4j.DailyRollingFileAppender
log4j.appender.bizInfo.File=${logdir}/info.log
log4j.appender.bizInfo.layout=org.apache.log4j.PatternLayout
log4j.appender.bizInfo.DatePattern='_'yyyy-MM-dd
log4j.appender.bizInfo.layout.ConversionPattern=%d{yyy-MM-dd HH\:mm\:ss} %5p %c{1}\:%L - %m%n
log4j.appender.bizInfo.Threshold=INFO
#log4j.additivity.bizInfo=false
## error log ##
log4j.loger.bizError = info,bizError
log4j.appender.bizError = org.apache.log4j.DailyRollingFileAppender
log4j.appender.bizError.File = ${logdir}/error.log
log4j.appender.bizError.layout = org.apache.log4j.PatternLayout
log4j.appender.bizError.DatePattern='_'yyyy-MM-dd
log4j.appender.bizError.layout.ConversionPattern =%d{yyy-MM-dd HH\:mm\:ss} %5p %c{1}\:%L - %m%n
log4j.appender.bizError.Threshold = ERROR
#log4j.additivity.error=false
## error log ##
log4j.loger.error = info,error
log4j.appender.error = org.apache.log4j.DailyRollingFileAppender
log4j.appender.error.File = ${logdir}/sys_error.log
log4j.appender.error.layout = org.apache.log4j.PatternLayout
log4j.appender.error.DatePattern='_'yyyy-MM-dd
log4j.appender.error.layout.ConversionPattern =%d{yyy-MM-dd HH\:mm\:ss} %5p %c{1}\:%L - %m%n
log4j.appender.error.Threshold = ERROR
#log4j.additivity.error=false
server:
port: 8088
# dubbo 配置
dubbo:
application:
name: user-app
qosEnable: true
qosPort: 33333
qosAcceptForeignIp: false
# 使用 zookeeper 注册中心暴露服务,注意要先开启 zookeeper
# 注册中心id
registry:
id: zookeeper-registry
# 注册中心协议
protocol: zookeeper
# 注册中心地址
address: 127.0.0.1:2181
# dubbo协议在20880端口暴露服务
# 协议名称
protocol:
name: dubbo
# 协议端口 对外提供访问的端口
port: 20881
# 协议访问log
accesslog: dubbo-access.log
# 重试次数
provider:
#重试次数
retries: 0
# 超时时间
timeout: 3000
# 注册监控中心
monitor:
protocol: registry
config-center:
protocol: zookeeper
address: 127.0.0.1:2181
注意 多个 dubbo项目部署在同一个电脑上时,dubbo对外访问的端口不要相同,否则会报 端口占用的错误。
注意: 入口类开启 dubbo时,使用
@DubboComponentScan("com.itzhongzi.userapp.service.dubbo")
中的包名,是user-module模块中对外提供的service报名。
package com.itzhongzi.couponapp;
import org.apache.dubbo.config.spring.context.annotation.DubboComponentScan;
import org.apache.dubbo.config.spring.context.annotation.EnableDubboConfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@EnableDubboConfig
@DubboComponentScan("com.itzhongzi.userapp.service.dubbo")
@SpringBootApplication
public class CouponAppApplication {
public static void main(String[] args) {
SpringApplication.run(CouponAppApplication.class, args);
}
}
- 在这里面调用远程接口
- 远程类自动注入要用
@Reference
- IUserService为 user-module模块的服务类
package com.itzhongzi.couponapp.service;
import com.itzhongzi.userserviceapi.service.IUserService;
import com.itzhongzi.userserviceapi.vo.UserVo;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.stereotype.Service;
/**
* @description:
* @author: lihongwei
* @time: 2020/1/8 4:06 下午
*/
@Service
public class CouponService {
@Reference
private IUserService iUserService;
public UserVo getCouponUser(Integer id){
return iUserService.getUserById(id);
}
}
package com.itzhongzi.couponapp.controller;
import com.itzhongzi.couponapp.service.CouponService;
import com.itzhongzi.userserviceapi.vo.UserVo;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
/**
* @description:
* @author: lihongwei
* @time: 2020/1/8 4:08 下午
*/
@RestController
public class TestController {
@Resource
private CouponService couponService;
@RequestMapping("coupon_user")
public UserVo getUser(Integer id){
return couponService.getCouponUser(id);
}
}
我们把两个项目都启动,user-module在8086端口,coupon-module在8088端口。
我们去请求 8088 端口coupon-mudule开放的api,看看能不能 调用user-module的模块。
如图所示,请求成功。
这样我们springboot+dubbo+zookeeper搭建的微服务框架就搭建完毕了。后续可以自己加入数据库等各种配置。
谢谢观看。