任而风吹雨打,胜似闲庭信步。
一个月了,工作仍然没有着落。“金三银四,金九银十”,真应了这句行规,七八月份不是个找工作的好时节。在最好的时候去了一家混子公司,接了一堆烂摊子。在最不好的时候被人开除了,四处碰壁。我急嘛,倒也不是很急,转行前就知道自己不会长期
Spring Cloud,你到底是个什么东西?
1.什么是SpringCloud:一言以蔽之,一个微服务落地框架。
2.主流微服务框架对比:
3.学习SpringCloud其实就是学些各个组件使用及整合。
4.第一个springClouddemo项目的编写(项目涉及业务比较简单,很多层级省略了。用到了很多的注解和插件后期会补充说明。该项目主要体会意思)
数据库脚本:
/*
SQLyog Ultimate v9.62
MySQL - 5.5.55 : Database - epolageloo
*********************************************************************
*/
/*!40101 SET NAMES utf8 */;
/*!40101 SET SQL_MODE=''*/;
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
CREATE DATABASE /*!32312 IF NOT EXISTS*/`epolageloo` /*!40100 DEFAULT CHARACTER SET utf8 */;
USE `epolageloo`;
/*Table structure for table `tb_user` */
DROP TABLE IF EXISTS `tb_user`;
CREATE TABLE `tb_user` (
`id` int(255) NOT NULL DEFAULT '0',
`user_name` varchar(20) DEFAULT NULL,
`password` varchar(20) DEFAULT NULL,
`name` varchar(20) DEFAULT NULL,
`age` int(255) DEFAULT NULL,
`sex` int(10) DEFAULT NULL,
`birthday` date DEFAULT NULL,
`created` date DEFAULT NULL,
`updated` date DEFAULT NULL,
`note` varchar(20) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*Data for the table `tb_user` */
insert into `tb_user`(`id`,`user_name`,`password`,`name`,`age`,`sex`,`birthday`,`created`,`updated`,`note`) values (1,'张三','123','张三',20,1,'1999-03-06','2019-08-01',NULL,'挺好的一个人');
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
1)创建maven聚合工程,主要用来统一管理依赖。而且idea不支持多项目在同一个窗口开启,创建一个工程,再以模块方式创建各个服务还是比较方便的。
<?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.scbg.demo</groupId>
<artifactId>cloud-demo</artifactId>
<version>1.0.0-SNAPSHOT</version>
<modules>
<module>user-service</module>
<module>consumer-demo</module>
</modules>
<packaging>pom</packaging>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.4.RELEASE</version>
<relativePath/>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<spring-cloud.version>Finchley.SR1</spring-cloud.version>
<mapper.starter.version>2.0.3</mapper.starter.version>
<mysql.version>5.1.32</mysql.version>
</properties>
<dependencyManagement>
<dependencies>
<!--springcloud-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!--通用mapper控制器-->
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper-spring-boot-starter</artifactId>
<version>${mapper.starter.version}</version>
</dependency>
<!--mysql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
<!--springboot maven 插件-->
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
2)右键项目名,新建module,user-service模块。提供user信息查询服务。
<?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>cloud-demo</artifactId>
<groupId>com.scbg.demo</groupId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>user-service</artifactId>
<dependencies>
<!--springcloud-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--通用mapper控制器-->
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper-spring-boot-starter</artifactId>
</dependency>
<!--mysql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
</dependencies>
</project>
项目结构:
mapper接口
package com.scbg.user.mapper;
import com.scbg.user.pojo.User;
import tk.mybatis.mapper.common.Mapper;
public interface UserMapper extends Mapper<User> { }
user实体类
package com.scbg.user.pojo;
import lombok.Data;
import tk.mybatis.mapper.annotation.KeySql;
import javax.persistence.Id;
import javax.persistence.Table;
import java.util.Date;
@Table(name="tb_user")//对应数据库表名
//@Data 我这里注解加入没成功。就手动写settergetter,否则不需要手动生成gettersetter
public class User {
//jpa的注解
@Id
@KeySql(useGeneratedKeys = true)
private Integer id;
private String userName;
private String password;
private String name;
private Integer age;
private Integer sex;
private Date birthday;
private Date created;
private Date updated;
private String note;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Integer getSex() {
return sex;
}
public void setSex(Integer sex) {
this.sex = sex;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public Date getCreated() {
return created;
}
public void setCreated(Date created) {
this.created = created;
}
public Date getUpdated() {
return updated;
}
public void setUpdated(Date updated) {
this.updated = updated;
}
public String getNote() {
return note;
}
public void setNote(String note) {
this.note = note;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", userName='" + userName + '\'' +
", password='" + password + '\'' +
", name='" + name + '\'' +
", age=" + age +
", sex=" + sex +
", birthday=" + birthday +
", created=" + created +
", updated=" + updated +
", note='" + note + '\'' +
'}';
}
}
package com.scbg.user.service;
import com.scbg.user.mapper.UserMapper;
import com.scbg.user.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
public User queryById(Integer id){
User user=userMapper.selectByPrimaryKey(id);
System.out.print(user.toString());
return userMapper.selectByPrimaryKey(id);
}
}
package com.scbg.user.controller;
import com.scbg.user.pojo.User;
import com.scbg.user.service.UserService;
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.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("user")
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/{id}")
public User queryById(@PathVariable Integer id){
User user=userService.queryById(id);
System.out.println(user);
return user;
}
}
springboot启动类
package com.scbg;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import tk.mybatis.spring.annotation.MapperScan;
@SpringBootApplication
@MapperScan("com.scbg.user.mapper")
public class UserApplication {
public static void main(String[] args) {
SpringApplication.run(UserApplication.class);
}
}
application.yml配置文件
server:
port: 8081
spring:
datasource:
url: jdbc:mysql://localhost:3306/~~自己的数据库名~~
username: ~~用户名~~
password: ~~密码~~
mybatis:
type-aliases-package: com.scbg.user.pojo
测试一下是否能够启动访问成功:
3)右键项目名创建consummer-demo模块,用以远程调用user-service模块的服务。
结构:
pom文件,不需要其他的,能启动就好。
<?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>cloud-demo</artifactId>
<groupId>com.scbg.demo</groupId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>consumer-demo</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
</project>
User实体类同上,但不需要一系列注解。这边也不需要跟数据库交互等
package com.scbg.consumer.pojo;
import java.util.Date;
public class User {
private Integer id;
private String userName;
private String password;
private String name;
private Integer age;
private Integer sex;
private Date birthday;
private Date created;
private Date updated;
private String note;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Integer getSex() {
return sex;
}
public void setSex(Integer sex) {
this.sex = sex;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public Date getCreated() {
return created;
}
public void setCreated(Date created) {
this.created = created;
}
public Date getUpdated() {
return updated;
}
public void setUpdated(Date updated) {
this.updated = updated;
}
public String getNote() {
return note;
}
public void setNote(String note) {
this.note = note;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", userName='" + userName + '\'' +
", password='" + password + '\'' +
", name='" + name + '\'' +
", age=" + age +
", sex=" + sex +
", birthday=" + birthday +
", created=" + created +
", updated=" + updated +
", note='" + note + '\'' +
'}';
}
}
controller层:用到了我们前边说的RestTemplate
package com.scbg.consumer.controller;
import com.scbg.consumer.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
@RestController
@RequestMapping("consumer")
public class ConsumerController {
@Autowired
private RestTemplate restTemplate;
@RequestMapping("{id}")
public User queryById(@PathVariable("id") Integer id){
String url="http://localhost:8081/user/"+id;
User user= restTemplate.getForObject(url,User.class);
return user;
}
}
启动类:
package com.scbg;
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 ConsumerApplication {
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class,args);
}
}
测试是否成功(保证user-service开启),注意浏览器端口,我们是访问consumer,consumer再去访问user-service将数据得到。
(题外话,但是很重要)
.服务间的调用方式:
这个问题一直困扰着我这个菜鸡。很多经验丰富的人也说不明白。举个栗子,同学A,硕士,送外卖的一家公司上班,36K,三年经验。我问他,你给我说一下webservice(这部分可以参考另一篇文章,没写完,主要现在基本不太用了)吧。不会,真的不会。我能理解,毕竟微服务用不到webservice。这本质上说明一个问题,很多程序员在做技术的时候没有全局意识。无论做的什么系统几乎都离不开服务之间的调用,如果他能意识到这一点,那么至少我应该得到的回答是:“webservice是一种古老的服务间调用的方式,基于soap协议,现在除了一些银行金融等项目外,几乎已经被Http+Rest全面取代”。
***困扰点: ***我以前一直搞不明白浏览器访问应用和应用间访问的区别。其实仔细想想,有个锤子区别。
本质上,都是调用访问。只不过我们在应用间系统调用时候,因为涉及自己的需求,将一些信息自己处理了。(比如说请求头,我们自己做了处理)。
1、服务间的调用目前基本两种方式:
1)RPC:远程过程调用,很多框架做了实现。典型代表:阿里系的Dubbo。(个人理解webservice也算一种)
自定义数据格式,效率快。
2)HTTP:微服务基本都用http+rest。
规定了数据格式,消息封装臃肿,效率比上边dubbo慢一点,但在能接受范围内。对双方使用语言及平台没有太明确要求,比较灵活(跨语言跨平台其实webservice也能做到)。
传输层都是基于TCP。(后期请展开一下说明一下)
二者选择方面(不是说微服务,微服务就http),项目老大说用啥就用啥,很多煞笔就喜欢用老的技术也没什么办法。如果有选择权,如果全Java技术栈,dubbo挺不错(应该说在Java方面目前国内最厉害的还是阿里)。如果可能涉及跨语言等,springcloud更胜一筹,而且spring全家桶自己的东西,整合起来也挺方便。
2.Http客户端
微服务选择了http。目前有很多开源客户端工具帮我们来实现请求和相应的处理,如:
1)HttpClient apache提供(用过)
2)OKHttp 见都没见过
3)HttpUrlConnection jdk提供的(用过)
三种API各不相同,spring对推出了RestTemplate对其进行整合,三种均支持,可指定。不指定,默认使用HttpUrlConnection。还实现了json和对象的序列化和反序列化,很方便。
代码待补充,回头请补个demo。