서블릿의 개수가 너무 많아 생성되는 객체들 또한 너무 많다.
어떻게 해결할 수 있을까?
위에서 서블릿 하나당 Service 객체가 만들어지고 이어서 똑같은 Repository 객체가 각각 3개씩 만들어진다. 이는 메모리 효율의 낭비를 야기한다. 어떻게 해결할 수 있을까?
우리는 싱글톤패턴으로 이 문제를 해결해보도록 한다.
public class CustomerService {
private CustomerRepository repository;
public CustomerService() {
repository = new CustomerRepository();
}
CustomerService를 예를 들어보도록하자.
위 코드를 보면 외부에서 CustomerService 객체를 마음대로 생성할 수 있다. 우린 이 서비스 객체가 하나씩만 생성되길 원한다.
이 때, 싱글톤 패턴의 핵심은 생성자를 private로 접근제한해서 외부에서 new연산자로 생성자를 호출할 수 없도록 막는 것이다.
public class CustomerService {
private CustomerRepository repository;
private CustomerService() {
repository = new CustomerRepository();
}
public을 private로 바꿨으니 외부에선 생성자를 이제 호출할 수 없다.
public class CustomerService {
private static CustomerService service = new CustomerService();
private CustomerRepository repository;
private CustomerService() {
repository = new CustomerRepository();
}
public static CustomerService getInstance() {
return service;
}
private static
은 자바에서 사용하는 두 개의 접근 지시자를 함께 사용한 것입니다.
private
: 이 접근 지시자는 해당 필드나 메서드가 선언된 클래스 내부에서만 접근 가능함을 나타냅니다. 다른 클래스에서는 접근할 수 없습니다.
static
: 이 키워드는 해당 필드가 클래스 레벨의 필드임을 나타냅니다. 즉, 이 필드는 클래스의 모든 인스턴스에서 공유되며 클래스가 메모리에 로드될 때 한 번만 생성됩니다.
따라서, private static CustomerService service = new CustomerService();
구문은 CustomerService 클래스의 인스턴스를 생성하고, 이를 클래스 레벨에서 공유되는 service
라는 필드에 할당하며, 이 필드는 CustomerService 클래스 내부에서만 접근 가능하다는 것을 의미합니다.
이렇게 생성된 service
객체는 JVM(Java Virtual Machine)의 메소드 영역에 저장됩니다. JVM의 메모리는 크게 힙 영역, 스택 영역, 메소드 영역으로 나뉩니다. 여기서 스태틱 변수는 메소드 영역에 저장되며, 프로그램이 시작될 때 생성되고 종료될 때 파괴됩니다. 즉, service
는 프로그램이 실행되는 동안에 계속 유지되며, 같은 클래스의 모든 인스턴스에서 공유됩니다.
이 코드는 싱글턴 패턴의 한 예입니다. 이 패턴을 사용하면, CustomerService
클래스의 인스턴스는 프로그램 내에서 단 한 번만 생성되고, 이후에는 getInstance()
메소드를 통해 이 인스턴스에 접근할 수 있습니다. 이 방식을 통해 리소스를 절약하고, 모든 곳에서 동일한 CustomerService
인스턴스를 사용할 수 있습니다.
@WebServlet("/loginservlet")
public class LoginServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
private CustomerService service;
public LoginServlet() {
//service = new CustomerService();
service = CustomerService.getInstance();
}
그리고 나서 위와 같이 서블릿 부분에서는 new로 생성자를 호출하는 것이 아닌 service = CustomerService.getInstance();
을 이용해 호출한다.
이제 위와 같이 각각의 서블릿들이 하나의 CustomerService를 이용하게 된다.
그럼 Repository도 싱글톤패턴으로 또 만들어야해?
위의 그림에서 보면 알 수 있듯이 어차피 서비스객체가 싱글톤패턴으로 하나만 만들어지므로 자연스레 레파지토리 객체를 한번만 호출하게 된다. 따라서 따로 만들필요는 없다.
위 사진은 하나의 서블릿을 이용하는 예인데, 아직 내가 모르는 부분이므로 다음에 정리하도록한다.