本篇文章将细述从0到1搭建一个微服务项目的整个过程.
- 如何通过IDEA新建spring boot项目
- 如何优化项目配置得到更好的开发体验
- 如何使用
Spring Cloud Openfeign进行远程调用 - 如何集成
Nacos实现服务发现与注册 OpenFeign如何整合Nacos进行服务动态调用与负载均衡
本文源代码仓库地址: z2o
- 本文对部分功能的原理不会做解释, 如果需要可评论区提问
准备
- IDEA 2024.x (可以通过ToolBox下载对应版本, 无Utl版可选择社区版或EAP版)
- Nacos 2.4.x (可以暂时使用本人提供的
共享Nacos服务, 请注意该服务会在2024年12月底停止)
正式开始
项目初始化
打开IDEA的New project/新建项目页面
如何打开这个页面?
- 如果是第一次进入或上次一关闭项目是通过
Close project/关闭项目的则打开IDEA时会弹出Welcome界面, 在Welcome界面点击Create new project/新建项目, 则会弹出新建项目页面- 如果IDEA已经打开了某个项目, 则点击左上角
File/文件-> 选择New/新建-> 选择project/项目, 则会弹出新建项目页面
在New project/新建项目页面左侧选择Spring Boot, 并配置项目的基本信息
注意事项
- 如果是国内建议修改spring boot initialize配置.
- 如果本地的没有JDK或者JDK < 17的话可以在选择JDK的下拉菜单中直接下载
填完消息后点击Next/下一步, 进入选择依赖项页面(按需选择)
然后点击Create/创建就能新建Spring Boot项目了
配置项目
Maven配置优化
编辑pom.xml文件, 覆盖原来在最下面的</build>标签(添加该配置后就无需配置maven的settings.xml文件)
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<encoding>${project.build.sourceEncoding}</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<version>3.1.3</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<encoding>${project.build.sourceEncoding}</encoding>
</configuration>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>Default</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<repositories>
<repository>
<id>public</id>
<name>aliyun nexus</name>
<url>https://maven.aliyun.com/repository/public</url>
<releases>
<enabled>true</enabled>
</releases>
</repository>
<repository>
<id>central-repos</id>
<name>Central Repository</name>
<url>https://repo.maven.apache.org/maven2</url>
</repository>
<repository>
<id>central</id>
<url>https://maven.aliyun.com/nexus/content/groups/public</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>snapshots</id>
<url>https://maven.aliyun.com/nexus/content/groups/public</url>
<releases>
<enabled>false</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
</profile>
</profiles>
添加后需要执行一次mvn clean install命令
软件包作用说明
SpringBoot项目的软件包大体分为四类,
- 业务代码:
src.main.java.<groupId> - 资源文件:
src.main.java.resources - 测试代码:
src.main.test - 编译结果:
target(通过执行mvn compile / mvn install生成)
spring配置修改
将resources包下原有的application.properties重命名为application.yml, 并使用一下内容覆盖原有内容
server:
servlet:
# 声明请求当前服务接口时的前缀
context-path: /z2o
# 声明请求当前服务接口时的端口, 默认8080
port: 8000
spring:
application:
name: z2o
在执行完这一步后可以测试性地启动项目, 看是否有问题
接口声明
添加后续需要使用的四个 类/接口
在SimpleController中声明接口并启动项目
@RestController
@RequestMapping("/simple")
public class SimpleController {
@GetMapping("/hello/spring_boot")
public String helloSpringBoot() {
return "Hello Spring Boot!";
}
}
声明完成后点击方法名左侧的图标 直接生成请求, 然后点击执行即可请求该接口
使用Openfeign进行远程调用
在这一步 我们通过请求接口来得到另一个接口的返回值, 这就是Feign接口的主要用途与用法
编辑SimpleControllerClient
@FeignClient(
contextId = "SimpleControllerClient",
value = "z2o",
path = "/z2o/simple",
url = "localhost:${server.port:8080}")
public interface SimpleControllerClient {
@GetMapping("/hello/spring_boot")
String helloSpringBoot();
}
编辑SimpleController
@RestController
@RequestMapping("/simple")
public class SimpleController {
@Resource private SimpleControllerClient simpleControllerClient;
@GetMapping("/hello/spring_boot")
public String helloSpringBoot() {
return "Hello Spring Boot!";
}
@GetMapping("/hello/feign")
public String helloFeign() {
return simpleControllerClient.helloSpringBoot();
}
}
同上请求新声明的controller中的/hello/feign接口即可得到/hello/spring_boot的返回值.
Feign使用优化
在正式项目中不会每个服务以及仓库都定义一套Feign, 而是会将Feign归类抽离到一个公共仓库中, 这样只需要声明一套Feign接口就能在多个仓库/服务中使用.
编辑SimpleApiClient
@FeignClient(
contextId = "SimpleApiClient",
value = "z2o",
path = "/z2o/simple/api",
url = "localhost:${server.port:8080}")
public interface SimpleApiClient {
@GetMapping("/hello/open_feign")
String helloOpenFeign();
}
编辑SimpleApi
@RestController
@RequestMapping("/simple/api")
public class SimpleApi implements SimpleApiClient {
@Override
public String helloOpenFeign() {
return "It's random number: " + Math.random();
}
}
在这个示例中, 通过实现Feign定义的接口来声明其所调用的端点(即接口).
实现类中不需要再次声明方法对应的请求路径, 只需要声明类的请求路径即可
Feign整合Nacos
引入Nacos依赖并配置
在pom.xml文件中添加如下配置
添加dependencyManagement
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2023.0.1.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
添加dependency
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
在application.yml文件中配置Nacos参数
spring:
application:
name: z2o
cloud:
nacos:
discovery:
enabled: true
server-addr: 120.77.239.177:8848
编辑SimpleApiClient(去掉@FeignClient中的url参数)
@FeignClient(
contextId = "SimpleApiClient",
value = "z2o",
path = "/z2o/simple/api")
public interface SimpleApiClient {
@GetMapping("/hello/open_feign")
String helloOpenFeign();
}
编辑SimpleController
@RestController
@RequestMapping("/simple")
public class SimpleController {
@Resource private SimpleControllerClient simpleControllerClient;
@GetMapping("/hello/spring_boot")
public String helloSpringBoot() {
return "Hello Spring Boot!";
}
@GetMapping("/hello/feign")
public String helloFeign() {
return simpleControllerClient.helloSpringBoot();
}
@Resource private SimpleApiClient simpleApiClient;
@GetMapping("/hello/nacos_feign")
public String helloNacosFeign() {
return simpleApiClient.helloOpenFeign();
}
}
重启项目, 并请求helloNacosFeign接口, 可以通过Feign调用SimpleApi中声明的接口
可以到Nacos中查看是否成功注册(如果有其他人注册了相同的服务名 可通过修改服务名进行区别化, 或者查看集群服务的节点IP中是否有你的IP [由于是内网 可能IP重复] )
也可通过注册不同group实现区别化, 详见git提交记录
解析
在原有的Feign声明中, 由于指定了Feign调用端口的URL 所以无法路由到其他IP的相同服务, 也无法进行负载均衡.
通过而引入Nacos则很好的解决了这个问题, 一次Feign调用将通过服务名(o2z)拉取对应注册到Nacos中的集群列表, 并通过nacos中配置的权重对请求进行路由