Java lang

[Java] 생성자에서는 getInstance호출에 신중하자.

Razelo 2022. 11. 30. 12:10

오늘 코드를 작성하던 중 신기한 현상을 만났다. 

 

게임 서버를 구동했는데 정상 작동하지 않았다.

 

신기하게도 아무런 에러도 찍히지 않았다.

 

분명 어딘가 문제가 있을 것이라고 생각하고 살펴보았지만 짐작가는 곳은 없어서 빠르게 해결하기 위해 출력문으로 찍어보고 문제의 핵심을 찾았다. 

 

아래 두 코드 부분을 보자.

 

두 코드는 각각 Game과 RedisTemplate의 생성자에 관한 코드이다. 

 

 

왼쪽에 존재하는 Game에서는 RedisTemplate의 객체를 getInstance를 통해 받아오려 하고 있다.

 

오른쪽의 RedisTemplate 또한 Game의 객체를 getInstance를 통해 받아오려 하고 있다. 

 

참고로 Game와 RedisTemplate 모두 싱글톤으로 작성되어있다. 

 

그렇다면 이렇게 생성자 내에서 서로가 싱글톤으로 작성된 상대방을 호출하려하면 어떤 현상이 발생할까? 

 

무한루프에 빠질 수 있다.

 

Game 생성자에서 RedisTemplate의 객체를 요청하면 당연히 RedisTemplate은 getInstance의 로직대로 객체가 없는 상태에서는 해당 객체를 생성하기 위해 RedisTemplate 내에 존재하는 생성자를 통해 객체를 만들어낸다.

 

하지만 RedisTemplate 내의 생성자 또한 마찬가지로 Game의 getInstance를 통해 getInstance 로직대로 Game 객체가 없다면 새로운 Game객체를 만들게 된다. 

 

그렇기 때문에 이 부분에서 더 이상 코드가 진행되지 못하는 것이다. 

 

잘하는 친구에게 곧장 물어보니 생성자에서는 getInstance 호출에 대해서 주의해야한다고 말을 해주었다. 

 

자 그렇다면 이 문제를 어떻게 해결할 수 있을까? 

 

친구가 한 가지 방법을 제안해주었는데 Dependency Injection처럼 외부에서 주입해주는 방법이 하나의 선택지가 될 수 있다고 말해주었다. 

 

그래서 지금 고민하는 와중에 외부에서 주입해주는 메서드를 하나 만들어줄지 아니면 애초에 생성할때 인자로 넘겨주게 만들것인지에 대해 고민하고 있다. 

 


위 내용을 작성하고나서 얼마되지 않아 문제를 해결했다. 

 

파라미터로 넘겨주거나 주입을 해주는 등의 방법을 쓰게 되면 외부에서 추가적인 코드가 필요할 것이라고 생각되어 Game과 RedisTemplate 클래스 둘 중 하나를 Utility Class 로 만들어서 해결했다. 

 

다행인 것은 RedisTemplate을 Utility 클래스로 바꿀지에 대한 고민을 이전부터 하고 있던 터라서 오히려 잘된 셈이다. 

 

참고로 유틸리티 클래스는 인스턴스 메서드와 인스턴스 변수를 일절 제공하지 않고 오직 정적 메서드와 변수만을 제공하는 클래스를 의미한다.

 

그래서 클래스의 본질인 데이터와 데이터 처리를 위한 로직의 캡슐화를 염두에 두지 않고 그냥 비슷한 기능의 메서드와 상수를 모아서 캡슐화 한것이 유틸리티 클래스라고 볼 수 있다. 

 

유틸리티 클래스에 대한 설명은 제가 이전에 작성했던 포스팅이 있는데 그걸 참고하시면 됩니다. 

 

https://spongeb0b.tistory.com/100

 

[Java] 유틸리티 클래스란 무엇인가?

유틸리티 클래스란 무엇인가? https://morningcoding.tistory.com/entry/Java15-%ED%81%B4%EB%9E%98%EC%8A%A4-%EB%B3%80%EC%88%98-%ED%81%B4%EB%9E%98%EC%8A%A4-%EB%A9%94%EC%84%9C%EB%93%9C%EC%99%80-%EC%9C%A0%ED%8B%B8%EB%A6%AC%ED%8B%B0-%ED%81%B4%EB%9E%98%E

spongeb0b.tistory.com

 

반응형