一、首先编写微服务基础项目framework
1、pom.xml
1 <?xml version="1.0" encoding="UTF-8"?> 2 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 3 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> 4 5 <modelVersion>4.0.0</modelVersion> 6 7 <parent> 8 <groupId>org.springframework.boot</groupId> 9 <artifactId>spring-boot-starter-parent</artifactId> 10 <version>1.3.0.RELEASE</version> 11 </parent> 12 13 <groupId>com.microservice</groupId> 14 <artifactId>framework</artifactId> 15 <version>1.0-SNAPSHOT</version> 16 <packaging>jar</packaging> 17 18 <properties> 19 <java.version>1.8</java.version><!-- 官方推荐 --> 20 </properties> 21 22 <!-- 引入实际依赖 --> 23 <dependencies> 24 <dependency> 25 <groupId>org.springframework.boot</groupId> 26 <artifactId>spring-boot-starter-web</artifactId> 27 </dependency> 28 <!-- consul-client --> 29 <dependency> 30 <groupId>com.orbitz.consul</groupId> 31 <artifactId>consul-client</artifactId> 32 <version>0.10.0</version> 33 </dependency> 34 <!-- consul需要的包 --> 35 <dependency> 36 <groupId>org.glassfish.jersey.core</groupId> 37 <artifactId>jersey-client</artifactId> 38 <version>2.22.2</version> 39 </dependency> 40 <dependency> 41 <groupId>com.alibaba</groupId> 42 <artifactId>fastjson</artifactId> 43 <version>1.1.15</version> 44 </dependency> 45 <dependency> 46 <groupId>org.springframework.boot</groupId> 47 <artifactId>spring-boot-starter-actuator</artifactId> 48 </dependency> 49 <dependency> 50 <groupId>org.projectlombok</groupId> 51 <artifactId>lombok</artifactId> 52 <version>1.16.8</version> 53 <scope>provided</scope> 54 </dependency> 55 </dependencies> 56 57 <build> 58 <plugins> 59 <plugin> 60 <groupId>org.springframework.boot</groupId> 61 <artifactId>spring-boot-maven-plugin</artifactId> 62 </plugin> 63 </plugins> 64 </build> 65 </project>
说明:
- 上边的<packaging>jar</packaging>可以去掉。因为spring-boot-maven-plugin会打jar包的
- 引入spring-boot-starter-actuator是为了注册服务的时候可以直接使用"http://localhost:8080/health"进行健康检查。见第二十章 springboot + consul
- 注意:health的port不是固定的8080,而是服务启动的接口,如果服务是以8090启动,使用"http://localhost:8090/health"来检查
2、com.microservice.framework.MySpringAplication
1 package com.microservice.framework; 2 3 import org.springframework.boot.SpringApplication; 4 import org.springframework.boot.autoconfigure.SpringBootApplication; 5 6 import com.microservice.framework.consul.ConsulRegisterListener; 7 8 /** 9 * 注意:@SpringBootApplication该注解必须在SpringApplication.run()所在的类上 10 * 11 */ 12 @SpringBootApplication 13 public class MySpringAplication { 14 15 public void run(String[] args) { 16 SpringApplication sa = new SpringApplication(MySpringAplication.class); 17 sa.addListeners(new ConsulRegisterListener()); 18 sa.run(args); 19 } 20 21 public static void main(String[] args) { 22 } 23 }
注意:这里的main方法声明是要有的(否则无法install为jar)。
3、com.microservice.framework.consul.ConsulRegisterListener
1 package com.microservice.framework.consul; 2 3 import java.net.MalformedURLException; 4 import java.net.URI; 5 6 import org.springframework.context.ApplicationListener; 7 import org.springframework.context.event.ContextRefreshedEvent; 8 9 import com.orbitz.consul.AgentClient; 10 import com.orbitz.consul.Consul; 11 12 /** 13 * 监听contextrefresh事件 14 */ 15 public class ConsulRegisterListener implements ApplicationListener<ContextRefreshedEvent> { 16 17 @Override 18 public void onApplicationEvent(ContextRefreshedEvent event) { 19 Consul consul = event.getApplicationContext().getBean(Consul.class); 20 ConsulProperties prop = event.getApplicationContext().getBean(ConsulProperties.class); 21 22 AgentClient agentClient = consul.agentClient(); 23 try { 24 agentClient.register(prop.getServicePort(), 25 URI.create(prop.getHealthUrl()).toURL(), 26 prop.getHealthInterval(), 27 prop.getServicename(), 28 prop.getServicename(), // serviceId: 29 prop.getServiceTag()); 30 } catch (MalformedURLException e) { 31 e.printStackTrace(); 32 } 33 } 34 35 }
注意:这个代码是关键,后边会讲改代码的作用。
其中,ConsulProperties和Consul我们需要在代码中构建成Bean(如下变4和5),之后才能从容器中取出来,否则为null。
4、com.microservice.framework.consul.ConsulProperties
1 package com.microservice.framework.consul; 2 3 import org.springframework.beans.factory.annotation.Value; 4 import org.springframework.stereotype.Component; 5 6 import lombok.Getter; 7 import lombok.Setter; 8 9 @Component 10 @Getter @Setter 11 public class ConsulProperties { 12 13 @Value("${service.name}") 14 private String servicename; 15 @Value("${service.port:8080}") 16 private int servicePort; 17 @Value("${service.tag:dev}") 18 private String serviceTag; 19 // @Value("${serviceIp:localhost}") 20 // private String serviceIp; 21 22 @Value("${health.url}") 23 private String healthUrl; 24 @Value("${health.interval:10}") 25 private int healthInterval; 26 27 }
注意:
- 这里使用lombok简化了pojo
- @value注解中可以指定默认值,查看上边":"后边的值就是
5、com.microservice.framework.consul.ConsulConfig
1 package com.microservice.framework.consul; 2 3 import org.springframework.context.annotation.Bean; 4 import org.springframework.context.annotation.Configuration; 5 6 import com.orbitz.consul.Consul; 7 8 @Configuration 9 public class ConsulConfig { 10 11 @Bean 12 public Consul consul(){ 13 return Consul.builder().build(); 14 } 15 }
编写完上述代码后,执行"mvn clean install",如果成功的话,此时"framework-1.0-SNAPSHOT.jar"这个jar就会装载到本地的.m2/repository/com/microservice/framework/q.0-SNAPSHOT中了(mac中.m2默认在~下)
二、开发第一个微服务myserviceA
像上边所示,我们创建了client和server。
- server:用于实现具体逻辑
- client:用于封装server接口(通常就是server模块的controller中的各个url),提供给其他service或gateway甚至是app使用
1、myserviceA
pom.xml
1 <?xml version="1.0" encoding="UTF-8"?> 2 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 3 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> 4 5 <modelVersion>4.0.0</modelVersion> 6 7 <parent> 8 <groupId>org.springframework.boot</groupId> 9 <artifactId>spring-boot-starter-parent</artifactId> 10 <version>1.3.0.RELEASE</version> 11 </parent> 12 13 <groupId>com.microservice</groupId> 14 <artifactId>myserviceA</artifactId> 15 <version>1.0-SNAPSHOT</version> 16 <packaging>pom</packaging> 17 18 <properties> 19 <java.version>1.8</java.version><!-- 官方推荐 --> 20 </properties> 21 22 <modules> 23 <module>server</module> 24 <module>client</module> 25 </modules> 26 27 <!-- 引入实际依赖 --> 28 <dependencies> 29 <dependency> 30 <groupId>org.springframework.boot</groupId> 31 <artifactId>spring-boot-starter-web</artifactId> 32 </dependency> 33 </dependencies> 34 </project>
2、myserviceA-server
2.1、pom.xml
1 <?xml version="1.0" encoding="UTF-8"?> 2 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 3 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> 4 5 <modelVersion>4.0.0</modelVersion> 6 7 <parent> 8 <groupId>com.microservice</groupId> 9 <artifactId>myserviceA</artifactId> 10 <version>1.0-SNAPSHOT</version> 11 </parent> 12 13 <artifactId>myserviceA-server</artifactId> 14 15 <!-- 引入实际依赖 --> 16 <dependencies> 17 <dependency> 18 <groupId>com.microservice</groupId> 19 <artifactId>framework</artifactId> 20 <version>1.0-SNAPSHOT</version> 21 </dependency> 22 <dependency> 23 <groupId>com.alibaba</groupId> 24 <artifactId>fastjson</artifactId> 25 <version>1.1.15</version> 26 </dependency> 27 </dependencies> 28 29 <build> 30 <plugins> 31 <plugin> 32 <groupId>org.springframework.boot</groupId> 33 <artifactId>spring-boot-maven-plugin</artifactId> 34 </plugin> 35 </plugins> 36 </build> 37 </project>
2.2、application.properties
1 service.name=myserviceA 2 service.port=8080 3 service.tag=dev 4 health.url=http://localhost:8080/health 5 health.interval=10
说明:
- service.name(这是一个service在注册中心的唯一标识)
- service.port
- service.tag(该值用于在注册中心的配置管理,dev环境下使用dev的配置,prod下使用prod的配置,配置管理通常使用KV来实现的,tag用于构建Key)
- health.url(健康检查的url)
- health.interval(每隔10s ping一次health.url,进行健康检查)
2.3、com.microservice.myserviceA.MyServiceAApplication
1 package com.microservice.myserviceA; 2 3 import org.springframework.boot.autoconfigure.SpringBootApplication; 4 5 import com.microservice.framework.MySpringAplication; 6 7 @SpringBootApplication 8 public class MyServiceAApplication { 9 10 public static void main(String[] args) { 11 MySpringAplication mySpringAplication = new MySpringAplication(); 12 mySpringAplication.run(args); 13 } 14 }
说明:这里调用了framework中的MySpringAplication的run(),该run()首先初始化了SpringApplication实例,之后为该实例添加ConsulRegisterListener实例,最后再执行SpringApplication的run()。
ConsulRegisterListener的执行时机见附4 springboot源码解析-run(),简言之,就是
- run()方法会先构建容器ApplicationContext,之后将各个BeanDefinition装入该容器,最后刷新容器,这时候执行ConsulRegisterListener中的onApplication方法,用于注册service到consul。
3、myserviceA-client
pom.xml
1 <?xml version="1.0" encoding="UTF-8"?> 2 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 3 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> 4 5 <modelVersion>4.0.0</modelVersion> 6 7 <parent> 8 <groupId>com.microservice</groupId> 9 <artifactId>myserviceA</artifactId> 10 <version>1.0-SNAPSHOT</version> 11 </parent> 12 13 <artifactId>myserviceA-client</artifactId> 14 15 <build> 16 <plugins> 17 <plugin> 18 <groupId>org.springframework.boot</groupId> 19 <artifactId>spring-boot-maven-plugin</artifactId> 20 </plugin> 21 </plugins> 22 </build> 23 </project>
该client以后在需要用到的时候完成。
测试:启动consul,开发环境下,直接使用"consul agent -dev"快速启动,查看consul UI,如下:
启动"myserviceA-server",启动完成后,查看consul UI,如下:
表示注册成功,我们还可以查看myserviceA的健康检查URL,如下:
以上就完成了基本微服务架构的搭建与服务启动时自动注册!