Spring Cloud服务提供者与服务消费者怎么运作的?
在微服务中最基本最基本的两个角色是服务提供者与服务消费者。 之前所有代码都在同一个框架的时候,比如Controller调用Service的,直接注入Service bean即可进行调用了。现在做成微服务之后,那么我们就需要有一个工程专门提供相应的服务功能,对应的有相应的工程消费这个功能,这就是服务提供者和服务消费者最基本的概念。 目录大纲: (1)服务提供者与服务消费者概念(2)编码思路(3)服务提供者编码(4)服务消费者编码(5)存在问题 接下来看下具体的内容: (1)服务提供者与服务消费者概念 服务提供者:服务的被调用方(即,为其他服务提供服务的服务); 服务消费者:服务的调用方(即,依赖其他服务的服务); (2)编码思路 这里我们使用最基本的方式实现服务提供者和服务消费者。 (1)两个项目,一个服务提供者,一个是服务消费者; (2)服务提供者从内存数据库H2中查询数据,Controller进行调用获取; (3)服务消费者调用服务提供者的Controller进行获取数据,然后返回给浏览器。 (3)服务提供者编码 新建工程 新建一个提供用户信息的工程,取名为:microservie-provider-user 在pom.xml添加依赖包 Xml代码 <projectxmlns="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.0http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.kfit</groupId> <artifactId>ms-provider-user</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>ms-provider-user</name> <url>http://maven.apache.org</url> <!--springbootparent节点,引入这个之后,在下面和springboot相关的就不需要引入版本了;--> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.4.1.RELEASE</version> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <dependencies> <!--web支持:1、webmvc;2、restful;3、jackjson支持;4、aop........--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--内存数据库h2--> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <scope>runtime</scope> </dependency> <!--springdatajpa--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> </dependencies> </project> 在src/main/resources下新建schema.sql添加建表语句 创建了一张User表: Sql代码 droptableuserifexists; createtableuser( idbigintgeneratedbydefaultasidentity, usernamevarchar(40), namevarchar(20), ageint(3), balancedecimal(10,2), primarykey(id) ); 在src/main/resources/新建data.sql插入数据 在User表插入几条数据进行测试: Sql代码 insertintouser(id,username,name,age,balance)values(1,'user1','张三',20,100.00); insertintouser(id,username,name,age,balance)values(2,'user2','李四',20,100.00); insertintouser(id,username,name,age,balance)values(3,'user3','王五',20,100.00); insertintouser(id,username,name,age,balance)values(4,'user4','赵六',20,100.00); 创建实体类User Java代码 @JsonIgnoreProperties({"hibernateLazyInitializer","handler"}) @Entity publicclassUserimplementsSerializable{ privatestaticfinallongserialVersionUID=1L; @Id@GeneratedValue privatelongid;//主键. privateStringusername;//用户名. privateStringname;//姓名 privateintage;//年龄. privateBigDecimalbalance;//余额. } 为什么要加@JsonIgnoreProperties呢? 问题在于,使用load方法,您只需要一个代理,而不是真正的对象。代理对象没有已经加载的属性,所以当序列化发生时,没有要序列化的属性。使用get方法,您实际上可以获得真正的对象,这个对象实际上可以被序列化。 具体可以参考文章:https://my.oschina.net/lieefu/blog/680098 创建Dao类UserRepository Java代码 publicinterfaceUserRepositoryextendsJpaRepository<User,Long>{ } 创建Service类UserService Java代码 @Service publicclassUserService{ @Autowired privateUserRepositoryuserRepository; publicUsergetById(longid){ returnuserRepository.getOne(id); } } 创建Controller类UserController Java代码 @RestController publicclassUserController{ @Autowired privateUserServiceuserService; @GetMapping("/user/{id}") publicUsergetById(@PathVariablelongid){ Useruser=userService.getById(id); System.out.println(user); returnuser; } } 在src/main/resources新建application.properties 主要是配置端口号和jpa配置: Properties代码 server.port=7900 spring.jpa.generate-ddl=false spring.jpa.show-sql=true spring.jpa.hibernate.ddl-auto=none spring.datasource.platform=h2 spring.datasource.schema=classpath:schema.sql spring.datasource.data=classpath:data.sql logging.level.root=INFO logging.level.org.hibernate=INFO 编写启动类 Java代码 @SpringBootApplication publicclassApp{ publicstaticvoidmain(String[]args){ SpringApplication.run(App.class,args); } } 启动App测试 启动访问:http://127.0.0.1:7900/user/1可以在浏览器中看到返回信息: {"id":1,"username":"user1","name":"张三","age":20,"balance":100.00} 到此服务提供者就编写完毕了,这个代码没有什么特别之处,和我们常规代码编写是一样的!。 (4)服务消费者编码 新建工程 新建一个服务消费者项目,取名为:microservice-consumer-movice 在pom.xml添加依赖包 Xml代码 <projectxmlns="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.0http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.kfit</groupId> <artifactId>ms-consumer-movice</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>ms-consumer-movice</name> <url>http://maven.apache.org</url> <!--springbootparent节点,引入这个之后,在下面和springboot相关的就不需要引入版本了;--> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.8.RELEASE</version> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <dependencies> <!--web支持:1、webmvc;2、restful;3、jackjson支持;4、aop........--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies> </project> 新建实体类User Java代码 publicclassUserimplementsSerializable{ privatestaticfinallongserialVersionUID=1L; privatelongid;//主键. privateStringusername;//用户名. privateStringname;//姓名 privateintage;//年龄. privateBigDecimalbalance;//余额. } 新建Controller类MoviceController Java代码 @RestController publicclassMoviceController{ @Autowired privateRestTemplaterestTemplate; @GetMapping("/user/{id}") publicUsergetById(longid){ Stringurl="http://127.0.0.1:7900/user/"+id; returnrestTemplate.getForObject(url,User.class); } } 在src/main/resources新建application.properties 这里只配置了端口号: server.port=7901 新建启动类App.java Java代码 @SpringBootApplication publicclassApp{ @Bean publicRestTemplaterestTemplate(){ returnnewRestTemplate(); } publicstaticvoidmain(String[]args){ SpringApplication.run(App.class,args); } } 这里将RestTemplate进行初始化,交给Spring进行管理。 启动测试 启动访问:http://127.0.0.1:7901/user/2,返回给浏览器信息: {"id":2,"username":"user2","name":"李四","age":20,"balance":100.00} (5)存在问题 该例子简单易理解,但是存在很多的问题,比如: (1)请求地址(http://127.0.0.1:7900/user/)硬编码了; (2)当有多个提供者节点的时候,怎么进行负载,基本想法可以在提供者和消费者中间加一个反向代理,但是服务太多的时候不利于管理。