Core Technologies
In the preceding scenario, using @Autowired works well and provides the desired modularity, but determining exactly where the autowired bean definitions are declared is still somewhat ambiguous. For example, as a developer looking at ServiceConfig, how do
docs.spring.io
틀린 해석이 있다면 알려주세요 💥
1.9.5. Using CustomAutowireConfigurer ~ 끝까지
1.9.5. Using CustomAutowireConfigurer
CustomAutowireConfigurer (Spring Framework 6.0.6 API)
postProcessBeanFactory Modify the application context's internal bean factory after its standard initialization. All bean definitions will have been loaded, but no beans will have been instantiated yet. This allows for overriding or adding properties even
docs.spring.io
customAutowireConfigurer 는 Spring annotation으로 지정되지 않은 경우에도 custom qualifier를 등록할 수 있는BeanFactoryPostProcessor 이다
<bean id="customAutowireConfigurer"
class="org.springframework.beans.factory.annotation.CustomAutowireConfigurer">
<property name="customQualifierTypes">
<set>
<value>example.CustomQualifier</value>
</set>
</property>
</bean>
The AutowireCandidateResolver determines autowire candidates by:
- The autowire-candidate value of each bean definition // autowire-candidate 각 빈의 definition값
- Any default-autowire-candidates patterns available on the <beans/> element // 요소 candidates 모든 패턴
- The presence of @Qualifier annotations and any custom annotations registered with the CustomAutowireConfigurer // @Qualifier 애노테이션이 있거나 커스텀애노테이션이 있는 경우
When multiple beans qualify as autowire candidates, the determination of a “primary” is as follows: If exactly one bean definition among the candidates has a primary attribute set to true, it is selected.
1.9.6. Injection with @Resource
Spring은 필드 또는 bean 속성 setter 메서드에서 JSR-250 @Resource 주석(jakarta.annotation.Resource)을 사용하여 주입을 지원한다.
이는 Jakarta EE의 일반적인 패턴이다(예: JSF 관리 Bean 및 JAX-WS end point).
Spring은 Spring 관리 객체에 대해서도 이 패턴을 지원하고 있다. @Resource는 이름 속성을 사용한다.
기본적으로 Spring은 해당 값을 주입할 bean 이름으로 해석한다.
public class SimpleMovieLister {
private MovieFinder movieFinder;
@Resource(name="myMovieFinder") // @Resouce
public void setMovieFinder(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
}
이름을 명시적으로 지정해주지 않으면 기본 default name은 필드 이름이나 setter method에서 파생된다
필드의 경우 필드 이름을 사용하고, setter method의 경우에는 bean property 이름을 가져온다
이렇게 하면 Resource 이름을 movieFinder 로 주입할 것이다
public class SimpleMovieLister {
private MovieFinder movieFinder;
@Resource
public void setMovieFinder(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
}
해석규칙
SimpleJndiBeanFactory (Spring Framework 6.0.6 API)
Determine the type of the bean with the given name. More specifically, determine the type of object that BeanFactory.getBean(java.lang.String) would return for the given name. For a FactoryBean, return the type of object that the FactoryBean creates, as ex
docs.spring.io
명시적인 이름이 지정되지 않은 @Resource 사용의 exclusive case에서 @Autowired와 유사하게 @Resource는 특정 명명된 bean대신 기본 type 을 찾아 해결 가능한 종속성(BeanFactory, ApplicationContext, ResourceLoader, ApplicationEventPublisher 및 MessageSource 인터페이스)와 매칭한다
예제에서
customerPreferenceDao 필드는 먼저 "customerPreferenceDao"라는 빈을 찾은 다음 CustomerPreferenceDao 유형에 대한 기본 유형 일치로 폴백한다
public class MovieRecommender {
@Resource
private CustomerPreferenceDao customerPreferenceDao;
@Resource
private ApplicationContext context; // 해결가능한 종속성유형 ApplicationContext 주입
public MovieRecommender() {
}
// ...
}
1.9.7. Using @Value
@Value 는 일반적으로 externalized (외부화) 된 properties를 주입할 때 쓴다
@Component
public class MovieRecommender {
private final String catalog;
public MovieRecommender(@Value("${catalog.name}") String catalog) {
this.catalog = catalog;
}
}
@Configuration
@PropertySource("classpath:application.properties")
public class AppConfig { }
application.properties 에 세팅
catalog.name=MovieCatalog
이 경우에 MovieCatalog의 값은 동일하다
In that case, the catalog parameter and field will be equal to the MovieCatalog value.
A default lenient embedded value resolver is provided by Spring. It will try to resolve the property value and if it cannot be resolved, the property name (for example ${catalog.name}) will be injected as the value. If you want to maintain strict control over nonexistent values, you should declare a PropertySourcesPlaceholderConfigurer bean, as the following example shows:
@Configuration
public class AppConfig {
@Bean
public static PropertySourcesPlaceholderConfigurer propertyPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
}
위의 구성을 사용하면 ${} 자리 표시자를 확인할 수 없을 경우 Spring initialization이 실패된다
setPlaceholderPrefix, setPlaceholderSuffix 또는 setValueSeparator와 같은 메서드를 사용하여 자리 표시자를 사용자 지정할 수 있다
** Spring Boot는 기본적으로 application.properties 및 application.yml 파일에서 속성을 가져오는 PropertySourcesPlaceholderConfigurer 빈을 구성한다
Spring에서 제공하는 converter 을 이용해서 (Integer or int 를 String 으로 변환하는 등의 예) 자동 처리할 수 있다
쉼표로 구분한 값들은 자동으로 배열 변환된다
@Component
public class MovieRecommender {
private final String catalog;
public MovieRecommender(@Value("${catalog.name:defaultCatalog}") String catalog) {
this.catalog = catalog;
}
}
Spring BeanPostProcessor는 ConvensionService를 사용하여 @Value의 문자열 값을 target type으로 변환하는 프로세스를 처리해준다. 고유한 커스텀 타입에 대한 변환 지원을 제공하려면 ConversionService Bean 인스턴스를 제공해도 된다
@Configuration
public class AppConfig {
@Bean
public ConversionService conversionService() {
DefaultFormattingConversionService conversionService = new DefaultFormattingConversionService();
conversionService.addConverter(new MyCustomConverter());
return conversionService;
}
}
SpEL식이 @Value에 포함된 경우에는 runtime 시 dynamic하게 계산된다
@Component
public class MovieRecommender {
private final String catalog;
public MovieRecommender(@Value("#{systemProperties['user.catalog'] + 'Catalog' }") String catalog) {
this.catalog = catalog;
}
}
SpEL을 사용하면 더 복잡한 데이터 구조의 사용도 가능하게 된다
@Component
public class MovieRecommender {
private final Map<String, Integer> countOfMoviesPerCatalog;
public MovieRecommender(
@Value("#{{'Thriller': 100, 'Comedy': 300}}") Map<String, Integer> countOfMoviesPerCatalog) {
this.countOfMoviesPerCatalog = countOfMoviesPerCatalog;
}
}
1.9.8. Using @PostConstruct and @PreDestroy
CommonAnnotationBeanPostProcessor는 @Resource 주석뿐만 아니라 JSR-250 라이프사이클 주석(jakarta.annotation.PostConstruct 및 jakarta.annotation.PreDestroy)도 인식한다.
Spring 2.5에 도입된 이러한 주석에 대한 지원은 초기화 콜백 및 소멸 콜백에 설명된 수명 주기 콜백 메커니즘에 대한 대안을 제공한다. CommonAnnotationBeanPostProcessor가 Spring ApplicationContext에 등록되어 있는 경우 이러한 주석 중 하나를 전달하는 메서드는 해당 Spring 수명 주기 인터페이스 메서드 또는 명시적으로 선언된 콜백 메서드와 동일한 수명 주기 지점에서 호출한다.
public class CachingMovieLister {
@PostConstruct
public void populateMovieCache() {
// populates the movie cache upon initialization...
}
@PreDestroy
public void clearMovieCache() {
// clears the movie cache upon destruction...
}
}
내가 정리한 effects of combining various lifecycle mechanisms
https://delightpip.tistory.com/115
Jakarta EE 9부터 패키지는 현재 jakarta.annotation에 있다. 필요한 경우 지금 Maven Central을 통해 jakarta.annotation-api 아티팩트를 가져와 다른 라이브러리와 마찬가지로 애플리케이션의 클래스 경로에 추가해서 쓰면 된다