유튜브를 보다가 토비님이 제목과 같은 영상을 올리셔서 정리하고자 한다.
영상을 만드신 이유는 인프런 질문에 @Configuration과 proxyBeanMethods 강의를 실습하던 도중
Bean1, Bean2, Common, MyConfig 클래스들을 Static 클래스로 만들어야 정상적인 테스트가 가능
해당 클래스들을 정적 클래스가 아닌 내부 클래스로 작성하니 적절한 빈 타입을 찾을 수 없다는 에러에서 시작됐다.
개요
@SpringBootApplication
public class SpringbootAcApplication {
@Component
static class StaticInnerClass {
public StaticInnerClass() {
System.out.println("StaticInnerClass");
}
}
public static void main(String[] args) {
ConfigurableApplicationContext ac = SpringApplication.run(SpringbootAcApplication.class, args);
System.out.println(ac.getBean(StaticInnerClass.class));
}
}
com.example.springbootac.SpringbootAcApplication$StaticInnerClass@3bb8aabc
다음과 같이 hashCode가 나온다.
@SpringBootApplication
public class SpringbootAcApplication {
// Static Nested Class
@Component
static class StaticInnerClass {
public StaticInnerClass() {
// Local Class (Nested Class)
class LocalClass {
public LocalClass() {
System.out.println("LocalClass");
}
}
// Anonymous Class
var runnable = new Runnable() {
@Override
public void run() {
System.out.println("Runnable");
}
};
System.out.println("StaticInnerClass");
}
}
// (Non-Static Nested) Inner Class
@Component
class InnerClass {
public InnerClass() {
System.out.println("InnerClass");
}
}
public static void main(String[] args) {
ConfigurableApplicationContext ac = SpringApplication.run(SpringbootAcApplication.class, args);
System.out.println(ac.getBean(StaticInnerClass.class));
System.out.println(ac.getBean(InnerClass.class));
}
}
두 클래스 모두 Bean으로 등록된 것으로 보인다.
com.example.springbootac.SpringbootAcApplication$StaticInnerClass@29a4f594 com.example.springbootac.SpringbootAcApplication$InnerClass@57b75756
Static Nested Class는 Top Level Class로 다른 파일로 클래스를 정의한 것과 거의 99% 같다.
(위치만 다른 클래스 안쪽 - Outer Class와 깊이 관여하고(Grouping)
내부에서만 사용할 것 같을때 사용하고 가독성이 좋아짐)
Inner Class
외부 클래스의 오브젝트가 먼저 존재해야 하며, 외부 클래스와 직접적인 연관관계를 맺은 경우 InnerClass의 Object가 만들어짐 (외부 인스턴스(특정 Object)와 연결시켜서만 만들 수 있음)
@SpringBootApplication
public class SpringbootAcApplication {
private String name;
// Static Nested Class
@Component
static class StaticInnerClass {
void print() {
System.out.println(name); // 외부 클래스와 무관계 (멤버 변수 사용 불가)
}
}
// (Non-Static Nested) Inner Class
@Component
class InnerClass {
void print() {
System.out.println(name); //외부 클래스와 직접적인 관계 (멤버 변수 사용 가능)
}
}
public static void main(String[] args) {
ConfigurableApplicationContext ac = SpringApplication.run(SpringbootAcApplication.class, args);
System.out.println(ac.getBean(StaticInnerClass.class));
System.out.println(ac.getBean(InnerClass.class));
new StaticInnerClass();
SpringbootAcApplication outerClass= new SpringbootAcApplication();
InnerClass innerClass = outerClass.new InnerClass();
}
}
Spring 관점에서
@Component -> 클래스 정보를 이용해서 Bean을 만들어라는 선언
Reflection을 이용해서 클래스 정보를 가져가 클래스로 새로운 인스턴스를 만들어 Bean Object로 써라
InnerClass는 독자적으로 쓸 수 없음 (Bean이 될 수 없음)
But @SpringBootApplication은 @ComponentScan 뿐 만 아니라 @Component어노테이션도 있다.
1. OuterClass가 Bean으로 등록 되었는지 확인
2. 만약 OuterClass가 Bean으로 등록 되었다면 등록된 OuterClass를 이용해서 outerClass.new InnerClass();
3. InnerClass를 Bean으로 등록
정리
중첩 클래스 - 클래스 안에 클래스가 정의 된 것
중첩 클래스는 두 가지로 구분이 된다.
1. static nested class (정적 중첩 클래스)
2. Inner class (내부 클래스)(non-static-nested)
InnerClass는 OuterClass의 Object(Instance)가 존재해야 연관관계를 맺고 자신은 Object로 만들 수 있음
OuterClass를 Bean으로 등록하고 InnerClass를 Bean으로 등록시키는 것이 실제로 쓸모가 있는가?
static nested class의 경우 DI를 통해 OuterClass 정보를 주입하는데 InnerClass는 그 과정이 필요 없음
OuterClass의 내부 정보를 활용하는 InnerClass로 Bean을 분리하여 동작할 필요가 있는 경우 활용할 수 있다. ex) 모니터링
BeanFactoryMethod를 가지고 일반 @Component붙은 클래스 안에 정의하는 경우 Bean으로 노출이 되면 OuterClass쪽의 정보를 수집할 수 있음 - 다른 Bean에 모니터링 정보를 제공하는 용도로 Reference Guide에 나와있다고 한다. (Light Mode)
참조
https://www.youtube.com/watch?v=2G41JMLh05U
https://docs.oracle.com/javase/tutorial/java/javaOO/nested.html
'BackEnd > Spring & Springboot Study' 카테고리의 다른 글
스프링 핵심 원리 - 기본편 [객체 지향 설계와 스프링] (0) | 2023.04.17 |
---|---|
RestTemplate은 스프링에서 제거되나요? (1) | 2023.03.14 |
토비의 스프링부트 - 이해와 원리 #0 강의소개 및 학습 방법 (0) | 2023.02.06 |
스프링 시큐리티 공부할때 순서 (0) | 2022.12.29 |
springboot의 특징 5가지 임시저장 (0) | 2022.12.29 |