대표적인 서비스 제공자 프레임워크 - JDBC
서비스 제공자 프레임워크에서의 제공자는 서비스의 구현체
이 구현체들을 클라이언트에 제공하는 역할을 프레임워크가 통제, 클라이언트를 구현체로부터 분리
서비스 제공자 프레임워크 핵심 컴포넌트
서비스 인터페이스 - 구현체의 동작을 정의 - Connection
제공자 등록 API - 제공자가 구현체를 등록 할 때 사용 - DriverManager.registerDriver
서비스 접근 API - 클라이언트가 서비스의 인스턴스를 얻을 때 사용 - DriverManager.getConnection
서비스 제공자 인터페이스 - 서비스 인터페이스의 인스턴스를 생성하는 팩토리 객체를 설명 - Driver
JDBC 예제
Class.forName("oracle.jdbc.driver.OracleDriver");
Connection connection = null;
connection = DriverManager.getConnection
("jdbc:oracle:thin:@localhost:1121:test", "root", "root");
Class.forName()의 동작 원리
해당 메소드는 물리적인 클래스 파일 명을 인자로 넣어주면, JVM에게 이 클래스를 로드하라고 요청한다.
클래스 로더는 클래스의 메타 데이터를 메서드 영역에 저장 및 Class 객체를 힙 영역에 할당하게 된다.
클래스 로딩이 끝나게 되면 static 필드 및 static 블록이 초기화되며, 이때 제공자 등록 API가 활용된다.
이를 대체하는 것이 java.util.ServiceLoader
ServiceLoader<HelloService> loader = ServiceLoader.load(HelloService.class);
Optional<HelloService> helloServiceOptional = loader.findFirst();
helloServiceOptional.ifPresent(h -> {
System.out.println(h.hello());
});
DriveManager
public class DriverManager {
private DriverManager() {
}
private static final Map<String, Driver> drivers = new ConcurrentHashMap<String, Driver>();
public static final String DEFAULT_DRIVER_NAME = "default";
public static void registerDefaultPrivider(Driver d) {
System.out.println("Driver 등록");
registerDriver(DEFAULT_DRIVER_NAME, d);
}
public static void registerDriver(String name, Driver d) {
drivers.put(name, d);
}
public static Connection getConnection() {
return getConnection(DEFAULT_DRIVER_NAME);
}
public static Connection getConnection(String name) {
Driver d = drivers.get(name);
if (d == null) throw new IllegalArgumentException();
return d.getConnection();
}
}
Driver
public class OracleDriver implements Driver {
static {
defaultDriver = null;
Timestamp timestamp = Timestamp.valueOf("2000-01-01 00:00:00.0");
try {
if (defaultDriver == null) {
defaultDriver = new OracleDriver();
DriverManager.registerDriver(defaultDriver); // OracleDriver 등록
}
} catch (RuntimeException runtimeexception) {
} catch (SQLException sqlexception) {
}
}
...
public Connection getConnection() {
...
}
}
Connection
public interface Connection {
Statement createStatement() throws SQLException;
PreparedStatement prepareStatement(String sql);
void commit() throws SQLException;
void rollback() throws SQLException;
...
}