[LIKELION] 221019

고관운·2022년 10월 19일

회고

😄 느낀점

  • 처음 Spring을 배우면서 어색한 느낌이 강했다. 이해와 연습이 필요하다.

😁 목표

  • Spring 정확히 이해

[멋쟁이사자처럼] 5주차 - Spring 입문

알고리즘(Stack)

Stack이란

  • 스택(Stack) -> 티슈, 감자칩 (First In Last Out)
  • 큐(Queue) -> 대기 줄 (First In First Out)

Stack을 쓰는 이유

  • Stack을 공부하며 Class를 쓰는 이유를 알 수 있음
    👉 Class 쓰는 이유 : 상태 + 동작을 같이 쓰기 위해
  • 자료구조의 첫걸음
  • 특정 계산을 컴퓨터에게 시키기 위해 인위적으로 생김
  • 함수에서 함수를 호출하는 기능을 구현하기 위해
    👉 plus(minus(30, multiple(4*5),20) = plus(10,20), 호출 방향 : plus() -> minus() -> multiple()

Stack 기능

  • push() : 넣기(맨 위에)
  • pop() : 꺼내기(맨 위에서 꺼내고 없애기)
  • peek() : 맨 위의 값을 확인하는 기능(없애지 않음)
  • isEmpty() : 비었는지 체크

Stack (push, pop 구현)

import java.util.Arrays;

public class Stack01 {
    private int[] arr = new int[10000];
    private int pointer = 0;

    public Stack01() {
    }

    public Stack01(int size) {
        this.arr = new int[size];
    }

    public void push(int value) {
        this.arr[this.pointer] = value;
        this.pointer++;
    }

    public int pop() {
        this.pointer--;
        return this.arr[this.pointer];
    }

    public int[] getArr() {
        return arr;
    }

    public static void main(String[] args) {
        Stack01 stack01 = new Stack01();
        stack01.push(10);
        stack01.push(20);
        System.out.println(Arrays.toString(stack01.getArr()));
        System.out.println(stack01.pop());
        System.out.println(Arrays.toString(stack01.getArr()));
    }
}

자바 DB 연동 및 데이터 추가

Interface 복습

ConnectionMaker

import java.sql.Connection;
import java.sql.SQLException;

public interface ConnectionMaker {
    public Connection getConnection() throws ClassNotFoundException, SQLException;
}

AwsConnectionMaker

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Map;

public class AwsConnectionMaker implements ConnectionMaker{
    public Connection getConnection() throws ClassNotFoundException, SQLException {
        Map<String, String> env = System.getenv();
        String dbHost = env.get("DB_HOST");
        String dbName = env.get("DB_NAME");
        String dbPassword = env.get("DB_PASSWORD");

        Class.forName("com.mysql.cj.jdbc.Driver");
        Connection conn = DriverManager.getConnection(dbHost, dbName, dbPassword);

        return conn;
    }
}

UserDao 일부 코드

public class UserDao {

    private ConnectionMaker connectionMaker;

    // 매개 변수가 없다면 새로 생성하고
    // 받은 매개 변수가 있다면 awsConnectionMaker에 할당
    public UserDao() {
        this.connectionMaker = new AwsConnectionMaker();
    }

    public UserDao(ConnectionMaker connectionMaker) {
        this.connectionMaker = connectionMaker;
    }

    public void add(User user) throws SQLException, ClassNotFoundException {
        Connection conn = connectionMaker.getConnection();
        PreparedStatement ps = conn.prepareStatement("INSERT INTO users(id, name, password) VALUES (?, ?, ?)");
        ps.setString(1, user.getId());
        ps.setString(2, user.getName());
        ps.setString(3, user.getPassword());

        ps.executeUpdate();
        ps.close();
        conn.close();
    }

🔴 이해 과정
1. getConnection()를 갖고 있는 ConnectionMaker 인터페이스 생성
2. ConnectionMaker를 implements하는 AwsConnectionMaker 생성
3. AwsConnectionMaker에서 ConnectionMaker의 getConnection() 완성
4. UserDao에서 ConnectionMaker connectionMaker 선언

  • 객체 생성시 기본 생성자를 이용한다면, this.connectionMaker = new AwsConnectionMaker(); : AwsConnectionMaker은 ConnectionMaker를 implements하기 때문에 초기화 가능
  • 생성자로 Connection을 받으면, connectionMaker 변수에 할당
  1. 이후 connectionMaker로 Connection

Factroy

조립 설정 (어떤 조합을 사용할 것인지)

public class UserDaoFactory {
    // Factory는 조립을 해줌 - DAO에서는
    public UserDao awsUserDao() {
        AwsConnectionMaker awsConnectionMaker = new AwsConnectionMaker();
        // context 재사용 하는 부분이 많은 코드
        UserDao userDao = new UserDao(awsConnectionMaker);
        return userDao;
    }
}

🟢 이해 과정
1. UserDaoFactory 클래스 생성
2. AwsConnectionMaker 객체를 만들어서 UserDao에 넣어 조립해 준 후 리턴
3. 코드 변화

🟢 기존 코드
UserDao userDao = new UserDao(new AwsConnectionMaker());
🟢 Factory 적용후
UserDao userDao = new UserDaoFactory().awsUserDao();

Spring

Spring 사용 이유
1. Bean을 만들어 놓고 불러 쓰기가 좋기 때문에 씀
2. Singleton으로 생성을 해주기 때문에 씀(🔴 객체의 인스턴스가 오직 1개만 생성되는 패턴)

  • getBean을 사용하면 같은 주소(객체 하나)
  • factory.userDao()로 각각 객체를 생성하면 (객체 2개)
    👉 즉, Singleton을 사용하는 것은 GC(Garbage Collection)을 줄일 수 있음
  1. 테스트하기 좋기 때문에
    (Application은 점점 복잡 👉 작업 중간에 테스트 작업 필요)

Spring 적용 방법

  • 방법 1
  1. build.gradle -> dependecies에서 Alt + Insert
  2. spring-boot-starter-jdbc, spring-boot-starter-test add
  • 방법 2
    maven repository에서 검색 후(최신버전, gradle) 복사 붙여넣기

Factory에 Spring 적용
🟢 UserDaoFactory

  • @Configuration : 설정파일을 만들기 위한 애노테이션(Bean을 등록하기 위한)
  • @Bean : Spring IoC 컨테이너가 관리하는 자바 객체를 등록할 때 사용
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class UserDaoFactory {
    // Factory는 조립을 해줌 - DAO에서는
    @Bean
    public UserDao awsUserDao() {
        AwsConnectionMaker awsConnectionMaker = new AwsConnectionMaker();
        // context 재사용 하는 부분이 많은 코드
        UserDao userDao = new UserDao(awsConnectionMaker);
        return userDao;
    }

    @Bean
    public UserDao localUserDao() {
        UserDao userDao = new UserDao(new LocalConnectionMaker());
        return userDao;
    }
}

🟢 UserDaoTest

  • @ExtendsWith() : Spring을 쓰기 위해 작성
  • @ContextConfiguraiton() 를 추가 해주어야함 (설정파일이 어디있는지 특정화)
import likelion.domain.User;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;

import java.sql.SQLException;

@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = UserDaoFactory.class)
class UserDaoTest {

    @Autowired
    ApplicationContext context;

    @Test
    void addAndSelect() throws SQLException, ClassNotFoundException {
        UserDao userDao = context.getBean("awsUserDao", UserDao.class);

        User user = new User("10", "Lotto", "6666");
//        userDao.add(user);

        User selectedUser = userDao.findbyId("10");
        Assertions.assertEquals("Lotto", selectedUser.getName());
    }
}

0개의 댓글