@Component
빈 스캐너가 @Component
가 붙은 클래스를 빈으로 등록한다.
아래 클래스는 annotatedHello
라는 아이디로 빈 등록된다.
@Component
public class AnnotatedHello {
...
}
빈의 아이디는 임의로 설정할 수 있다.
@Component("myAnnotationHello")
public class AnnotatedHello {
...
}
@Component
는 메타 애노테이션으로도 사용가능하다.
즉, 다음과 같이 커스텀 애노테이션을 정의할 수 있다.
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Compenent
public @interface MyComponent {
String value() default "";
}
@Configuration & @Bean
@Configuration
애노테이션을 클래스에 달아두면 자바코드로 빈 설정 메타정보를 담을 수 있다.
@Configuration
public class AnnotatedHelloConfig {
@Bean
public AnnotatedHello annotatedHello() {
return new AnnotatedHello();
}
}
클래스 안의 @Bean
이 달려있는 메서드는 빈으로 등록된다.
타입은 반환타입인 AnnotatedHello
으로,
아이디는 메서드 이름인 annotatedHello
로 등록된다.
또한 AnnotatedHelloConfig
자체도 빈으로 등록된다.
@Configuration
에서 등록된 빈은 싱글톤으로 생성된다.
@Configuration
public class AnnotatedHelloConfig {
@Bean
public Person person1() {
Person person = new Person();
// 자동차는 하나만 만들어진다.
person.setCar(car());
return person;
}
@Bean
public Person person2() {
Person person = new Person();
// 자동차는 하나만 만들어진다.
person.setCar(car());
return person;
}
@Bean
public Car car() {
return new Car();
}
}
@Configuration+@Bean
으로 등록되는 빈은 싱글톤이기 때문에car()
를 여러번 호출해도 같은 객체가 반환이 된다.
결국 person1
빈과 person2
빈은 같은 자동차 객체를 가지게 된다.
반면에 일반 클래스에 @Bean
만 붙는다면 싱글톤으로 관리되지 않는다.
public class Normal {
@Bean
public Person person1() {
Person person = new Person();
// 자동차는 여러개 만들어 질 수 있다.
person.setCar(car());
return person;
}
@Bean
public Person person2() {
Person person = new Person();
// 자동차는 여러개 만들어 질 수 있다.
person.setCar(car());
return person;
}
@Bean
public Car car() {
return new Car();
}
}
이번에는 car
가 싱글톤 빈이 되지 않기 때문에car()
를 여러번 호출하면 각각 다른 객체가 생성된다.
person1
빈과 person2
빈은 다른 자동차 객체를 가지게 된다.
그렇다면 일반 클래스에서 싱글톤 빈을 사용하고 싶다면 어떻게 해야할까?
public class Normal {
private Car car;
public void setCar(Car car) {
this.car = car;
}
@Bean
public Person person1() {
Person person = new Person();
// 자동차는 여러개 만들어 질 수 있다.
person.setCar(this.car);
return person;
}
@Bean
public Person person2() {
Person person = new Person();
// 자동차는 여러개 만들어 질 수 있다.
person.setCar(this.car);
return person;
}
@Bean
public Car car() {
return new Car();
}
}
Normal
클래스가 Car
빈을 주입 받도록 하면 같은 빈 객체를 쓸 수 있을 것이다.car()
메서드는 스프링 컨테이너에 의해 싱글톤 오브젝트를 만들 때 한번만 호출된다.
AnnotationConfigApplicationContext
애노테이션을 사용할 경우 AnnotationConfigApplicationContext
를 이용하면 안에 빈 스캐너가 내장되어 있어, @Component
가 붙은 클래스를 빈으로 등록해준다.
public void simpleBeanScanning() {
ApplicationContext ctx = new AnnotationConfigApplicationContext("spring.demo.2jun0.bean");
// 빈의 아이디로 가져올 수 있다.
AnnotatedHello h = ctx.getBean("annotatedHello", AnnotatedHello.class);
}
생성자에 @Configuration
이 붙은 클래스를 넣어주는 방법도 있다.
public void simpleBeanScanning() {
ApplicationContext ctx = new AnnotationConfigApplicationContext(AnnotatedHelloConfig.class);
// 특정 타입의 빈이 하나만 존재한다면 이름을 생략할 수 있다.
AnnotatedHello h = ctx.getBean(AnnotatedHello.class);
// 설정 클래스도 빈으로 등록된다.
AnnotatedHelloConfig c = ctx.getBean("annotatedHelloConfig", AnnotatedHelloConfig.class);
}
@Resource 빈 의존관계 설정 방법
수정자 메서드
public class Hello {
...
@Resource(name="printer")
public void setPrinter(Printer printer) {
this.printer = printer;
}
}
필드
이런 방식을 필드 주입이라고 한다.
private여도 스프링이 주입해준다.
public class Hello {
@Resource(name="printer")
private Printer printer;
}
@Resource
는 name을 생략해도 된다. 다만, 이렇게 하면 메서드나 필드 이름으로 적용된다.
(@Autowired
는 타입으로 찾는다.)
@Autowired 빈 의존관계 설정 방법
@Autowired
은 @Resource
와 비슷하지만 다른 점은 이름 대신 타입으로 찾는다는 점이다.
수정자 메서드
public class Hello {
...
@Autowired
public void setPrinter(Printer printer) {
this.printer = printer;
}
}
필드 주입
public class Hello {
@Autowired
private Printer printer;
}
생성자 주입
생성자로 주입할 수 있다는 것도 @Resource
와 다른 점이다.
public class Hello {
// 혼동을 피하기 위해 하나의 생성자에만 적용할 수 있다.
@Autowired
public Hello(Printer printer, Reader reader) {
this.printer = printer;
this.reader = reader;
}
}
일반 메서드 주입
일반 메서드에도 @Autowired
를 적용할 수 있다.
public class Hello {
// 한 개 이상의 메서드에 적용 가능!
@Autowired
public void config(Printer printer, Reader reader) {
this.printer = printer;
this.reader = reader;
}
}
동일한 타입의 빈이 여러개 있을 때
동일한 타입의 빈이 여러개 있을땐 필드나, 파라미터를 컬렉션이나 배열로 선언하면 된다.
public class Hello {
@Autowired
private Collection<Printer> printers;
@Autowired
private Printer[] printers;
}
Map을 이용하면 {이름:객체} 쌍으로 받을 수 있다.
public class Hello {
@Autowired
private Map<String, Printer> printerByName;
}
@Qualifier
@Qualifier
를 사용하면 @Autowired
에도 빈 이름을 지정할 수 있다.
필드에 사용할 수 있고,
public class Hello {
@Autowired
@Qualifier("myPrinter")
private Printer printer;
}
수정자에 사용할 수 있고,
public class Hello {
...
@Autowired
@Qualifier("myPrinter")
public void setPrinter(Printer printer) {
this.printer = printer;
}
}
파라미터에 사용할 수 있다.
public class Hello {
@Autowired
public void config(@Qualifier("myPrinter") Printer printer, Reader reader) {
this.printer = printer;
this.reader = reader;
}
}
@Value으로 디폴트 값 설정하기
빈이 없더라도 @Value
를 이용해 디폴트 값을 정할 수 있다.
public class Hello {
@Value("1.2")
private double num;
}
'프로그래밍 > 기타' 카테고리의 다른 글
백준 허브 사용 후기 (0) | 2023.01.21 |
---|---|
스타듀밸리 순무 모드 업데이트 0.7.0 (1) | 2023.01.18 |
스프링 시큐리티 기본 user/password 안먹힐때 인코더 확인해라! (0) | 2023.01.02 |
RuntimeError: dictionary changed size during iteration (0) | 2022.10.21 |
synchronized, CAS, ABA (0) | 2022.08.21 |