SpringCloud(一)-手把手教你創(chuàng)建springcloud微服務(wù)父子項(xiàng)目

現(xiàn)在微服務(wù)思想大行其道,各個(gè)公司都在如火如荼的進(jìn)行技術(shù)轉(zhuǎn)型,掌握SpringCloud已經(jīng)成為升職加薪的墊腳石,筆者將從本文開始從實(shí)戰(zhàn)和原理記錄SpringCloud的學(xué)習(xí)過程。

系列文章
SpringCloud(一)-手把手教你創(chuàng)建springcloud微服務(wù)父子項(xiàng)目
SpringCloud(二)-手把手教你搭建Eureka Server和Eureka Client
SpringCloud(三)-手把手教你通過Rinbbon實(shí)現(xiàn)客戶端負(fù)載均衡
SpringCloud(四)-手把手教你使用OpenFeign
SpringCloud(五)-手把手教你使用Hystrix配置服務(wù)熔斷和降級(jí)以及Hystrix Dashboard
SpringCloud(六)-手把手教你搭建SpringCloud Config配置中心
SpringCloud(七)-手把手教你使用消息總線Bus實(shí)現(xiàn)動(dòng)態(tài)刷新
SpringCloud(八)-手把手教你使用Stream消息驅(qū)動(dòng)

碼云地址

https://gitee.com/zhaowenyi/springcloudtest/tree/master

初識(shí)SpringCloud

打開SpingCloud中文官網(wǎng),一行"微服務(wù)集大成者,云計(jì)算最佳業(yè)務(wù)實(shí)踐"赫然入目,由此可知SpringCloud在微服務(wù)領(lǐng)域的影響力。

SpringCloud 是由一系列技術(shù)棧組合而成:

  • Spring Cloud Config: 管理配置包,可以將配置文件放在遠(yuǎn)程服務(wù)器上集中化管理集群配置文件。支持本地存儲(chǔ),git,subversion。
  • Spring Cloud Bus:事件、消息總線,可以在集群中傳播狀態(tài)變化,比如配置文件變動(dòng),可以和Spring Cloud Config組合使用。
  • Netflix Eureka:服務(wù)注冊(cè)與發(fā)現(xiàn),一個(gè)基于REST服務(wù),用于服務(wù)注冊(cè)與發(fā)現(xiàn),故障轉(zhuǎn)移等功能
  • Netflix Hystrix:熔斷器,容錯(cuò)管理工具,旨在通過熔斷機(jī)制控制服務(wù)和第三方庫(kù)的節(jié)點(diǎn),從而為延遲和故障提供更強(qiáng)大的容錯(cuò)能力。
  • Netflix Zuul:提供動(dòng)態(tài)路由,監(jiān)控和安全等邊緣服務(wù)的框架。
  • Netflix Ribbon:提供云端負(fù)載均衡,有多種負(fù)載均衡可供選擇,可和熔斷器和服務(wù)發(fā)現(xiàn)組合使用
  • Open Feign: 是一款申明式,模塊化的HTTP客戶端

這還只是列出的一部分常用的框架,還有很多都沒有列出來,光通過定義都難以理解這些框架是干什么用的,只能千里之行始于足下,一步步開始攻克這些知識(shí)點(diǎn)了。

初識(shí)SpringBoot

上面的框架中沒有列出SpringBoot,是因?yàn)镾pringBoot作為最基礎(chǔ)的框架,是基石,任何微服務(wù)都要從搭建一個(gè)Spring Boot項(xiàng)目開始。

那么什么是Spring Boot呢?

打開Spring Boot官網(wǎng),我們了解到
使用Spring Boot可以輕松地創(chuàng)建獨(dú)立的,基于生產(chǎn)級(jí)別的基于Spring的應(yīng)用程序,我們可以“運(yùn)行”它們。也就是Spring Boot幫我們配置了Spring 項(xiàng)目中哪些繁瑣的配置,而且內(nèi)置了服務(wù)器,比如tomcat,我們可以直接運(yùn)行它。

總之其Spring思想還是沒有變,只是幫我們簡(jiǎn)單快速的搭建一個(gè)Spring 項(xiàng)目。

構(gòu)建SpringCloud項(xiàng)目

接下來就是開始搭建SpringCloud項(xiàng)目了。首選我們要搭建Spring Cloud項(xiàng)目父工程。

工具準(zhǔn)備

  • JDK : 1.8
  • Spring Boot:2.0
  • IntelliJ IDEA:ULTIMATE 2017.02
  • Mysql:5.6.24
  • Win10
  • Maven: 3.6

搭建步驟

創(chuàng)建父工程
新建項(xiàng)目
輸入gav坐標(biāo)
選擇項(xiàng)目路徑.png

點(diǎn)擊File - settings - Build Tools - Maven ,這里的Maven路徑選擇自己本地的maven路徑。

設(shè)置maven路徑

設(shè)置自動(dòng)導(dǎo)入依賴

點(diǎn)擊Enable Auto Import

Editor - File Types,末尾加上“.idea;.iml;”,設(shè)置隱藏impl文件和.idea文件

image.png

File - settings - Build - Complier - Java Complier ,需要將編譯版本設(shè)置為1.8

設(shè)置編譯的jdk版本

最終的項(xiàng)目結(jié)構(gòu)

項(xiàng)目結(jié)構(gòu)

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.elio.springcloud</groupId>
    <artifactId>springcloudtest</artifactId>
    <version>1.0-SNAPSHOT</version>

    <!--統(tǒng)一管理jar包版本-->
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <junit.version>4.12</junit.version>
        <lombok.version>1.18.10</lombok.version>
        <log4j.version>1.2.17</log4j.version>
        <mysql.version>5.1.47</mysql.version>
        <druid.version>1.1.16</druid.version>
        <mybatis.spring.boot.version>1.3.0</mybatis.spring.boot.version>
    </properties>

    <!--子模塊繼承之后,提供作用:鎖定版本+子module不用寫groupId和version-->
    <dependencyManagement><!--定義規(guī)范,但不導(dǎo)入-->
        <dependencies>
            <dependency>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-project-info-reports-plugin</artifactId>
                <version>3.0.0</version>
            </dependency>
            <!--spring boot 2.2.2-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>2.2.2.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!--spring cloud Hoxton.SR1-->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Hoxton.SR1</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!--spring cloud 阿里巴巴-->
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>2.1.0.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!--mysql-->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>${mysql.version}</version>
                <scope>runtime</scope>
            </dependency>
            <!-- druid-->
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid</artifactId>
                <version>${druid.version}</version>
            </dependency>
            <!--mybatis-->
            <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
                <version>${mybatis.spring.boot.version}</version>
            </dependency>
            <!--junit-->
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>${junit.version}</version>
            </dependency>
            <!--log4j-->
            <dependency>
                <groupId>log4j</groupId>
                <artifactId>log4j</artifactId>
                <version>${log4j.version}</version>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <!--熱啟動(dòng)插件-->
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <fork>true</fork>
                    <addResources>true</addResources>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>
創(chuàng)建子工程

父工程完成后,我們接下來創(chuàng)建兩個(gè)子項(xiàng)目,一個(gè)是商品服務(wù)的提供者,一個(gè)是商品服務(wù)的消費(fèi)者。首先來創(chuàng)建商品服務(wù)的提供者

右鍵項(xiàng)目名,點(diǎn)擊New - module

新增子項(xiàng)目
點(diǎn)擊next

輸入子項(xiàng)目名稱 ”springcloud-product-provider-8100“,表示的商品的提供者,使用8100端口

輸入子項(xiàng)目名稱
點(diǎn)擊next

點(diǎn)擊finish后,我們可以看到構(gòu)建成功的子項(xiàng)目

商品服務(wù)提供者8100

添加商品服務(wù)提供者的pom.xml配置

右鍵商品服務(wù)提供者項(xiàng)目的resources文件夾,新增application.yml配置文件,新增之后application.yml前面有個(gè)綠色的小葉子標(biāo)識(shí)

新增yml配置文件

yml中的配置文件如下

server:
  port: 8100 #端口號(hào)

spring:
  application:
    name: springcloud-product-provider-8100
  datasource:
      url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&userSSL=false
      driverClassName: com.mysql.jdbc.Driver
      username: root
      password: 111111

mybatis:
  mapper-locations: classpath:mapping/*mapper.xml # Mybatis 映射文件位置
  type-aliases-package: com.elio.springcloud.entity  # 表對(duì)應(yīng)的實(shí)體類包


右鍵java文件夾新增,實(shí)體類Product,這將是我們接下來的product表對(duì)應(yīng)的實(shí)體類

package com.elio.springcloud.entity;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@NoArgsConstructor
@AllArgsConstructor
@Setter
@Getter
public class Product {

    private Long id; //自增id
    private String name;// 產(chǎn)品名稱
    private int stock;// 庫(kù)存

}

新增dao層接口ProductMapper

package com.elio.springcloud.dao;

import com.elio.springcloud.entity.Product;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;

@Repository
public interface ProductMapper {
    /**
     * 查詢
     * @param id
     * @return
     */
    public Product selectById(@Param("id") Long id);


    /**
     * 刪除
     * @param id
     * @return
     */
    public int deleteById(@Param("id") Long id);

    /**
     * 修改
     * @param id
     * @param name
     * @return
     */
    public int updateById(@Param("id") Long id, @Param("name") String name);

    /**
     * 新增
     * @param product
     * @return
     */
    public int insertOne(Product product);
}

右鍵resources文件,新增mapping\product_mapper.xml文件,這個(gè)是product表對(duì)應(yīng)的sql文件,包含簡(jiǎn)單的增刪改查

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.elio.springcloud.dao.ProductMapper">

    <resultMap id="BaseResultMap" type="com.elio.springcloud.entity.Product">
        <result column="id" jdbcType="BIGINT" property="id" />
        <result column="name" jdbcType="VARCHAR" property="name" />
        <result column="stock" jdbcType="INTEGER" property="stock" />
    </resultMap>

    <!--查詢-->
    <select id="selectById" resultType="Product">
        select * from product where id = #{id}
    </select>

    <!--刪除-->
    <delete id="deleteById" parameterType="Long">
        delete from product where id = #{id}
    </delete>

    <!--修改-->
    <update id="updateById" parameterType="Product">
        update product set name = #{name} where id = #{id}
    </update>

    <!--新增-->
    <insert id="insertOne" parameterType="Product">
       insert into product(name, stock) values (#{name}, #{stock})
    </insert>

</mapper>

新增ProductService.java文件

package com.elio.springcloud.service;

import com.elio.springcloud.entity.Product;
import org.apache.ibatis.annotations.Param;

/**
 * 商品服務(wù)類
 */
public interface ProductService {

    /**
     * 查詢
     * @param id
     * @return
     */
    public Product selectById(Long id);


    /**
     * 刪除
     * @param id
     * @return
     */
    public int deleteById(Long id);

    /**
     * 修改
     * @param id
     * @param name
     * @return
     */
    public int updateById(Long id, String name);

    /**
     * 新增
     * @param product
     * @return
     */
    public int insertOne(Product product);

}


新增ProductServiceImpl.java 類

package com.elio.springcloud.service.impl;

import com.elio.springcloud.dao.ProductMapper;
import com.elio.springcloud.entity.Product;
import com.elio.springcloud.service.ProductService;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

@Service
public class ProductServiceImpl implements ProductService{

    @Resource
    private ProductMapper productMapper;

    public Product selectById(Long id) {
        return productMapper.selectById(id);
    }

    public int deleteById(Long id) {
        return productMapper.deleteById(id);
    }

    public int updateById(Long id, String name) {
        return productMapper.updateById(id, name);
    }

    public int insertOne(Product product) {
        return productMapper.insertOne(product);
    }
}


新增Result.java

package com.elio.springcloud.dto;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@AllArgsConstructor
@NoArgsConstructor
@Setter
@Getter
public class Result {

    private int code;
    private String message;
    private Object result;
}

新增ProductProviderController.java

package com.elio.springcloud.controller;

import com.elio.springcloud.dto.Result;
import com.elio.springcloud.entity.Product;
import com.elio.springcloud.service.ProductService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;

@RestController
@Slf4j
@RequestMapping("/")
public class ProductProviderController {

    @Resource
    private ProductService productService;

    /**
     * 查詢
     * @param id
     * @return
     */
    @GetMapping("product/provider/get/{id}")
    public Result selectById(@PathVariable("id") Long id){
        return new Result(200, "查詢成功", productService.selectById(id));
    }

    /**
     * 刪除
     * @param id
     * @return
     */
    @GetMapping("product/provider/delete/{id}")
    public Result deleteById(@PathVariable("id") Long id){
        return new Result(200, "刪除成功", productService.deleteById(id));
    }

    /**
     * 修改
     * @param product
     * @return
     */
    @PostMapping("product/provider/update")
    public Result updateById(@RequestBody Product product){
        return new Result(200, "修改成功", productService.updateById(product.getId(), product.getName()));

    }

    /**
     * 新增
     * @return
     */
    @PutMapping( "product/provider/add")
    public Result insertById(@RequestBody Product product){
        return new Result(200, "修改成功", productService.insertOne(product));
    }
}

右鍵java文件夾,新增主啟動(dòng)類ProductProvider8100

新增主啟動(dòng)類

ProductProvider8100內(nèi)容如下,加上@SpringBootApplication和MapperScan注解

package com.elio.springcloud;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
@MapperScan("com.elio.springcloud.dao")
public class ProductProvider8100 {

    public static void main(String[] args){
        SpringApplication.run(ProductProvider8100.class, args);
    }
}


創(chuàng)建表結(jié)構(gòu)


-- ----------------------------
-- Table structure for product
-- ----------------------------
DROP TABLE IF EXISTS `product`;
CREATE TABLE `product` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  `stock` int(10) unsigned DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;


測(cè)試

至此微服務(wù)的商品提供者,我們已經(jīng)創(chuàng)建成功,接下來就是測(cè)試該提供者了


右鍵主啟動(dòng)類DEBUG

啟動(dòng)成功后可以查看結(jié)果如下


啟動(dòng)成功

瀏覽器地址輸入 http://localhost:8100/product/provider/get/1

查詢結(jié)果

創(chuàng)建商品服務(wù)消費(fèi)者

右鍵父項(xiàng)目,點(diǎn)擊next

點(diǎn)擊Next
輸入項(xiàng)目名
輸入項(xiàng)目名

配置商品消費(fèi)者的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">
    <parent>
        <artifactId>springcloudtest</artifactId>
        <groupId>com.elio.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>springcloud-product-consumer-8200</artifactId>


    <dependencies>
        <!--spring boot -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--熱部署-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
        </dependency>
        <!--lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
    </dependencies>

    <!--熱啟動(dòng)插件-->
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <fork>true</fork>
                    <addResources>true</addResources>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

resources文件夾下新增application.yml文件

server:
  port: 8200

spring:
  application:
    name: springcloud-product-consumer-8200

新增主啟動(dòng)類 ProductConsumer8200,因?yàn)橄M(fèi)者不需要連接數(shù)據(jù)庫(kù),所以pom.xml中也沒有導(dǎo)入相關(guān)依賴,因此需要將自動(dòng)注入數(shù)據(jù)源的的類過濾掉 @SpringBootApplication(exclude={DataSourceAutoConfiguration.class,HibernateJpaAutoConfiguration.class})

package com.elio.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;

@SpringBootApplication(exclude={DataSourceAutoConfiguration.class,HibernateJpaAutoConfiguration.class})
public class ProductConsumer8200 {

    public static void main(String[] args){
        SpringApplication.run(ProductConsumer8200.class, args);
    }
}

新增業(yè)務(wù)類 ProductConsumerController

package com.elio.springcloud.controller;

import com.elio.springcloud.dto.Result;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;

@RestController
public class ProductConsumerController {

    @Resource
    RestTemplate restTemplate;

    public static String url = "http://localhost:8100/";

    /**
     * 查詢
     * @param id
     * @return
     */
    @GetMapping("product/consumer/get/{id}")
    public Result selectById(@PathVariable("id") Long id){

        return new Result(200, "查詢成功",
                restTemplate.getForObject(url+"product/provider/get/"+id, Result.class));
    }

}

**新增結(jié)果返回實(shí)體類Result **

package com.elio.springcloud.dto;


import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@AllArgsConstructor
@NoArgsConstructor
@Setter
@Getter
public class Result {

    private int code;
    private String message;
    private Object result;
}

因?yàn)橐{(diào)用消費(fèi)者的api, 因此我們需要注入restTemplate對(duì)象,新增RestConfig

package com.elio.springcloud.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration
public class RestConfig {

    @Bean
    public RestTemplate getRestTemplate(){
        return new RestTemplate();
    }
}

至此,我們已經(jīng)創(chuàng)建好了消費(fèi)者項(xiàng)目,接下來就是測(cè)試了

消費(fèi)者項(xiàng)目架構(gòu)

右鍵主啟動(dòng)類,啟動(dòng)成功后會(huì)顯示如下結(jié)果

啟動(dòng)日志

瀏覽器地址輸入 http://localhost:8200/product/consumer/get/1
這是使用消費(fèi)者的路徑訪問提供者的api,結(jié)果如下

返回成功的結(jié)果

總結(jié)

我們至此創(chuàng)建了一個(gè)父項(xiàng)目springcloudtest,然后有一個(gè)商品服務(wù)提供者
springcloud-product-provider-8100 和一個(gè)商品服務(wù)消費(fèi)者springcloud-product-consumer-8200 。然后這就是最簡(jiǎn)單的兩個(gè)微服務(wù)了,實(shí)現(xiàn)了功能的解耦,但是這個(gè)簡(jiǎn)單的微服務(wù)存在著很多問題,比如都用公共的實(shí)體類Result,還有提供者地址在消費(fèi)者里面寫死了等等,這些問題,我們接下來會(huì)一一解決。如有問題,請(qǐng)?jiān)谠u(píng)論區(qū)指正。

項(xiàng)目架構(gòu)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容