本文介绍了Java分布式入门的基础知识,包括分布式系统的基本概念、特点和优势。文章还详细讲解了Java中的网络通信、进程间通信、常见分布式框架如ZooKeeper、Spring Cloud和Dubbo的使用方法。此外,还涉及了分布式数据存储、缓存技术和分布式部署的相关内容。
分布式系统简介 什么是分布式系统分布式系统是由多台计算机和网络设备通过网络连接在一起,共同协同工作以完成特定任务的系统。分布式系统中的计算机可以位于不同的位置,并通过网络进行通信。分布式系统的核心目标是提高系统的可用性、可靠性和性能。分布式系统可以看作是一个整体,但每个部分都可以独立运行和维护。
分布式系统的特点和优势特点
- 透明性:用户无需关心数据和计算资源的分布情况,可以像使用单一系统一样使用分布式系统。
- 可靠性:分布式系统可以容忍部分节点的故障,确保整体系统的高可用性和稳定性。
- 可扩展性:可以通过添加更多的节点来增强系统的处理能力和存储能力。
- 灵活性:分布式系统可以根据需要动态调整资源分配,适应不同的应用场景。
- 负载均衡:通过合理分配任务,确保每个节点的负载均衡,提高系统整体性能。
优势
- 高可用性:分布式系统可以设计成在部分节点故障时仍能继续提供服务。
- 可伸缩性:系统可以根据业务需求进行水平或垂直扩展,以适应不同的负载。
- 高效性:通过并行处理和负载均衡,可以显著提高系统处理速度和效率。
- 灵活部署:分布式系统可以在不同的物理位置部署,适应不同的网络环境和业务需求。
分布式系统应用场景广泛,包括但不限于以下领域:
- 云计算:云计算平台(如阿里云、腾讯云等)利用分布式系统提供计算、存储和网络服务。
- 大数据处理:Hadoop、Spark等大数据处理框架利用分布式系统进行大规模数据集的并行处理。
- 微服务架构:Spring Cloud、Docker等技术框架利用分布式系统实现服务的解耦和独立可扩展性。
- 实时数据处理:流处理系统如Apache Kafka、Flink等利用分布式系统进行实时数据处理和分析。
- 高并发系统:如电商网站、社交平台等,通过分布式系统实现高并发访问和响应。
- 互联网应用:多个用户同时访问同一个系统,分布式系统可以有效提升系统性能和稳定性。
网络通信基础
Socket编程简介
Socket编程是Java网络通信的基础,它允许不同主机上的进程通过网络进行通信。Java提供了Socket类和ServerSocket类来实现客户端和服务器之间的网络通信。
Socket
:用于客户端连接服务器,表示一个具体的连接。ServerSocket
:用于服务器端监听客户端的连接请求,只有一个端口。
示例代码
客户端代码示例
import java.io.*;
import java.net.*;
public class Client {
public static void main(String[] args) {
try (Socket socket = new Socket("localhost", 12345)) {
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
out.write("Hello Server");
out.newLine();
out.flush();
String response = in.readLine();
System.out.println("Server Response: " + response);
} catch (IOException e) {
e.printStackTrace();
}
}
}
服务器端代码示例
import java.io.*;
import java.net.*;
public class Server {
public static void main(String[] args) {
try (ServerSocket serverSocket = new ServerSocket(12345)) {
System.out.println("Server started on port 12345");
Socket clientSocket = serverSocket.accept();
System.out.println("Client connected");
BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(clientSocket.getOutputStream()));
String clientMessage = in.readLine();
System.out.println("Message from client: " + clientMessage);
out.write("Hello Client");
out.newLine();
out.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}
TCP和UDP协议概述
- TCP(传输控制协议):面向连接的传输协议,提供可靠的数据传输,确保数据传输的顺序性和完整性。
- UDP(用户数据报协议):无连接的传输协议,传输效率高,但不保证数据的顺序性和完整性。
示例代码
使用DatagramSocket
实现UDP通信
客户端代码
import java.io.*;
import java.net.*;
public class UDPClient {
public static void main(String[] args) {
try (DatagramSocket socket = new DatagramSocket()) {
String message = "Hello Server";
InetAddress address = InetAddress.getByName("localhost");
int port = 12346;
byte[] buffer = message.getBytes();
DatagramPacket packet = new DatagramPacket(buffer, buffer.length, address, port);
socket.send(packet);
buffer = new byte[100];
packet = new DatagramPacket(buffer, buffer.length);
socket.receive(packet);
System.out.println("Server Response: " + new String(packet.getData(), 0, packet.getLength()));
} catch (IOException e) {
e.printStackTrace();
}
}
}
服务器端代码
import java.io.*;
import java.net.*;
public class UDPServer {
public static void main(String[] args) {
try (DatagramSocket socket = new DatagramSocket(12346)) {
System.out.println("Server started on port 12346");
byte[] buffer = new byte[100];
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
socket.receive(packet);
String clientMessage = new String(packet.getData(), 0, packet.getLength());
System.out.println("Message from client: " + clientMessage);
InetAddress address = packet.getAddress();
int port = packet.getPort();
String response = "Hello Client";
DatagramPacket responsePacket = new DatagramPacket(response.getBytes(), response.length(), address, port);
socket.send(responsePacket);
} catch (IOException e) {
e.printStackTrace();
}
}
}
进程间通信与消息传递
进程间通信(IPC,Inter-Process Communication)是指同一计算机内不同进程之间进行数据交换的过程。常见的进程间通信方式包括管道、套接字、共享内存、消息队列等。
管道(Pipe)
管道是一种简单的进程间通信方式,允许一个进程的输出作为另一个进程的输入。管道分为匿名管道和命名管道。
- 匿名管道:用于父进程和子进程之间的通信。
- 命名管道:可以在不同进程之间进行通信。
示例代码
使用匿名管道
import java.io.*;
public class AnonymousPipe {
public static void main(String[] args) {
try (PipedInputStream pin = new PipedInputStream();
PipedOutputStream pout = new PipedOutputStream()) {
PinReader reader = new PinReader(pin);
PinWriter writer = new PinWriter(pout);
reader.start();
writer.start();
writer.join();
reader.join();
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
}
static class PinReader extends Thread {
private PipedInputStream pin;
public PinReader(PipedInputStream pin) {
this.pin = pin;
}
@Override
public void run() {
try {
byte[] buffer = new byte[1024];
int length = pin.read(buffer);
System.out.println("Received: " + new String(buffer, 0, length));
} catch (IOException e) {
e.printStackTrace();
}
}
}
static class PinWriter extends Thread {
private PipedOutputStream pout;
public PinWriter(PipedOutputStream pout) {
this.pout = pout;
}
@Override
public void run() {
try {
pout.write("Hello!".getBytes());
pout.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
消息队列
消息队列是一种异步通信机制,允许进程之间通过消息进行通信。Java中可以使用java.util.concurrent
包中的BlockingQueue
实现消息队列。
示例代码
使用BlockingQueue
实现消息队列
import java.util.concurrent.*;
public class MessageQueueExample {
public static void main(String[] args) {
BlockingQueue<String> queue = new LinkedBlockingQueue<>();
Producer producer = new Producer(queue);
Consumer consumer = new Consumer(queue);
Thread producerThread = new Thread(producer);
Thread consumerThread = new Thread(consumer);
producerThread.start();
consumerThread.start();
try {
producerThread.join();
consumerThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
static class Producer implements Runnable {
private BlockingQueue<String> queue;
public Producer(BlockingQueue<String> queue) {
this.queue = queue;
}
@Override
public void run() {
for (int i = 0; i < 5; i++) {
String message = "Message " + i;
try {
queue.put(message);
System.out.println("Produced: " + message);
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
static class Consumer implements Runnable {
private BlockingQueue<String> queue;
public Consumer(BlockingQueue<String> queue) {
this.queue = queue;
}
@Override
public void run() {
while (true) {
try {
String message = queue.take();
System.out.println("Consumed: " + message);
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
RPC(远程过程调用)介绍
RPC(Remote Procedure Call)是一种允许程序调用远程计算机上的过程或函数的技术。RPC通过网络提供透明的远程过程调用,使得调用远程服务就像调用本地服务一样简单。Java中常用的RPC框架有Java RMI、gRPC等。
Java RMI
Java RMI(Java Remote Method Invocation)允许Java对象调用远程计算机上的方法。Java RMI通过接口定义远程对象的方法,并通过网络传输调用数据。
示例代码
使用Java RMI
- 定义远程接口
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface MyRemote extends Remote {
String sayHello(String message) throws RemoteException;
}
- 实现远程接口
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
public class MyRemoteImpl extends UnicastRemoteObject implements MyRemote {
protected MyRemoteImpl() throws RemoteException {
super();
}
@Override
public String sayHello(String message) throws RemoteException {
return "Hello, " + message;
}
}
- 服务器端代码
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
public class Server {
public static void main(String[] args) {
try {
MyRemoteImpl myRemoteImpl = new MyRemoteImpl();
Registry registry = LocateRegistry.createRegistry(1099);
registry.rebind("MyRemote", myRemoteImpl);
System.out.println("Server started");
} catch (Exception e) {
e.printStackTrace();
}
}
}
- 客户端代码
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
public class Client {
public static void main(String[] args) {
try {
Registry registry = LocateRegistry.getRegistry("localhost", 1099);
MyRemote myRemote = (MyRemote) registry.lookup("MyRemote");
String response = myRemote.sayHello("World");
System.out.println("Client received: " + response);
} catch (Exception e) {
e.printStackTrace();
}
}
}
Java分布式开发常用框架
ZooKeeper:分布式协作框架简介
ZooKeeper是一个开源的分布式协调服务,用于分布式环境中的配置管理、命名服务、分布式锁和协调服务。ZooKeeper通过提供简单的接口来实现这些复杂的功能。
- 节点类型:
- 持久节点:节点数据在客户端断开连接后仍然存在。
- 临时节点:节点数据随着客户端断开连接而消失。
- 数据模型:ZooKeeper将数据组织成树形结构,每个节点可以包含子节点和数据。
- 观察者模式:客户端可以注册对节点的监听,当节点发生变化时,客户端会收到通知。
示例代码
使用ZooKeeper创建节点和监听节点变化
import org.apache.zookeeper.*;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.data.Stat;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
public class ZooKeeperExample {
private static final String ZK_ADDRESS = "localhost:2181";
private static final String PATH = "/myNode";
public static void main(String[] args) throws Exception {
ZooKeeper zk = new ZooKeeper(ZK_ADDRESS, 5000, new Watcher() {
@Override
public void process(WatchedEvent event) {
System.out.println("Received event: " + event.getState() + " " + event.getType() + " " + event.getPath());
}
});
// Create node
zk.create(PATH, "data".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
// Start watching the node
zk.getData(PATH, true, new Stat());
// Wait for changes
CountDownLatch latch = new CountDownLatch(1);
latch.await(10, TimeUnit.SECONDS);
zk.close();
}
}
Spring Cloud:微服务框架简介
Spring Cloud是一套基于Spring Boot的微服务框架,它提供了多种工具帮助开发者构建分布式系统。Spring Cloud的核心组件包括服务注册与发现(Eureka)、配置中心(Config Server)、服务网关(Zuul)、负载均衡(Ribbon)、断路器(Hystrix)等。
示例代码
使用Spring Cloud Eureka实现服务注册与发现
- 创建Eureka Server
server:
port: 8761
spring:
application:
name: eureka-server
eureka:
client:
register-with-eureka: false
fetch-registry: false
instance:
hostname: localhost
- 创建服务提供者
spring:
application:
name: service-provider
server:
port: 8081
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
@RestController
public class ServiceController {
@GetMapping("/hello")
public String hello() {
return "Hello from Service Provider";
}
}
- 创建服务消费者
spring:
application:
name: service-consumer
server:
port: 8082
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
ribbon:
eureka:
enabled: false
@RestController
public class ServiceController {
@Autowired
private LoadBalancerClient loadBalancerClient;
@GetMapping("/hello")
public String hello() {
URI url = loadBalancerClient.choose("SERVICE-PROVIDER").getURI();
return restTemplate.getForObject(url + "/hello", String.class);
}
}
Dubbo:分布式服务框架简介
Dubbo是一个高性能、轻量级的Java RPC框架,提供了服务发布、发现、负载均衡、路由等功能。Dubbo支持多种服务协议和注册中心,包括Zookeeper、Spring Cloud等。
示例代码
使用Dubbo实现服务提供者
- 配置Dubbo服务提供者
<dubbo:application name="service-provider"/>
<dubbo:registry address="zookeeper://localhost:2181" />
<dubbo:protocol name="dubbo" port="20880"/>
- 实现服务接口
public interface HelloService {
String sayHello(String name);
}
- 实现服务接口的实现类
@Service("helloService")
public class HelloServiceImpl implements HelloService {
@Override
public String sayHello(String name) {
return "Hello, " + name;
}
}
使用Dubbo实现服务消费者
- 配置Dubbo服务消费者
<dubbo:application name="service-consumer"/>
<dubbo:registry address="zookeeper://localhost:2181" />
<dubbo:reference id="helloService" interface="com.example.demo.HelloService"/>
- 调用服务
public class Consumer {
public static void main(String[] args) {
ReferenceConfig<HelloService> reference = new ReferenceConfig<>();
reference.setApplication(new ApplicationConfig("consumer"));
reference.setRegistry(new RegistryConfig("zookeeper://localhost:2181"));
reference.setInterface(HelloService.class);
reference.setVersion("1.0.0");
HelloService helloService = reference.get();
String result = helloService.sayHello("World");
System.out.println("Result from service: " + result);
}
}
分布式数据存储
NoSQL数据库简介
NoSQL(Not Only SQL)数据库是一种非关系型数据库,与传统的关系型数据库不同,NoSQL数据库主要用于存储非结构化或半结构化的数据。NoSQL数据库的特点包括高可用性、性能、可扩展性和灵活性。
常见的NoSQL数据库包括MongoDB、Redis、Cassandra等。
- MongoDB:一种基于文档的数据库,支持JSON格式的数据存储。
- Redis:一种内存数据库,常用于缓存和实时数据处理。
- Cassandra:一种分布式数据库,具有高可用性和数据一致性。
示例代码
使用MongoDB存储数据
import com.mongodb.client.MongoClients;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import org.bson.Document;
public class MongoDBExample {
public static void main(String[] args) {
MongoClient mongoClient = MongoClients.create("mongodb://localhost:27017");
MongoDatabase database = mongoClient.getDatabase("test");
MongoCollection<Document> collection = database.getCollection("users");
Document user = new Document("name", "John Doe")
.append("age", 30)
.append("email", "[email protected]");
collection.insertOne(user);
System.out.println("User inserted successfully");
}
}
分布式缓存技术简介
分布式缓存技术是分布式系统中用于提高性能和减少数据库访问的一种技术。常见的分布式缓存系统包括Redis、Memcached、Ehcache等。
- Redis:一个内存数据库,具有持久化功能,支持多种数据结构。
- Memcached:一个高性能的分布式缓存系统,主要用于缓存数据。
- Ehcache:一个内存中的Java对象缓存框架,支持多种缓存策略。
示例代码
使用Redis存储数据
import redis.clients.jedis.Jedis;
public class RedisExample {
public static void main(String[] args) {
Jedis jedis = new Jedis("localhost");
jedis.set("username", "John Doe");
String username = jedis.get("username");
System.out.println("Username: " + username);
jedis.close();
}
}
数据一致性与分区容错性
在分布式系统中,数据一致性是一个关键问题。CAP理论(一致性、可用性、分区容错性)指出,在分布式系统中,不可能同时满足一致性、可用性和分区容错性三个特性。
- 一致性:所有节点上的数据视图都是一致的。
- 可用性:每个请求都能得到一个响应,即使无法执行请求,也必须告知用户。
- 分区容错性:网络中的任意节点间的通信失败时,系统仍然能够继续运行。
通常,分布式系统需要在一致性、可用性和分区容错性之间进行权衡。
示例代码
使用ZooKeeper实现分布式锁
import org.apache.zookeeper.*;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.data.Stat;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CountDownLatch;
public class DistributedLockExample {
private static final String ZK_ADDRESS = "localhost:2181";
private static final String PATH = "/lock";
private static final int SESSION_TIMEOUT = 10000;
public static void main(String[] args) throws Exception {
ZooKeeper zk = new ZooKeeper(ZK_ADDRESS, SESSION_TIMEOUT, event -> {
System.out.println("Received event: " + event.getType());
});
CountDownLatch latch = new CountDownLatch(1);
new Thread(() -> {
try {
acquireLock(zk);
Thread.sleep(10000);
System.out.println("Lock acquired, releasing...");
releaseLock(zk);
} catch (InterruptedException | KeeperException e) {
e.printStackTrace();
} finally {
latch.countDown();
}
}).start();
latch.await();
zk.close();
}
private static void acquireLock(ZooKeeper zk) throws KeeperException, InterruptedException {
String ephemeralPath = zk.create(PATH + "/lock-", Collections.singletonList("lock".getBytes()), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
List<String> children = zk.getChildren(PATH, false);
int sequenceNumber = Integer.parseInt(ephemeralPath.substring(PATH.length() + 1));
int sortedChildIndex = Collections.binarySearch(children, Integer.toString(sequenceNumber));
if (sortedChildIndex < 0) {
sortedChildIndex = ~sortedChildIndex;
}
while (sortedChildIndex > 0) {
String path = PATH + "/" + children.get(sortedChildIndex - 1);
int sessionTimeout = (int) zk.exists(path, (w, c) -> {
System.out.println("Node " + path + " deleted, trying to acquire lock...");
acquireLock(zk);
}).getAtime();
Thread.sleep(sessionTimeout);
}
}
private static void releaseLock(ZooKeeper zk) throws InterruptedException, KeeperException {
List<String> children = zk.getChildren(PATH, false);
for (String child : children) {
zk.delete(PATH + "/" + child, -1);
}
}
}
分布式部署与配置
Java项目的打包与分发
在分布式系统中,Java项目通常被打包成JAR或WAR文件,并通过网络分发到不同的节点上。常用的打包工具包括Maven和Gradle。
示例代码
使用Maven打包项目
<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>my-project</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.2.0</version>
</plugin>
</plugins>
</build>
</project>
使用命令打包
mvn clean package
配置管理工具简介
配置管理工具用于管理和分发分布式系统中的配置文件。常见的配置管理工具包括Ansible、Chef、Puppet和Consul等。
- Ansible:一个自动化配置管理工具,使用Python编写,支持多种操作系统。
- Chef:一个基于Ruby的自动化配置管理工具,支持多种操作系统。
- Puppet:一个基于Ruby的自动化配置管理工具,支持多种操作系统。
- Consul:一个服务网格工具,可以用于服务发现、配置管理和健康检查。
示例代码
使用Consul存储配置和获取配置
import com.ecwid.consul.v1.ConsulClient;
import com.ecwid.consul.v1.Response;
import com.ecwid.consul.v1.kv.model.Value;
public class ConsulExample {
public static void main(String[] args) {
ConsulClient consulClient = new ConsulClient("localhost", 8500);
// Store configuration
consulClient.putKVValue("app/config", "value");
// Retrieve configuration
Response<Value> response = consulClient.getKVValue("app/config");
if (response.getValue() != null) {
System.out.println("Configuration value: " + response.getValue().getValue());
}
}
}
容器化(Docker)与容器编排(Kubernetes)
容器化技术通过将应用程序及其依赖项打包到一个隔离的容器中,使得应用程序可以在不同的环境中一致运行。Kubernetes是一个开源的容器编排平台,可以自动化容器应用的部署、扩展和管理。
示例代码
使用Docker构建镜像
FROM openjdk:8-jdk-alpine
COPY target/my-app.jar /app/my-app.jar
CMD ["java", "-jar", "/app/my-app.jar"]
构建Docker镜像
docker build -t my-app:v1 .
使用Kubernetes部署应用
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
spec:
replicas: 3
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
containers:
- name: my-app
image: my-app:v1
ports:
- containerPort: 8080
应用部署
kubectl apply -f deployment.yaml
实战案例:搭建简单的分布式系统
项目需求分析
假设我们需要开发一个简单的朋友圈应用,该应用需要支持用户注册、登录、发布和查看朋友圈动态等功能。为了实现高可用性和可扩展性,我们需要将应用部署到多个节点上,并使用分布式数据库存储用户数据。
系统设计与实现
- 用户注册和登录:使用Spring Boot和Spring Security实现用户注册和登录功能。
- 发布动态:使用Spring Boot和MyBatis实现动态发布功能。
- 查看动态:使用Spring Boot和MyBatis实现动态查看功能。
- 服务注册与发现:使用Spring Cloud Eureka实现服务注册与发现。
- 配置管理:使用Spring Cloud Config Server管理配置文件。
- 数据库:使用MySQL作为数据库,存储用户和动态数据。
示例代码
用户注册和登录
- 用户实体类
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String username;
private String password;
// getters and setters
}
- 用户服务接口
public interface UserService {
User register(User user);
User login(String username, String password);
}
- 用户服务实现
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserRepository userRepository;
@Override
public User register(User user) {
// 密码加密处理
user.setPassword(passwordEncoder.encode(user.getPassword()));
return userRepository.save(user);
}
@Override
public User login(String username, String password) {
User user = userRepository.findByUsername(username);
if (user != null && passwordEncoder.matches(password, user.getPassword())) {
return user;
}
return null;
}
@Autowired
private PasswordEncoder passwordEncoder;
}
- 用户接口
@RestController
public class UserController {
@Autowired
private UserService userService;
@PostMapping("/register")
public ResponseEntity<User> register(@RequestBody User user) {
User registeredUser = userService.register(user);
return ResponseEntity.ok(registeredUser);
}
@PostMapping("/login")
public ResponseEntity<User> login(@RequestBody User user) {
User loggedUser = userService.login(user.getUsername(), user.getPassword());
if (loggedUser != null) {
return ResponseEntity.ok(loggedUser);
}
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
}
}
发布动态
- 动态实体类
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
@Entity
public class Post {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String content;
@ManyToOne
private User user;
// getters and setters
}
- 动态服务接口
public interface PostService {
Post createPost(Post post);
List<Post> getPosts();
}
- 动态服务实现
@Service
public class PostServiceImpl implements PostService {
@Autowired
private PostRepository postRepository;
@Override
public Post createPost(Post post) {
return postRepository.save(post);
}
@Override
public List<Post> getPosts() {
return postRepository.findAll();
}
}
- 动态接口
@RestController
public class PostController {
@Autowired
private PostService postService;
@PostMapping("/post")
public ResponseEntity<Post> createPost(@RequestBody Post post) {
Post createdPost = postService.createPost(post);
return ResponseEntity.ok(createdPost);
}
@GetMapping("/posts")
public ResponseEntity<List<Post>> getPosts() {
List<Post> posts = postService.getPosts();
return ResponseEntity.ok(posts);
}
}
服务注册与发现
- Eureka Server
server:
port: 8761
spring:
application:
name: eureka-server
eureka:
client:
register-with-eureka: false
fetch-registry: false
instance:
hostname: localhost
- Eureka Client
spring:
application:
name: my-app
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
配置管理
- 配置服务器
spring:
application:
name: config-server
server:
port: 8081
spring:
cloud:
config:
server:
git:
uri: https://github.com/example/config-repo
username: your-username
password: your-password
- 配置客户端
spring:
application:
name: my-app
server:
port: 8082
spring:
cloud:
config:
name: my-app
label: master
profile: default
uri: http://localhost:8081
数据库
- Spring Data JPA
spring:
datasource:
url: jdbc:mysql://localhost:3306/mydb
username: root
password: root
jpa:
hibernate:
ddl-auto: update
- MyBatis
mybatis:
configuration:
cache-enabled: true
type-handlers-package: com.example.typehandlers
mapper-locations: classpath:/mapper/*.xml
系统测试与部署
系统测试
- 单元测试
@RunWith(SpringRunner.class)
@SpringBootTest
public class UserServiceTest {
@Autowired
private UserService userService;
@Test
public void testRegisterUser() {
User user = new User();
user.setUsername("test");
user.setPassword("password");
User registeredUser = userService.register(user);
assertNotNull(registeredUser);
}
@Test
public void testLoginUser() {
User user = new User();
user.setUsername("test");
user.setPassword("password");
User registeredUser = userService.register(user);
User loggedUser = userService.login("test", "password");
assertNotNull(loggedUser);
}
}
- 集成测试
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class UserControllerTest {
@Autowired
private TestRestTemplate restTemplate;
@Test
public void testRegisterUser() {
User user = new User();
user.setUsername("test");
user.setPassword("password");
ResponseEntity<User> response = restTemplate.postForEntity("/register", user, User.class);
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.CREATED);
}
@Test
public void testLoginUser() {
User user = new User();
user.setUsername("test");
user.setPassword("password");
ResponseEntity<User> response = restTemplate.postForEntity("/login", user, User.class);
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
}
}
系统部署
- 打包
mvn clean package
- 启动Eureka Server
java -jar target/eureka-server.jar
- 启动配置服务器
java -jar target/config-server.jar
- 启动应用
java -jar target/my-app.jar
共同學習,寫下你的評論
評論加載中...
作者其他優質文章