728x90

@Configuration을 사용하는 것과 그냥 팩토리를 사용하는 것과 다른 것이 없어보인다.

 

만약 팩토리를 사용하여 userDao() 메서드를 여러번 호출한다면 동일한 오브젝트가 돌아올까?

당연히 아니고, 매번 새로운 오브젝트가 생성되어 다른 오브젝트가 만들어진다.

 

하지만 애플리케이션 컨텍스트에서 getBean()을 사용해 가져오는 객체는 모두 동일한 오브젝트를 가져오게 된다.

싱글톤으로 저장하고 관리하기 때문이다.

 

왜 스프링에서는 빈을 싱글톤으로 관리할까?

스프링은 대규모의 요청을 처리하기 위해 만들어졌다.

만약 싱글톤을 사용하지 않는다면 요청마다 오브젝트를 생성해야 하고, 생성에도 비용이 드는 것이 아니라 가비지 컬렉션에도 큰 비용이 들게 될 것이다.

그렇기에 하나의 오브젝트만 생성하고, 해당 오브젝트를 공유하는 싱글톤 패턴을 사용하는 것이다.

 

하지만 기존의 싱글톤 패턴은 약간의 문제점이 있었다. (상속 받으면 기본 생성자가 private이다 등등..)

그렇기에 평범한 자바 클래스를 이런 싱글톤으로 활용할 수 있도록 스프링이 기능을 제공한다.

 

하지만 자바는 멀티 스레드 환경이다.

이러한 상황에서 싱글톤을 사용하게 된다면 인스턴스 변수의 사용에 큰 문제가 발생할 수도 있다.

 

기존의 코드를 다음과 같이 바꿔보자.

package seungkyu;

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

public class UserDao {

    private final ConnectionHelper connectionHelper;
    
    private Connection c;
    private User user;

    public UserDao(ConnectionHelper connectionHelper) {
        this.connectionHelper = connectionHelper;
    }

    public User get(String id) throws ClassNotFoundException, SQLException {

//        Connection connection = connectionHelper.makeConnection();
        this.c = connectionHelper.makeConnection();
        PreparedStatement preparedStatement = c.prepareStatement(
                "select * from users where id = ?"
        );

        preparedStatement.setString(1, id);

        var resultSet = preparedStatement.executeQuery();

        resultSet.next();

        this.user = new User();
        this.user.setId(resultSet.getString("id"));
        this.user.setName(resultSet.getString("name"));
        this.user.setPassword(resultSet.getString("password"));

        resultSet.close();
        preparedStatement.close();
        c.close();

        return user;
    }
}

 

이러면 UserDao의 User를 공유하게 되기에 해당 메서드를 사용하는 중간에 다른 메서드가 끼어든다면, 내용이 바뀔 수도 있다는 문제가 있다.

 

그렇기에 싱글톤을 사용할 때 다른 싱글톤 빈을 저장하는 용도나 final이라면 인스턴스 변수를 사용해도 괜찮지만, 수정이 될 수 있는 경우에는 인스턴스 변수를 사용하지 않는것이 좋다.

 

 

+ Recent posts