728x90
* DB
1. 보안
위험 상황
MySQL과 인텔리제이를 연동할 때 다음과 같이 3가지를 입력하게 된다.
Class.forName("com.mysql.cj.jdbc.Driver");
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306", "root", "1234");
- DBMS 접속 아이디
- DBMS 접속 비밀번호
- DBMS 접속 URL
로컬 데이터베이스로 연동할 경우, 해당 데이터들이 로컬에 접속되기 때문에 주소가 노출되어도 보안에 큰 문제가 발생하지 않지만 클라우드와 같은 공유 주소를 사용할 경우 데이터가 노출되어 보안에 심각한 위협을 받게 된다.
- 예시
- 강사님 DB 해킹
(Do you have bitcoin?)
Class.forName("com.mysql.cj.jdbc.Driver");
Connection conn = DriverManager.getConnection("jdbc:mysql://aws ipv4 링크/likelion-db", "root", "1234");
해결방법
환경변수에 보안이 필요한 정보를 저장하고 메소드를 활용하여 해당 데이터를 불러온다.
- 접속 정보가 필요한 클래스의 설정에 들어갑니다.
- 환경 변수에 들어갑니다.
- ‘+’기호를 선택하여 Name과 Value 부분에 데이터를 입력합니다.
- 다음과 같이 코드를 구성합니다.
Map<String, String> env = System.getenv();
String dbHost = env.get("DB_HOST");
String dbUser = env.get("DB_USER");
String dbPassword = env.get("DB_PASSWORD");
Class.forName("com.mysql.cj.jdbc.Driver");
Connection conn = DriverManager.getConnection(dbHost, dbUser, dbPassword);
System.getenv()
환경 변수를 읽어오며, 모든 시스템 환경변수에 대한 값을 Key, value(Map<String,String) 형태로 반환
System.getenv(String name)
name에 해당되는 시스템 환경 변수의 값을 반환
- 추후에 properties나 yml을 사용하여 분리할 수 있다.
2. DAO(Data Access Object) 분리
1. 관심사의 분리
- 객체를 설계할때 미래의 변화를 대비해야한다.
- 가상의 추상 세계 자체를 효과적으로 구성할 수 있고, 자유롭고 편리하게 변경, 발전 확장시킬 수 있어야한다.
- 변경이 일어날 때 필요한 작업을 최소화하고, 문제를 일으키지 않게 하기 위해 분리와 확장을 고려한 설계를 해야한다.
- 모든 변경과 발전은 한 번에 한 가지 관심사항에 집중해서 일어난다.
관심사의 분리(Separation of Concerns)
관심이 같은 것끼리 하나의 객체 안으로 또는 친한 객체로 모이게 하고, 관심이 다른 것은 가능한 한 따로 떨어져서 서로 영향을 주지 않도록 분리하는 것.
2. 중복 사용되는 Connection 추출
관심사항
- DB와 연결을 위한 커넥션을 어떻게 가져올 것인가?
- 사용자 등록을 위해 DB에 보낼 SQL 문장을 담을 Statement를 만들고 실행하는 것.
- 리소스인 Statement와 Connection오브젝트를 닫아 공유 리소스를 시스템에 반환
중복 코드의 메소드 추출
public User get(String id) throws ClassNotFoundException, SQLException {
Map<String, String> env = System.getenv();
String dbHOST = env.get("DB_HOST");
String dbUser = env.get("DB_USER");
String dbPassowrd = env.get("DB_PASSWORD");
Class.forName("com.mysql.cj.jdbc.Driver");
Connection conn = DriverManager.getConnection(dbHOST, dbUser, dbPassowrd);
...
}
public List<User> findAll() throws ClassNotFoundException, SQLException {
Map<String, String> env = System.getenv();
String dbHOST = env.get("DB_HOST");
String dbUser = env.get("DB_USER");
String dbPassowrd = env.get("DB_PASSWORD");
Class.forName("com.mysql.cj.jdbc.Driver");
Connection conn = DriverManager.getConnection(dbHOST, dbUser, dbPassowrd);
...
}
위의 상황과 같이 메소드마다 중복된 코드가 존재한다면, 해당 코드를 분리하는 것이다.
public Connection getConnection() throws ClassNotFoundException, SQLException {
Map<String, String> env = System.getenv();
String dbHost = env.get("DB_HOST");
String dbUser = env.get("DB_USER");
String dbPassword = env.get("DB_PASSWORD");
Class.forName("com.mysql.cj.jdbc.Driver");
Connection conn = DriverManager.getConnection(dbHost, dbUser, dbPassword);
return conn;
}
public List<User> findAll() throws SQLException, ClassNotFoundException {
Connection conn = getConnection();
...
}
public void add(User user) throws SQLException, ClassNotFoundException {
Connection conn = getConnection();
...
}
해당 코드처럼 중복된 곳을 한 곳으로 모아 처리한다면, 추후에 로그인 정보가 변하는 상황이 발생하였을 때 getConnection()이라는 하나의 메소드 코드만 수정하면 된다.
리팩토링
기존의 코드를 외부의 동작방식에는 변화 없이 내부 구조를 변경해서 재구성하는 작업 또는 기술. 대표적으로, 중복된 코드는 매우 흔하게 발견되는 나쁜 냄새다. 이런 코드는 적절한 리팩토링 방법을 적용하여 제거해야한다.
3. DB 커넥션 만들기 독립 Abstract
변화를 반기는 DAO를 만들어보자.
상속을 통한 확장 - 팩토리 메소드 패턴
UserDao를 한 단계 더 분리하면 된다.
- UserDao의 메소드 구현 코드를 제거하고 getConnection()을 추상 메소드로 만든다.
- 해당 추상클래스 UserDao를 필요한 고객에게 판매한다.
- 구매한 고객은 UserDao클래스를 상속하여 각각 본인에게 필요한 서브클래스를 제작한다.
- 서브클래스에서는 UserDao에서 추상 메소드로 선언했던 getConnection() 메소드를 원하는 방식대로 구현할 수 있다.
해당 방법을 사용하면 UserDao의 소스코드를 제공해서 수정해 쓰도록 하지 않아도 getConnection()메소드를 원하는 방식으로 확장한 후에 UseDao의 기능과 함께 사용할 수 있다.
판매자
public abstract class UserDaoAbstract {
public abstract Connection getConnection() throws ClassNotFoundException, SQLException;
public void add(User user) throws SQLException, ClassNotFoundException {
Connection conn = getConnection();
...
}
public User get(String id) throws SQLException, ClassNotFoundException {
Connection conn = getConnection();
...
}
}
서비스 구매자
public class AWSUserDaoImpl extends UserDaoAbstract{
@Override
public Connection getConnection() throws ClassNotFoundException, SQLException {
Map<String, String> env = System.getenv();
String dbHost = env.get("DB_HOST");
String dbUser = env.get("DB_USER");
String dbPassword = env.get("DB_PASSWORD");
Class.forName("com.mysql.cj.jdbc.Driver");
Connection conn = DriverManager.getConnection(dbHost, dbUser, dbPassword);
return conn;
}
}
템플릿 메소드 패턴(Template Method Pattern)
이렇게 슈퍼클래스에 기본적인 로직의 흐름(커넥션 가져오기, SQL 등)을 만들고, 그 일부를 추상 메소드나 오버라이딩이 가능한 protected 메소드등으로 만든 뒤 서브클래스에서 이런 메소드를 필요에 맞게 구현해서 사용하도록 하는 방법
팩토리 메소드 패턴(Factory Method Pattern)
구체적인 오브젝트 생성 방법을 결정하게 하는 것
템플릿 메소드 패턴
- 장점
- 중복 코드의 최소화
- 동일한 기능을 사위 클래스에서 정의하며 확장/변화가 필요한 부분만 서브 클래스에서 구현
- 자식 클래스의 역할을 최소화하여 핵심 로직 관리가 용이
- 단점
- 추상 메소드가 많아지며 클래스 관리가 복잡하다.
- 클래스간의 관계, 코드가 복잡해질 수 있다.
팩토리 메소드 패턴
- 팩토리 메소드 패턴
- 부모(상위) 클래스에 알려지지 않은 구체 클래스를 생성하는 패턴
- 자식(하위) 클래스가 어떤 객체를 생성할지 결정하도록 하는 패턴
- 상위 클래스 코드에 구체 클래스 이름을 감추기 위한 방법으로도 사용
- 주의사항
- 중첩시 굉장히 복잡해질 수 있다.
- 상속을 사용하지만 상위 클래스를 전혀 확장하지 않는다.
- 해당 패턴은 extends관계를 잘못이용한 것으로 볼 수 있다.
- extends 관계를 남발하면 프로그램의 엔트로피가 높아질 수 있으므로 사용을 주의해야한다.
참조
이일민 저 - 토비의 스프링
반응형
'회고록 > Archive' 카테고리의 다른 글
retrospect: 멋쟁이 사자처럼 백앤드 스쿨 2022.11.16 회고 (0) | 2022.12.04 |
---|---|
retrospect: 멋쟁이 사자처럼 백앤드 스쿨 2022.11.01 회고 (1) | 2022.12.02 |
retrospect: 멋쟁이 사자처럼 백앤드 스쿨 2022.09.30 회고 (0) | 2022.12.02 |
docs: 멋쟁이 사자처럼 백앤드 스쿨 2기 수업 일지 READ ME(2022-11-13) (7) | 2022.11.13 |
[Java] 대용량 데이터 분석 - 4 (대한민국 인구 유동(전입, 전출) 데이터 분석 & 처리) (0) | 2022.10.11 |