본문 바로가기

Spring/Spring

(SPRING) IoC 컨테이너 - @Autowired

생성자 @Autowired

@Service
public class BookService {

    BookRepository bookRepository;
    
    @Autowired
    public BookService(BookRepository bookRepository) {
        this.bookRepository = bookRepository;
    }
}

실행결과

me.choi.demospring51.BookRepository 타입에 해당하는 Bean을 찾을 수 가 없다.

@Repository 추가 - Bean등록

@Repository
public class BookRepository {

}

 

그래 인정! 생성자이기 때문에 BookService에 대한 빈을 생성하지 못하는구나.

Bookservice bookService  = new BookService(bookRepository); -> 불가!


Setter @Autowired

bookRepository에 대한 Bean을 생성하지 않은 상태 (즉 @Repository 설정 안 함)

@Service
public class BookService {

    BookRepository bookRepository;

    @Autowired
    public void setBookRepository(BookRepository bookRepository) {
        this.bookRepository = bookRepository;
    }
}

실행결과 위의 상황과 동일

그렇다면 생성자도 아닌 Setter인대 적어도 BookService에 대한 Bean은 생성되야하는 것이 정상 아닐까?

@Autowired를 작성하여서 

의존성을 주입하려고 하기 때문이다.

 

이때 required = false를 주어 Optional로 만들어 버리면 된다.

@Service
public class BookService {

    BookRepository bookRepository;

    @Autowired(required = false)
    public void setBookRepository(BookRepository bookRepository) {
        this.bookRepository = bookRepository;
    }
}
@SpringBootApplication
public class Demospring51Application {

	public static void main(String[] args) {
		ConfigurableApplicationContext run = SpringApplication.run(Demospring51Application.class, args);
		String[] beanDefinitionNames = run.getBeanDefinitionNames();
		System.out.println(Arrays.toString(beanDefinitionNames));
	}

}

bookService에 대한 bean은 생성되고 bookRepository에 대한 bean은 생성되지 않았다.


Field @Autowired

@Service
public class BookService {

    @Autowired(required = false)
    BookRepository bookRepository;

}

경우의 수

  • 해당 타입의 빈이 없는 경우
  • 해당 타입의 빈이 한 개인 경우
  • 해당 타입의 빈이 여러 개인 경우

특정 타입의 빈이 여러 개인 경우

public interface BookRepository {

}
@Repository
public class MyBookRepository implements BookRepository{
}
@Repository
public class JunwooBookRepository implements BookRepository{
}

 

이때 스프링은 어떤 BookRepository를 주입해줄까?

@Service
public class BookService {

    @Autowired
    BookRepository bookRepository;

}

주입을 못해준다.

스프링이 어떤 타입을 주입해야 할지 모르기 때문이다.


@Primary : 여러 가지 동일한 Bean을 주입해야 할 경우에 특정 빈을 사용할 것이라고 지정하는 애노테이션

@Repository @Primary
public class JunwooBookRepository implements BookRepository{
}

확인 : BookService 빈 생성 시 어떠한 빈을 주입받는지

@Service
public class BookService {

    @Autowired
    BookRepository bookRepository;

    public void printBookRepository() {
        System.out.println(bookRepository.getClass());
    }
}
@Component
public class BookServiceRunner implements ApplicationRunner {
    @Autowired
    BookService bookService;

    @Override
    public void run(ApplicationArguments args) throws Exception {
        bookService.printBookRepository();
    }

 

실행결과

@Qualifier("small case의 클래스명") : 주입받을 빈을 명시하는 방법

@Service
public class BookService {

    @Autowired @Qualifier("myBookRepository")
    BookRepository bookRepository;

    public void printBookRepository() {
        System.out.println(bookRepository.getClass());
    }
}

실행결과

같은 타입의 모든 Bean을 주입받을 때 : List 선언

@Service
public class BookService {

    @Autowired
    List<BookRepository> bookRepository;

    public void printBookRepository() {
        this.bookRepository.forEach(System.out::println);
    }
}

실행결과

필드 명을 주입받을 Bean의 small case를 작성하여 주입

@Service
public class BookService {

    @Autowired
    BookRepository junwooBookRepository;

    public void printBookRepository() {
        System.out.println(this.junwooBookRepository.getClass());
    }
}


동작원리

BeanPostProcessor

https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/beans/factory/config/BeanPostProcessor.html

 

BeanPostProcessor (Spring Framework 5.2.2.RELEASE API)

Factory hook that allows for custom modification of new bean instances — for example, checking for marker interfaces or wrapping beans with proxies. Typically, post-processors that populate beans via marker interfaces or the like will implement postProcess

docs.spring.io

빈의 인스턴스를 생성한 다음 빈의 초기화 라이프사이클(initialization) 이전 이후에 또 다른 작업을 할 수 있는 라이프사이클 콜백이 있다.

이를 BeanPostProcessor라고 한다.

 

Bean 인스턴스가 만들어지고 나서 부가적인 처리를 하는 방법 두 가지

 

1. 애노테이션 사용

@PostConstruct
public void setUp() {
    
}

2. InitailiInitializingBean 구현

@Service
public class BookService implements InitializingBean {

    @Autowired
    BookRepository junwooBookRepository;

    public void printBookRepository() {
        System.out.println(this.junwooBookRepository.getClass());
    }


    @Override
    public void afterPropertiesSet() throws Exception {
        
    }
}

 

https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.html

 

AutowiredAnnotationBeanPostProcessor (Spring Framework 5.2.2.RELEASE API)

Post-process the given property values before the factory applies them to the given bean. Allows for checking whether all dependencies have been satisfied, for example based on a "Required" annotation on bean property setters. Also allows for replacing the

docs.spring.io

즉 Bean 초기화 이전에

AutowiredAnnotationBeanPostProcessor 발동하여 @Autowired를 처리한다.

 (빈의 주입)

 


@Service
public class BookService {

    @Autowired
    BookRepository junwooBookRepository;

//    public void printBookRepository() {
//        System.out.println(this.junwooBookRepository.getClass());
//    }

    @PostConstruct
    public void setUp() {
        System.out.println(this.junwooBookRepository.getClass());
    }
}

찍히는 곳이 다른데...?

 

이전의 라이프사이클은 애플리케이션 구동이 완료되고 처리되지만

현재의 라이프사이클은 애플리케이션 구동 중에 처리된다.

 

 

 

 

일반적인 Bean들에게 

BeanPostProcessor의 애노테이션 처리 로직을 적용한다.

 

 

 

 

AutowiredAnnotationBeanPostProcessor가 빈으로 등록되어있는지 확인

@Component
public class BookServiceRunner implements ApplicationRunner {
    @Autowired
    BookService bookService;

    @Autowired
    ApplicationContext applicationContext;

    @Override
    public void run(ApplicationArguments args) throws Exception {
        //bookService.printBookRepository();
        AutowiredAnnotationBeanPostProcessor bean = applicationContext.getBean(AutowiredAnnotationBeanPostProcessor.class);
        System.out.println(bean);

    }
}

실행결과


코드 참조

https://github.com/mike6321/Spring/tree/master/Spring/demospring51

 

mike6321/Spring

Contribute to mike6321/Spring development by creating an account on GitHub.

github.com