Spring Cloud微服务代码示例仓库
Spring Cloud微服务代码示例仓库
在Java微服务实战:Spring Cloud全家桶构建企业级分布式系统和Spring Cloud微服务架构图解文章中,我们详细介绍了Spring Cloud微服务架构的设计和实现。为了帮助读者更好地理解和实践这些技术,本文将提供一个完整的代码示例仓库,包含所有核心组件的实现代码。
代码仓库地址
GitHub仓库地址:https://github.com/xueyise/spring-cloud-microservice-example
仓库结构说明
spring-cloud-microservice-example/
├── doc/ # 文档目录
│ ├── architecture.md # 架构设计文档
│ ├── api-design.md # API设计规范
│ └── deployment.md # 部署指南
├── infrastructure/ # 基础设施配置
│ ├── docker-compose.yml # Docker Compose配置
│ ├── k8s/ # Kubernetes部署配置
│ │ ├── nacos.yaml
│ │ ├── mysql.yaml
│ │ ├── redis.yaml
│ │ └── services/
│ └── sql/ # 数据库脚本
│ ├── schema.sql
│ └── data.sql
├── platform/ # 平台服务
│ ├── eureka-server/ # Eureka注册中心
│ ├── gateway-service/ # API网关服务
│ └── monitor-service/ # 监控服务
├── services/ # 业务服务
│ ├── auth-service/ # 认证授权服务
│ │ ├── src/main/java/com/example/auth/
│ │ │ ├── AuthApplication.java
│ │ │ ├── config/ # 配置类
│ │ │ ├── controller/ # 控制器
│ │ │ ├── service/ # 业务服务
│ │ │ ├── repository/ # 数据访问层
│ │ │ ├── entity/ # 实体类
│ │ │ ├── dto/ # 数据传输对象
│ │ │ ├── exception/ # 异常处理
│ │ │ └── util/ # 工具类
│ │ └── pom.xml
│ ├── user-service/ # 用户服务
│ ├── order-service/ # 订单服务
│ ├── product-service/ # 商品服务
│ └── payment-service/ # 支付服务
├── common/ # 公共模块
│ ├── common-core/ # 核心公共模块
│ ├── common-web/ # Web公共模块
│ ├── common-security/ # 安全公共模块
│ └── common-swagger/ # Swagger公共模块
├── pom.xml # 父工程POM
├── README.md # 项目说明文档
└── LICENSE # 开源许可证
核心模块代码示例
1. 父工程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">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>spring-cloud-microservice-example</artifactId>
<version>1.0.0</version>
<packaging>pom</packaging>
<modules>
<module>platform/eureka-server</module>
<module>platform/gateway-service</module>
<module>services/auth-service</module>
<module>services/user-service</module>
<module>services/order-service</module>
<module>services/product-service</module>
<module>common</module>
</modules>
<properties>
<java.version>11</java.version>
<spring-boot.version>2.7.0</spring-boot.version>
<spring-cloud.version>2021.0.3</spring-cloud.version>
<spring-cloud-alibaba.version>2021.0.1.0</spring-cloud-alibaba.version>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencyManagement>
<dependencies>
<!-- Spring Boot -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- Spring Cloud -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- Spring Cloud Alibaba -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring-cloud-alibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- 公共模块 -->
<dependency>
<groupId>com.example</groupId>
<artifactId>common-core</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.example</groupId>
<artifactId>common-web</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.example</groupId>
<artifactId>common-security</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring-boot.version}</version>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
2. Nacos配置中心示例
# application.yml
spring:
application:
name: user-service
cloud:
nacos:
discovery:
server-addr: ${NACOS_SERVER_ADDR:127.0.0.1:8848}
config:
server-addr: ${NACOS_CONFIG_ADDR:127.0.0.1:8848}
file-extension: yaml
group: DEFAULT_GROUP
namespace: public
timeout: 3000
datasource:
url: jdbc:mysql://${MYSQL_HOST:localhost}:${MYSQL_PORT:3306}/${MYSQL_DB:microservice}?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
username: ${MYSQL_USERNAME:root}
password: ${MYSQL_PASSWORD:root}
driver-class-name: com.mysql.cj.jdbc.Driver
redis:
host: ${REDIS_HOST:localhost}
port: ${REDIS_PORT:6379}
password: ${REDIS_PASSWORD:}
database: ${REDIS_DATABASE:0}
timeout: 2000ms
server:
port: ${SERVER_PORT:8080}
logging:
level:
com.example: DEBUG
org.springframework.web: INFO
3. API网关配置示例
// GatewayApplication.java
@SpringBootApplication
@EnableDiscoveryClient
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}
}
# application.yml
server:
port: 9000
spring:
application:
name: gateway-service
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
gateway:
discovery:
locator:
enabled: true
lower-case-service-id: true
routes:
- id: auth-service
uri: lb://auth-service
predicates:
- Path=/api/auth/**
filters:
- StripPrefix=2
- id: user-service
uri: lb://user-service
predicates:
- Path=/api/users/**
filters:
- StripPrefix=2
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 10
redis-rate-limiter.burstCapacity: 20
key-resolver: "#{@userKeyResolver}"
- id: order-service
uri: lb://order-service
predicates:
- Path=/api/orders/**
filters:
- StripPrefix=2
- id: product-service
uri: lb://product-service
predicates:
- Path=/api/products/**
filters:
- StripPrefix=2
default-filters:
- DedupeResponseHeader=Access-Control-Allow-Credentials Access-Control-Allow-Origin
- AddResponseHeader=X-Response-Default-Foo, Default-Bar
management:
endpoints:
web:
exposure:
include: "*"
endpoint:
gateway:
enabled: true
4. RBAC权限控制示例
// SecurityConfig.java
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig {
@Autowired
private JwtAuthenticationEntryPoint unauthorizedHandler;
@Autowired
private JwtAccessDeniedHandler accessDeniedHandler;
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public AuthenticationManager authenticationManager(
AuthenticationConfiguration authConfig) throws Exception {
return authConfig.getAuthenticationManager();
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.csrf().disable()
.exceptionHandling()
.authenticationEntryPoint(unauthorizedHandler)
.accessDeniedHandler(accessDeniedHandler)
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/auth/**").permitAll()
.antMatchers("/actuator/**").permitAll()
.anyRequest().authenticated();
http.addFilterBefore(jwtAuthenticationFilter(),
UsernamePasswordAuthenticationFilter.class);
return http.build();
}
}
// JwtUtil.java
@Component
public class JwtUtil {
@Value("${jwt.secret:mySecretKey}")
private String secret;
@Value("${jwt.expiration:86400}")
private Long expiration;
public String generateToken(UserDetails userDetails) {
Map<String, Object> claims = new HashMap<>();
return createToken(claims, userDetails.getUsername());
}
private String createToken(Map<String, Object> claims, String subject) {
return Jwts.builder()
.setClaims(claims)
.setSubject(subject)
.setIssuedAt(new Date(System.currentTimeMillis()))
.setExpiration(new Date(System.currentTimeMillis() + expiration * 1000))
.signWith(SignatureAlgorithm.HS512, secret)
.compact();
}
public Boolean validateToken(String token, UserDetails userDetails) {
final String username = getUsernameFromToken(token);
return (username.equals(userDetails.getUsername()) && !isTokenExpired(token));
}
public String getUsernameFromToken(String token) {
return getClaimFromToken(token, Claims::getSubject);
}
public Date getExpirationDateFromToken(String token) {
return getClaimFromToken(token, Claims::getExpiration);
}
public <T> T getClaimFromToken(String token, Function<Claims, T> claimsResolver) {
final Claims claims = getAllClaimsFromToken(token);
return claimsResolver.apply(claims);
}
private Claims getAllClaimsFromToken(String token) {
return Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();
}
private Boolean isTokenExpired(String token) {
final Date expiration = getExpirationDateFromToken(token);
return expiration.before(new Date());
}
}
5. 分布式事务示例
// OrderService.java
@Service
@Slf4j
public class OrderServiceImpl implements OrderService {
@Autowired
private OrderRepository orderRepository;
@Autowired
private ProductServiceFeignClient productServiceFeignClient;
@Autowired
private AccountServiceFeignClient accountServiceFeignClient;
@GlobalTransactional
@Override
public OrderDTO createOrder(CreateOrderRequest request) {
log.info("开始创建订单,用户ID: {}, 商品ID: {}",
request.getUserId(), request.getProductId());
// 1. 验证用户和商品
Result<UserDTO> userResult = accountServiceFeignClient.getUserById(request.getUserId());
if (!userResult.isSuccess() || userResult.getData() == null) {
throw new BusinessException("用户不存在");
}
Result<ProductDTO> productResult = productServiceFeignClient.getProductById(request.getProductId());
if (!productResult.isSuccess() || productResult.getData() == null) {
throw new BusinessException("商品不存在");
}
ProductDTO product = productResult.getData();
// 2. 检查库存
if (product.getStock() < request.getQuantity()) {
throw new BusinessException("库存不足");
}
// 3. 创建订单
Order order = new Order();
order.setUserId(request.getUserId());
order.setProductId(request.getProductId());
order.setQuantity(request.getQuantity());
order.setAmount(product.getPrice().multiply(BigDecimal.valueOf(request.getQuantity())));
order.setStatus(OrderStatus.CREATED);
orderRepository.save(order);
// 4. 调用商品服务扣减库存
DecreaseStockRequest decreaseStockRequest = new DecreaseStockRequest();
decreaseStockRequest.setProductId(request.getProductId());
decreaseStockRequest.setQuantity(request.getQuantity());
Result<Boolean> stockResult = productServiceFeignClient.decreaseStock(decreaseStockRequest);
if (!stockResult.isSuccess() || !stockResult.getData()) {
throw new BusinessException("扣减库存失败");
}
// 5. 调用账户服务扣减余额
DecreaseBalanceRequest decreaseBalanceRequest = new DecreaseBalanceRequest();
decreaseBalanceRequest.setUserId(request.getUserId());
decreaseBalanceRequest.setAmount(order.getAmount());
Result<Boolean> balanceResult = accountServiceFeignClient.decreaseBalance(decreaseBalanceRequest);
if (!balanceResult.isSuccess() || !balanceResult.getData()) {
throw new BusinessException("扣减余额失败");
}
log.info("订单创建成功,订单ID: {}", order.getId());
return convertToDTO(order);
}
}
部署说明
Docker部署
# 构建所有服务镜像
mvn clean package -DskipTests
# 启动基础设施
docker-compose -f infrastructure/docker-compose.yml up -d
# 启动各个服务
docker-compose -f services/auth-service/docker-compose.yml up -d
docker-compose -f services/user-service/docker-compose.yml up -d
docker-compose -f services/order-service/docker-compose.yml up -d
docker-compose -f services/product-service/docker-compose.yml up -d
Kubernetes部署
# 部署基础设施
kubectl apply -f infrastructure/k8s/nacos.yaml
kubectl apply -f infrastructure/k8s/mysql.yaml
kubectl apply -f infrastructure/k8s/redis.yaml
# 部署服务
kubectl apply -f infrastructure/k8s/services/auth-service.yaml
kubectl apply -f infrastructure/k8s/services/user-service.yaml
kubectl apply -f infrastructure/k8s/services/order-service.yaml
kubectl apply -f infrastructure/k8s/services/product-service.yaml
运行环境要求
- JDK: 11或更高版本
- Maven: 3.6.0或更高版本
- Docker: 20.10或更高版本(可选)
- Kubernetes: 1.20或更高版本(可选)
- MySQL: 8.0或更高版本
- Redis: 6.0或更高版本
- Nacos: 2.0或更高版本
使用说明
-
克隆代码仓库:
git clone https://github.com/xueyise/spring-cloud-microservice-example.git -
初始化数据库:
mysql -u root -p < infrastructure/sql/schema.sql mysql -u root -p < infrastructure/sql/data.sql -
启动Nacos服务:
cd infrastructure/nacos sh startup.sh -m standalone -
编译打包:
mvn clean package -DskipTests -
启动各个服务:
java -jar platform/eureka-server/target/eureka-server-1.0.0.jar java -jar platform/gateway-service/target/gateway-service-1.0.0.jar java -jar services/auth-service/target/auth-service-1.0.0.jar java -jar services/user-service/target/user-service-1.0.0.jar
贡献指南
欢迎对本项目进行贡献!请遵循以下步骤:
- Fork本仓库
- 创建功能分支 (
git checkout -b feature/AmazingFeature) - 提交更改 (
git commit -m 'Add some AmazingFeature') - 推送到分支 (
git push origin feature/AmazingFeature) - 开启Pull Request
许可证
本项目采用MIT许可证,详情请参见LICENSE文件。
本文由xueyise创作,提供Spring Cloud微服务代码示例仓库