微服务概述

微服务是什么?微服务解决了什么问题?微服务有什么特点?


单体架构是什么?

一个归档包包含了应用所有功能的应用程序,我们通常称之为单体应用。架构单体应用的架构风格,我们称之为单体架构,这是一种比较传统的架构风格。


单体架构存在的缺点:

1.复杂性逐渐变高。


2.技术债务逐渐上升。


3.部署速度逐渐变慢。


4.阻碍技术创新。


5.无法按需收缩。


架构的演进:

1.单体架构


2.SOA


3.微服务


什么是微服务?

Martin Fowler:简而言之,微服务架构风格这种开发方法,是以开发一组小型服务的方式来开发一个独立的应用系统的。其中每个小型服务都运行在自己的进程中,并经常采用HTTP资源API这样轻量的机制来相互通信。这些服务围绕业务功能进行构建,并能通过全自动的部署机制来进行独立部署。这些微服务可以使用不同的语言来编写,并且可以使用不同的数据存储技术。对这些微服务我们仅做最低限度的集中管理。


来自:http://www.martinfowler.com/articles/microservices.html


微服务具备的特性:

1.每个微服务都可独立运行在自己的进程里。


2.一系列独立运行的微服务共同构建起了整个系统。


3.每个服务为独立的业务开发,一个微服务一般完成某个特定的功能,比如:订单管理、用户管理等;


4.微服务之间通过一些轻量级的通信机制进行通信,例如通过REST API或者RPC的方法进行调用。


微服务的优点:

1.易于开发和维护


2.启动较快


3.局部修改容易部署


4.技术栈不受限制


5.按需收缩


6.Devops(即便于各个部门之间相互沟通与协作)


微服务带来的挑战:

1.运维要求较高


2.分布式的复杂性


3.接口调整成本高


4.重复劳动


注意:所说的重复劳动是说在各个组件使用不同的技术的情况下出现的,例如工具类的编写,Model类的编写。如果所有的组件使用的技术全部都相同,则可以将公共部分打包部署到Maven私服上。


微服务设计原则:

1.单一职责原则


2.服务自治原则


3.轻量级通信原则


4.接口明确原则


微服务开发框架浅谈:

Spring Cloud:http://projects.spring.io/spring-cloud


Dubbo:http://dubbo.io


Dropwizard:http://www.dropwizard.io


Consl、etcd &etc.


现在使用Spring cloud构建微服务是社会发展的趋势。接着去学习Spring  cloud


Spring cloud是什么?

Spring cloud并不是云计算,它是基于Springboot的一种快速构建分布式系统的工具集。


关于Spring cloud的版本:


大部分Spring的版本是以主版本.次版本.增量版本.里程碑版本的形式命名


Spring cloud的特点:

① 约定优于配置


② 开箱即用、快速启动


③ 适用于各种环境


⑤ 使用轻量级的组件 例如:服务发现Eureka


⑥ 组件支持很丰富,功能很齐全(配置中心、注册中心、智能路由)


⑦ 选型中立。例如对于服务发现而言 支持三种组件以供选择(Eureka、ZooKeeper、Consul)


使用Spring cloud需要的技术储备:

编程语言:主要是Java,也支持Scala和Groovy


构建工具:可以使用Maven和Gradle。 注意:Maven和Gradle项目可以相互转化,例如将Maven项目转为Gradle项目可以在Maven项目根目录下使用终端命令gradle init --type pom 从而将Maven项目转为Gradle项目。


技术框架:Spring Boot

入门使用

服务提供者:服务的被调用方(即:为其他服务提供服务的服务)

服务消费者:服务的调用方(即:依赖其它服务的服务)

俗话说:君子生非异也 善假于物。翻译原生英文文档太浪费时间和精力了,我也是在网上搜到的一些资料。研究没问题后发出来,借花献佛 献丑了。

编写一个简单的程序实现服务消费者和服务提供者:

微服务应用管理 微服务的应用_spring

Spring官网提供了快速构建Springboot项目的网址:http://start.spring.io/

①首先生成服务提供者项目

微服务应用管理 微服务的应用_微服务_02

② 然后生成服务消费者项目

微服务应用管理 微服务的应用_微服务应用管理_03

编写代码后两个的项目结构如下:

微服务应用管理 微服务的应用_java_04

(一)服务提供者程序的编写

schema.sql (SpringBoot启动时默认执行classpath下的schema.sql作为建表语句)

drop table user if exists;
create table user(
	id bigint generated by default as identity,
	username varchar(40),
	name varchar(20),
	age int(3),
	balance decimal(10,2),
	primary key(id)
);

data.sql 

insert into user(id,username, name, age, balance) values(1,'user1','张三',10, 100.00);
insert into user(id,username, name, age, balance) values(2,'user2','李四',20, 200.00);
insert into user(id,username, name, age, balance) values(3,'user3','王五',30, 300.00);
insert into user(id,username, name, age, balance) values(4,'user4','赵六',40, 400.00);
insert into user(id,username, name, age, balance) values(5,'user5','孙七',50, 500.00);
insert into user(id,username, name, age, balance) values(6,'user6','胜八',60, 600.00);

User.java

package com.liuxun.cloud.entity;

import java.io.Serializable;
import java.math.BigDecimal;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
public class User implements Serializable {
	private static final long serialVersionUID = 1L;
	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	private Long id;
	@Column
	private String username;
	@Column
	private String name;
	@Column
	private Short age;
	@Column
	private BigDecimal balance;

	public Long getId() {
		return id;
	}

	public void setId(Long id) {
		this.id = id;
	}

	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Short getAge() {
		return age;
	}

	public void setAge(Short age) {
		this.age = age;
	}

	public BigDecimal getBalance() {
		return balance;
	}

	public void setBalance(BigDecimal balance) {
		this.balance = balance;
	}

}

UserRepository

package com.liuxun.cloud.repository;

import org.springframework.data.jpa.repository.JpaRepository;

import com.liuxun.cloud.entity.User;

public interface UserRepository extends JpaRepository<User, Long> {

}

UserController

package com.liuxun.cloud.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

import com.liuxun.cloud.entity.User;
import com.liuxun.cloud.repository.UserRepository;

@RestController
public class UserController {

	@Autowired
	private UserRepository userRepository;

	@GetMapping("/simple/{id}")
	public User findById(@PathVariable Long id) {
		return userRepository.findById(id).get();
	}
}

application.yml

server:
  port: 7900
spring:
  jpa:
    generate-ddl: false
    show-sql: true
    hibernate:
      ddl-auto: none
  datasource:
    platform: h2
    schema: classpath:schema.sql #defalut schema.sql
    data: classpath:data.sql 
logging:
  level:
    root: info
    org.hibernate.type.descriptor.sql.BasicBinder: trace #与show-sql 结合打印参数
    org.hibernate.type.descriptor.sql.BasicExtractor: trace #与show-sql 结合打印参数

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.liuxun.cloud</groupId>
	<artifactId>microservice-simple-provider-user</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>

	<name>microservice-simple-provider-user</name>
	<description>Demo project for Spring Boot</description>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.0.0.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<java.version>1.8</java.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jpa</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>com.h2database</groupId>
			<artifactId>h2</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>
</project>

运行测试结果如下:

微服务应用管理 微服务的应用_微服务应用管理_05

(二)服务消费者程序的编写

User.java

package com.liuxun.cloud.entity;

import java.io.Serializable;
import java.math.BigDecimal;

public class User implements Serializable {
	private static final long serialVersionUID = 1L;
	private Long id;
	private String username;
	private String name;
	private Short age;
	private BigDecimal balance;

	public Long getId() {
		return id;
	}

	public void setId(Long id) {
		this.id = id;
	}

	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Short getAge() {
		return age;
	}

	public void setAge(Short age) {
		this.age = age;
	}

	public BigDecimal getBalance() {
		return balance;
	}

	public void setBalance(BigDecimal balance) {
		this.balance = balance;
	}

}

MovieController.java

package com.liuxun.cloud.controller;

import org.springframework.beans.factory.annotation.Autowired;
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 com.liuxun.cloud.entity.User;

@RestController
public class MovieController {

	@Autowired
	private RestTemplate restTemplate;

	@GetMapping("/movie/{id}")
	public User findById(@PathVariable Long id) {
		return this.restTemplate.getForObject("http://localhost:7900/simple/" + id, User.class);
	}
}

Application.java

package com.liuxun.cloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@SpringBootApplication
public class MicroserviceSimpleConsumerMovieApplication {

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

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

application.yml

server:
  port: 7901

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.liuxun.cloud</groupId>
	<artifactId>microservice-simple-consumer-movie</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>

	<name>microservice-simple-consumer-movie</name>
	<description>Demo project for Spring Boot</description>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.0.0.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<java.version>1.8</java.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>
</project>

启动两个项目  在服务消费者端进行测试 通信 是成功调用的


微服务应用管理 微服务的应用_java_06


注意事项:

默认建表语句脚本是执行classpath下的schema.sql

默认数据脚本是执行classpath下的data.sql

 这种方法的缺陷:微服务组件之间通信采用了硬编码是存在很大弊端的:

① 如果各个服务模块之间依赖紧密,当修改依赖模块的端口时 都要必须在服务消费者中修改地址

② 在负载均衡若使用nginx的话 这样硬编码会导致配置异常繁琐