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.8 은 ApplicationContext 컨테이너 확장하는 방법에 대해 설명하고 있는데
훑어보는 것으로 하고 넘기고, 1.9 를 자세히 살펴볼 예정
1.9. Annotation-based Container Configuration ~1.9.2. Fine-tuning Annotation-based Autowiring with @Primary
애노테이션이 익숙치않은 사람들은 이런 생각을 해보지않았을까?
이거.. 코드 안짜고 @애노테이션 이걸로 하는게 맞는건가??
나는 이런 생각을 해봤다. (앱에선 잘 안썼다)
해당 문서에서는 이 질문에 대한 답을 주고 있다.
"상황에 따라 다르다"
XML이든 애노테이션이든 각 장단점이 있고, 어떤 전략이 적합한지 결정하는 것은 개발자의 몫이다
주석의 정의된 방식은 많은 context 를 제공하여 짧고 간결하다
XML의 방식은 소스코드를 건드리거나 재 컴파일 하지않고 구성요소를 연결 할 수 있다
Spring은 두 스타일을 다 수용하고 있으니, 잘 알아서 선택하라고 한다. 쩰 어려운 답변인듯ㅎㅎ..
곧..? 아마도(?) 다루겠지만 Java-based Container Configuration 에서 좀더 자세히 해당 옵션을 살펴봐야겠다
https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-java
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
XML 설정에 대한 대안은 구성 요소를 연결하기 위해 XML 선언 대신 바이트 코드 메타데이터에 의존하는 주석 기반 구성으로 제공된다.
Bean 연결을 설명하기 위해 XML을 사용하는 대신 개발자는 관련 클래스, 메서드 또는 필드 선언에 대한 주석을 사용하여 구성 요소 클래스 자체로 구성을 이동한다.
예시: The AutowiredAnnotationBeanPostProcessor에서 언급했듯이 주석과 함께 BeanPostProcessor를 사용하는 것은 Spring IoC 컨테이너를 확장하는 일반적인 방법이다.
예를 들어 @Autowired 주석은 Autowiring Collaborators에 설명된 것과 동일한 기능을 제공하지만 더 세분화된 제어와 더 넓은 적용 가능성을 제공한다.
또한 Spring은 @PostConstruct 및 @PreDestroy와 같은 JSR-250 주석에 대한 지원과 @Inject 및 @Named와 같은 jakarta.inject 패키지에 포함된 JSR-330(Java용 의존성 주입) 주석에 대한 지원을 제공한다.
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
** 애노테이션 주입은 XML 주입 전에 수행된다. XML 구성은 두 접근 방식을 통해 연결된 속성에 대해 주석을 재정의한다
PostProcessor 을 통해 개별 빈 정의로 등록할 수 있지만 XML 기반 Spring 구성에 다음 태그를 포함하여 암시적으로 등록할 수 있다
(context namesapce<<)
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
</beans>
<context:annotation-config/> only looks for annotations on beans in the same application context in which it is defined. This means that, if you put <context:annotation-config/> in a WebApplicationContext for a DispatcherServlet, it only checks for @Autowired beans in your controllers, and not your services. See The DispatcherServlet for more information.
1.9.1. Using @Autowired
JSR 330의 @Inject 주석은 이 섹션에 포함된 예제에서 Spring의 @Autowired 주석 대신 사용할 수 있다
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
You can apply the @Autowired annotation to constructors, as the following example shows:
public class MovieRecommender {
private final CustomerPreferenceDao customerPreferenceDao;
@Autowired
public MovieRecommender(CustomerPreferenceDao customerPreferenceDao) {
this.customerPreferenceDao = customerPreferenceDao;
}
// ...
}
Spring Framework 4.3부터 bean이 시작할 생성자를 하나만 정의하는 경우 이러한 생성자에 대한 @Autowired 주석을 달지 않아도 된다. 그러나 여러 생성자를 사용할 수 있고 기본/기본 생성자가 없는 경우 컨테이너에 사용할 생성자를 지시하기 위해 적어도 하나의 생성자에 @Autowired 주석을 달아줘야한다.
@Autowired annotation to traditional setter methods
public class SimpleMovieLister {
private MovieFinder movieFinder;
@Autowired
public void setMovieFinder(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
// ...
}
임의의 이름과 여러 인수 메소드에도 적용 가능하다
public class MovieRecommender {
private MovieCatalog movieCatalog;
private CustomerPreferenceDao customerPreferenceDao;
@Autowired
public void prepare(MovieCatalog movieCatalog,
CustomerPreferenceDao customerPreferenceDao) {
this.movieCatalog = movieCatalog;
this.customerPreferenceDao = customerPreferenceDao;
}
// ...
}
필드에도 적용할 수 있고, constructor와 같이 사용할 수 있다
You can apply @Autowired to fields as well and even mix it with constructors
public class MovieRecommender {
private final CustomerPreferenceDao customerPreferenceDao;
@Autowired
private MovieCatalog movieCatalog;
@Autowired
public MovieRecommender(CustomerPreferenceDao customerPreferenceDao) {
this.customerPreferenceDao = customerPreferenceDao;
}
// ...
}
** @Autowired 애노테이션 주입 지점에 사용하는 type으로 일관되게 선언되는지 체크해볼 것
불일치하면 runtime 오류가 날 수 있다
클래스 경로 스캔을 통해 찾은 XML 정의 빈 또는 구성 요소 클래스의 경우 컨테이너는 일반적으로 구체적인 유형을 미리 알고 있다.
그러나 @Bean 팩토리 메소드의 경우 선언된 리턴 유형이 충분히 표현되는지 확인해야 한다.
여러 인터페이스를 구현하는 구성 요소 또는 구현 유형에 의해 잠재적으로 참조되는 구성 요소의 경우 팩토리 메소드에서 가장 구체적인 반환 유형을 선언하는 것이 좋다(최소한 bean을 참조하는 삽입 지점에서 요구하는 만큼 구체적이게).
배열 필드 또는 메소드에도 추가 가능하다
You can also instruct Spring to provide all beans of a particular type from the ApplicationContext by adding the @Autowired annotation to a field or method that expects an array of that type, as the following example shows:
public class MovieRecommender {
@Autowired
private MovieCatalog[] movieCatalogs;
// ...
}
public class MovieRecommender {
private Set<MovieCatalog> movieCatalogs;
@Autowired
public void setMovieCatalogs(Set<MovieCatalog> movieCatalogs) {
this.movieCatalogs = movieCatalogs;
}
// ...
}
target bean 의 순서를 정렬하려고 하는 경우 org.springframework.core.Ordered 인터페이스를 구현하거나 배열 또는 목록의 항목을 특정 순서로 정렬하려는 경우 @Order 또는 표준 @Priority 애노테이션을 사용할 수있다.
만약 따로 선언이 없을 경우에는 container에서 definition 등록 순서에 따른다
잠재적으로 동일한 빈 클래스를 사용하는 여러 definition 이 있을 경우에 bean definition에 대해 대상 class 수준 및 @Bean method에서 @Order 주석을 선언해줄 수 있다
@Order 값은 주입포인트의 우선 순위에 영향을 미칠 수 있으나, 종속관계 및 @DependsOn 선언에 의해 직접 결정되는 Singleton 시작 순서에는 영향을 미치지 않는다
표준 jakarta.annotation.Priority 어노테이션은 메소드에서 선언될 수 없기 때문에 @Bean 레벨에서 사용할 수 없다.
의미 체계는 각 유형에 대한 단일 빈에서 @Primary와 함께 @Order 값을 통해 모델링할 수 있다
Even typed Map instances can be autowired as long as the expected key type is String. The map values contain all beans of the expected type, and the keys contain the corresponding bean names, as the following example shows:
public class MovieRecommender {
private Map<String, MovieCatalog> movieCatalogs;
@Autowired
public void setMovieCatalogs(Map<String, MovieCatalog> movieCatalogs) {
this.movieCatalogs = movieCatalogs;
}
// ...
}
기본적으로 주어진 injection point에서 일치하는 bean을 사용할 수 없으면 autowiring이 실패한다.
By default, autowiring fails when no matching candidate beans are available for a given injection point. In the case of a declared array, collection, or map, at least one matching element is expected.
이때 required 를 사용하여 주입 지점을 필요하지 않다고 표시하여 건너띌 수 있다.
The default behavior is to treat annotated methods and fields as indicating required dependencies. You can change this behavior as demonstrated in the following example, enabling the framework to skip a non-satisfiable injection point through marking it as non-required (i.e., by setting the required attribute in @Autowired to false):
public class SimpleMovieLister {
private MovieFinder movieFinder;
@Autowired(required = false)
public void setMovieFinder(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
// ...
}
** 필요하지않은 메서드는 종속성을 사용할 수 없는 경우 호출되지않는다. 이 경우 필수 필드가 아닌 필드는 기본값 그대로 둔다.
required 를 false로 설정해주면 자동 연결 목적을 위한 선택 사항 속성임을 알려주고, 자동연결이 안될 경우에 무시할 수 있다.
이러면 선택적으로 재정의할 수 있는 기본값을 할당할 수 있다
주입된 생성자와 팩토리 메서드 인수는 @Autowired의 필수 속성이 잠재적으로 여러 생성자를 처리할 수 있는 Spring의 생성자 해결 알고리즘으로 인해 다소 다른 의미를 갖기 때문에 특별한 경우이다.
생성자 및 팩토리 메서드 인수는 기본적으로 효과적으로 필요하지만 일치하는 빈이 없는 경우 빈 인스턴스로 확인되는 다중 요소 주입 지점(배열, 컬렉션, 맵)과 같은 단일 생성자 시나리오의 몇 가지 특수 규칙이 있다. 이를 통해 모든 종속성을 고유한 다중 인수 생성자에서 선언할 수 있는 공통 구현 패턴이 허용된다.
예를 들어 @Autowired 는 주석 없이 단일 공용 생성자로 선언된다.
주어진 bean 클래스의 하나의 생성자만이 true로 설정된 필수 속성으로 @Autowired를 선언할 수 있으며 이는 생성자가 Spring bean으로 사용될 때 autowired임을 나타낸다.
결과적으로 필수 속성이 기본값인 true로 남아 있으면 단일 생성자만 @Autowired로 주석을 달 수 있다.
여러 생성자가 주석을 선언하는 경우 autowiring 후보로 간주되기 위해 모두 required=false를 선언해야 한다(XML의 autowire=constructor 와 비슷함).
Spring 컨테이너에서 일치하는 bean으로 만족할 수 있는 가장 많은 수의 종속성을 가진 생성자가 선택된다.
어떤 후보도 만족할 수 없으면 기본/기본 생성자(있는 경우)가 사용된다.
마찬가지로 클래스가 여러 생성자를 선언하지만 그 중 어느 것도 @Autowired로 주석이 지정되지 않은 경우 기본/기본 생성자(있는 경우)가 사용된다.
클래스가 시작할 단일 생성자만 선언하는 경우 주석이 지정되지 않은 경우에도 항상 사용된다.
주석이 달린 생성자는 공개일 필요가 없다.
Alternatively, you can express the non-required nature of a particular dependency through Java 8’s java.util.Optional, as the following example shows:
Optinal 특성으로 표현할 수 있다
public class SimpleMovieLister {
@Autowired
public void setMovieFinder(Optional<MovieFinder> movieFinder) {
...
}
}
As of Spring Framework 5.0, you can also use a @Nullable annotation (of any kind in any package — for example, javax.annotation.Nullable from JSR-305) or just leverage Kotlin built-in null-safety support:
public class SimpleMovieLister {
@Autowired
public void setMovieFinder(@Nullable MovieFinder movieFinder) {
...
}
}
public class MovieRecommender {
@Autowired
private ApplicationContext context;
public MovieRecommender() {
}
// ...
}
@Autowired, @Inject, @Value 및 @Resource 주석은 Spring BeanPostProcessor 구현에 의해 처리된다.
이는 자신의 BeanPostProcessor 또는 BeanFactoryPostProcessor 유형(있는 경우) 내에서 이러한 주석을 적용할 수 없다는 뜻이다. 이러한 유형은 XML 또는 Spring @Bean 메소드를 사용하여 명시적으로 '연결'되어야 한다.
1.9.2. Fine-tuning Annotation-based Autowiring with @Primary
type 별 autowiring은 여러 후보가 이어질 수 있어 더 많은 selection process 를 control해야할 경우가 많다
이럴때 Spring @Primary 애노테이션을 사용하면 된다
@Primary는 여러 bean이 단일 값 종속성에 autowiring될 후보일 때 특정 bean에 우선권을 부여해야함을 알린다
후보 중에 정확히 하나의 기본 bean이 있다면 autowired의 값이 된다
Consider the following configuration that defines firstMovieCatalog as the primary MovieCatalog
@Configuration
public class MovieConfiguration {
@Bean
@Primary
public MovieCatalog firstMovieCatalog() { ... }
@Bean
public MovieCatalog secondMovieCatalog() { ... }
// ...
}
MovieRecommender는 firstMovieCatelog와 연결되게 된다
public class MovieRecommender {
@Autowired
private MovieCatalog movieCatalog;
// ...
}
The corresponding bean definitions follow:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
<bean class="example.SimpleMovieCatalog" primary="true">
<!-- inject any dependencies required by this bean -->
</bean>
<bean class="example.SimpleMovieCatalog">
<!-- inject any dependencies required by this bean -->
</bean>
<bean id="movieRecommender" class="example.MovieRecommender"/>
</beans>