1. @ComponentScan과 @Component
- @ConponentScan으로 @Component를 자동 검색해서 빈으로 등록
- @Configuration이 붙은 자바 설정 클래스에 붙일 수 있다.
@Configuration
// @ComponentScan("com.fastcampus.ch3") - 패키지 지정
// @ComponentScan(basePackage = {"com.fastcampus.ch3"}) - 패키지 지정(다중)
// @ComponentScan(basePackageClasses = AppConfig.class) - 클래스 지정
@ConponentSCan // 이 애너테이션이 붙은 클래스의 패키지를 자동스캔
public class AppConfig {
...
}
// @Bean(name="superEngine") Engine superEngine() { return new SuperEngine(); }
// @Component("superEngine")
@Component
class SuperEngine extends Engine {}
- @Controller, @Service, @Repository, @ControllerAdvice의 메타 에너테이션
@Configuration
public class AppConfig {
// @Bean
// Car car(){
// return new Car();
// }
//
// @Bean
// @Scope("prototype")
// Engine engine(){
// return new Engine();
// }
//
// @Bean
// Door door(){
// return new Door();
// }
}
- 등록된 Bean들을 전부 주석처리 후 Main을 실행해 보면...
- Bean을 찾을 수 없다고 나오는데...
public class Main {
public static void main(String[] args) {
// AC를 생성 - AC의 설정파일은 AppConfig.class 자바설정
ApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
// Car car = (Car)ac.getBean("car"); // byName 객체(빈)을 조회
// Car car = ac.getBean("car", Car.class); // 위와 동일
// System.out.println("car = " + car);
// Engine engine = ac.getBean(Engine.class);
// Engine engine2 = ac.getBean(Engine.class);
// Engine engine3 = ac.getBean(Engine.class);
// System.out.println("engine = " + engine);
// System.out.println("engine2 = " + engine2);
// System.out.println("engine3 = " + engine3);
// Bean이 몇개나 등록되어있는가
System.out.println("ac.getBeanDefinitionCount() = " + ac.getBeanDefinitionCount());
// 등록된 Bean의 이름
System.out.println("ac.getBeanDefinitionNames() = " + Arrays.toString(ac.getBeanDefinitionNames()));
// // engine이라는 BeanDefinition이 있는지
// System.out.println("ac.containsBeanDefinition(\"engine\") = " + ac.containsBeanDefinition("engine"));
// // Bean 객체 Car의 @Scope가 Singleton인지아닌지
// System.out.println("ac.isSingleton(\"car\") = " + ac.isSingleton("car"));
// // Bean 객체 Engine의 @Scope가 prototype인지 아닌지
// System.out.println("ac.isPrototype(\"engine\") = " + ac.isPrototype("engine"));
}
}
- Main도 주석처리를해주면...
- appConfig가 등록되어있는데
ApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
- 여기서 등록해줘서 그렇다
@Configuration
@ComponentScan
public class AppConfig {
// @Bean
// Car car(){
// return new Car();
// }
//
// @Bean
// @Scope("prototype")
// Engine engine(){
// return new Engine();
// }
//
// @Bean
// Door door(){
// return new Door();
// }
}
- @ComponentScan을 붙여주면 이 패키지 안에서 @Component가 붙은 클래스를 찾는다.
@ToString
@Component
class Car{
Engine engine;
Door door;
}
@Component
class Engine {}
@Component
class Door {}
- class에 @Component를 붙여주면...
- 등록이 되었다.
2. @Value와 @PropertySource
- @PropertySource - 읽어올 파일 지정
- @Value - 읽어올 Key값 지정
- SysInfo.java
@Component
@PropertySource("setting.properties")
@ToString
public class SysInfo {
@Value("#{systemProperties['user.timezone']}")
String timeZone;
@Value("#{systemEnvironment['PWD']}")
String currDir;
@Value("${autosaveDir}")
String autoSaveDir;
@Value("${autosaveInterval}")
int autosaveInterval;
@Value("${autosave}")
boolean autosave;
}
- setting.properties
autosaveDir=/autosave
autosave=true
autosaveInterval=30
SysInfo info = ac.getBean(SysInfo.class);
System.out.println("info = " + info);
- 문자열을 Spring이 타입에 맞게 변경해준다.
- currDir(현재 디렉토리)가 null로 나와서 확인...
Map<String, String> env = System.getenv();
System.out.println("env = " + env);
- System.env에 있는 Key, Value값이 나온다.
3. @Autowired
- Spring container에서 타입으로 빈을 검색해서 참조 변수에 자동 주입(DI)
- 검색된 빈이 n개이면, 그 중에 참조변수와 이름이 일치하는 것을 주입
- 주입 대상이 변수일 때, 검색된 빈이 1개 아니면 예외 발생
- 주입 대상이 배열일 때, 검색된 빈이 n개라도 예외 발생X
- @Autowired(required=false)일 때, 주입할 빈을 못찾아도 예외 발생X
- Engine가 3개 있다면...?
@ToString
@Component
class Car{
@Autowired
Engine engine;
@Autowired
Door door;
}
@Component
class SuperEngine extends Engine{}
@Component
class TurboEngine extends Engine{}
@Component
class Engine {}
@Component
class Door {}
- class Engine가 주입된다.
- 이름이 같은걸 우선으로 찾기 때문
@Component
class SuperEngine extends Engine{}
@Component
class TurboEngine extends Engine{}
//@Component
class Engine {}
- class Engine을 주입 대상에서 제외하면?
- 에러 발생 single matching bean(한개를 찾으려 했는데 여러개라서 에러가 발생)
@ToString
@Component
class Car{
@Autowired
Engine[] engine;
@Autowired
Door door;
}
- Engine을 배열로 받으면?
- n개의 Engine이 들어간 모습
- 생성자 주입
@ToString
@Component
class Car{
// @Autowired
Engine[] engine;
// @Autowired
Door door;
@Autowired // 생략가능
Car(Engine[] engine, Door door){
this.engine = engine;
this.door = door;
}
}
- 기본 생성자가있으면?
@ToString
@Component
class Car{
// @Autowired
Engine[] engine;
// @Autowired
Door door;
Car(){}
// @Autowired
Car(Engine[] engine, Door door){
this.engine = engine;
this.door = door;
}
}
- @Autowired가 없는 생성자 일때
- @Autowired가 있을때
@ToString
@Component
class Car{
// @Autowired
Engine[] engine;
// @Autowired
Door door;
Car(){}
@Autowired
Car(Engine[] engine, Door door){
this.engine = engine;
this.door = door;
}
}
4. @Resource
- Spring container에서 이름으로 빈을 검색해서 참조 변수에 자동 주입(DI)
- 일치하는 이름의 빈이 없으면, 예외 발생
- byType이 2개 이상일때 @Qualifier를 이용해서 이름이 일치하는 Bean을 찾아서 등록할 수 있다.
- byType으로 주입후보를 결정하고 그 중 이름으로 일치하는걸 주입
class Car {
@Autowired
@Qualifier("superEngine")
Engine engine;
}
- byName으로 주입후보를 결정하고 일치하는걸 주입
class Car {
// @Resource(name="superEngine")
@Resource
Engine engine;
}
- 에러가 나는이유...
- class Engine의 @Component를 주석처리 해놨기 때문
- @Resource에 이름을 지정해주고 실행을해주면...
- SuperEngine이 잘 주입된 모습
- @Autowired만 해주면 에러가 나는데...
- 주입 후보가 2개나 있기 때문...
- @Qualifier를 붙여주면...
- 타입으로 검색된 빈이 여러개여도 이름이 일치하는 빈을 주입해준다.
5. 스프링 애너테이션(스프링 제공) vs 표준 애너테이션(자바 제공)
- Maven이 없기때문...
- javax.inject 버전 1로 해주면...
'Spring DI, AOP' 카테고리의 다른 글
7. 의존성 관리와 설정의 자동화(2) - 패스트캠퍼스 백엔드 부트캠프 3기 (0) | 2025.02.24 |
---|---|
6. 의존성 관리와 설정의 자동화(1) - 패스트캠퍼스 백엔드 부트캠프 3기 (0) | 2025.02.24 |
4. Bean과 ApplicationContext - 패스트캠퍼스 백엔드 부트캠프 3기 (2) | 2025.02.24 |
3. Spring DI의 원리(2) - 패스트캠퍼스 백엔드 부트캠프 3기 (2) | 2025.02.23 |
2. Java Reflection API - 패스트캠퍼스 백엔드 부트캠프 3기 (2) | 2025.02.21 |