코드는 OCP 원칙에 따라 변경에 닫혀있고 확장에 열려있어야 한다. 따라서 코드상에서 선언했던 SOCKET_PATH와 BUFFER_SIZE를 application.yml에서 설정하고 코드는 이를 받아 변수에 주입하도록 구현을 바꾸었다.
전체 코드
SocketProvider
package com.example.test;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
import lombok.extern.slf4j.Slf4j;
import org.newsclub.net.unix.AFSocketAddress;
import org.newsclub.net.unix.AFUNIXSocket;
import org.newsclub.net.unix.AFUNIXSocketAddress;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.net.URI;
@Slf4j
@Component
public class SocketProvider {
@Value("${socket-provider.socket-path}")
private String SOCKET_PATH;
@Value("${socket-provider.buffer-size}")
private int BUFFER_SIZE;
private AFUNIXSocket sock;
private OutputStream out;
private InputStream in;
@PostConstruct
public void connect() throws IOException {
SocketAddress endpoint = getSocketAddress(SOCKET_PATH);
sock = AFUNIXSocket.connectTo(AFUNIXSocketAddress.of(endpoint));
out = sock.getOutputStream();
in = sock.getInputStream();
log.info("UDS Connected Completely to {}", endpoint);
}
@PreDestroy
public void disconnect() throws IOException {
if (sock != null && !sock.isClosed()) {
sock.close();
log.info("Disconnected from server on " + SOCKET_PATH);
}
}
// Need for custom return value for error handling
public boolean isValid() {
if (sock == null) {
return false;
} else if (!sock.isConnected()) {
return false;
}
return true;
}
public void reconnect() throws IOException {
if (this.isValid()) {
return;
}
SocketAddress endpoint = getSocketAddress(SOCKET_PATH);
sock = AFUNIXSocket.connectTo(AFUNIXSocketAddress.of(endpoint));
out = sock.getOutputStream();
in = sock.getInputStream();
}
public String sendMessage(String message) throws IOException {
if (sock == null || !sock.isConnected()) {
log.info("UDS NOT CONNECTED!!!");
throw new IOException("UDS Not Connected");
}
log.info("Now writing string({}) to the server...", message);
out.write(message.getBytes());
out.flush();
byte[] buffer = new byte[BUFFER_SIZE];
int numRead = in.read(buffer);
if (numRead > 0) {
return new String(buffer, 0, numRead);
} else {
return null;
}
}
private SocketAddress getSocketAddress(String socketName) throws IOException {
if (socketName.startsWith("file:")) {
// demo only: assume file: URLs are always handled by AFUNIXSocketAddress
return AFUNIXSocketAddress.of(URI.create(socketName));
} else if (socketName.contains(":/")) {
// assume URI, e.g., unix:// or tipc://
return AFSocketAddress.of(URI.create(socketName));
}
int colon = socketName.lastIndexOf(':');
int slashOrBackslash = Math.max(socketName.lastIndexOf('/'), socketName.lastIndexOf('\\\\'));
if (socketName.startsWith("@")) {
// abstract namespace (Linux only!)
return AFUNIXSocketAddress.inAbstractNamespace(socketName.substring(1));
} else if (colon > 0 && slashOrBackslash < colon && !socketName.startsWith("/")) {
// assume TCP socket
String hostname = socketName.substring(0, colon);
int port = Integer.parseInt(socketName.substring(colon + 1));
return new InetSocketAddress(hostname, port);
} else {
// assume unix socket file name
return AFUNIXSocketAddress.of(new File(socketName));
}
}
}
applicaiton.yml
spring:
application:
name: test
profiles:
active: dev
logging:
level:
com.example.test: info
socket-provider:
socket-path: /tmp/my_unix_socket.sock
buffer-size: 256
@Value
@Value 애너테이션은 생성자 주입 시 자동으로 주입되지 않는 기본 자료형과 문자열의 값을 설정한다.
application.yml에 있는 값을 가져올 일이 많지 않아 이를 관리할 클래스까지 만들 필요가 없을 때, 애너테이션 하나로 해결이 가능하다.
'개발일기 > Spring + Unix Domain Socket' 카테고리의 다른 글
[Spring + UDS] 5. Spring Custom bean 생성 (0) | 2024.08.08 |
---|---|
[Spring + UDS] 4. Spring Boot Client 구현 (0) | 2024.08.08 |
[Spring + UDS] 3. C demo Server (0) | 2024.08.08 |
[Spring + UDS] 2. JUNIXSocket (0) | 2024.08.08 |
[Spring + UDS] 1. 사건의 발단… (0) | 2024.08.08 |
댓글