유튜브를 보다가 토비님이 제목과 같은 영상을 올리셔서 정리하고자 한다.
영상을 만드신 이유는 인프런 질문에 @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
Nested Classes (The Java™ Tutorials > Learning the Java Language > Classes and Objects)
The Java Tutorials have been written for JDK 8. Examples and practices described in this page don't take advantage of improvements introduced in later releases and might use technology no longer available. See Java Language Changes for a summary of updated
docs.oracle.com
'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 |