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.10.5. Defining Bean Metadata within Components ~ 1.10.9. Generating an Index of Candidate Components
1.10.5. Defining Bean Metadata within Components
Spring Component는 bean definition metadata를 컨테이너에 제공할 수 있다.
@Configuration 애노테이션을 붙인 클래스 내에서 정의하던 bean metadata를 @Bean에서 사용해도 동일한 수행이 가능하다
@Component
public class FactoryMethodComponent {
@Bean
@Qualifier("public")
public TestBean publicInstance() {
return new TestBean("publicInstance");
}
public void doWork() {
// Component method implementation omitted
}
}
위의 클래스는 doWork() 메소드에 애플리케이션 별 코드가 있는 구성이다. 그러나 publicInstance()를 참조하는 factory method가 있기 때문에 bean definition에도 적용된다. @Bean 애노테이션은 factory meethod와 @Qualifier 애노테이션을 퉁한 qualifier value와 같은 기타 bean definition 속성을 식별한다.
지정할 수 있는 다른 메서드 수준 주석은 @Scope, @Lazy 및 사용자 지정 qualifier 이 있다.
component initialization 역할 외에도 @Autowired 또는 @Inject로 표시된 주입 지점에 @Lazy 주석을 배치할 수도 있다.
이 컨텍스트에서 lazy-resolution proxy의 injection으로 이어진다. 그러나 이 프록시 접근 방식은 다소 제한적이다.
복잡한 지연 상호 작용의 경우, 특히 optional dependencies과 함께 ObjectProvider<MyTargetBean>을 대신 사용하는 것이 좋다
@Bean 메소드의 autowired에 대한 추가 지원과 함께 앞에서 설명한 것처럼 autowired fields 및 method가 지원된다.
@Component
public class FactoryMethodComponent {
private static int i;
@Bean
@Qualifier("public")
public TestBean publicInstance() {
return new TestBean("publicInstance");
}
// use of a custom qualifier and autowiring of method parameters
@Bean
protected TestBean protectedInstance(
@Qualifier("public") TestBean spouse,
@Value("#{privateInstance.age}") String country) {
TestBean tb = new TestBean("protectedInstance", 1);
tb.setSpouse(spouse);
tb.setCountry(country);
return tb;
}
@Bean
private TestBean privateInstance() {
return new TestBean("privateInstance", i++);
}
@Bean
@RequestScope
public TestBean requestScopedInstance() {
return new TestBean("requestScopedInstance", 3);
}
}
위의 예제는 String method parameter "country"를 privateInstance라는 다른 bean의 age 속성 값에 autowired 시킨다
SpEL 요소의 #{<expression>} 표기법을 이용하여 속성값을 정의했으며
@Value 애노테이션의 경우 해당 텍스트 해석 시 bean 이름을 찾도록 미리 구성시켜준다
Spring Framework 4.3부터는 현재 빈 생성을 트리거하는 요청 주입 지점에 액세스하기 위해 InjectionPoint 유형(또는 더 구체적인 하위 클래스: DependencyDescriptor)의 팩토리 메서드 매개변수를 선언할 수도 있다.
*** 이는 기존 인스턴스 주입이 아닌 실제 빈 인스턴스 생성에만 적용된다.
결과적으로 이 기능은 프로토타입 범위의 bean에 가장 적합하다.
다른 범위의 경우 팩토리 메서드는 주어진 범위에서 새 빈 인스턴스 생성을 트리거한 injection point만 보게된다(예: Lazy Singleton 빈 생성을 트리거한 종속성).
이러한 시나리오에서는 semantic care와 함께 제공된 injection point 메타데이터를 사용할 수 있다
InjectionPoint 사용하기
@Component
public class FactoryMethodComponent {
@Bean @Scope("prototype")
public TestBean prototypeInstance(InjectionPoint injectionPoint) {
return new TestBean("prototypeInstance for " + injectionPoint.getMember());
}
}
일반 Spring 컴포넌트의 @Bean 메소드는 Spring @Configuration 클래스 내부의 해당 메소드와 다르게 처리된다.
차이점은 메소드 및 필드의 호출을 가로채기 위해 @Component 클래스가 CGLIB로 향상되지 않는다는 것이다.
- CGLIB 프록싱은 @Configuration 클래스의 @Bean 메소드 내에서 메소드 또는 필드를 호출하여 협업 객체에 대한 빈 메타데이터 참조를 생성하는 수단이다. 이러한 메서드는 일반적인 Java 의미론으로 호출되지 않고 @Bean 메서드에 대한 프로그래밍 호출을 통해 다른 빈을 참조할 때에도 일반적인 수명 주기 관리 및 Spring 빈 프록시를 제공하기 위해 컨테이너를 통과한다.
대조적으로, 일반 @Component 클래스 내의 @Bean 메소드에서 메소드 또는 필드를 호출하는 것은 특별한 CGLIB 처리 또는 적용되는 다른 제약 조건이 없는 표준 Java sementic 을 갖는다.
@Bean 메소드를 정적으로 선언하여 포함하는 구성 클래스를 인스턴스로 생성하지 않고도 호출할 수 있다.
이는 post-processor 빈(예: BeanFactoryPostProcessor 또는 BeanPostProcessor type)을 정의할 때 이러한 빈이 컨테이너 lifecycle 초기에 초기화되고 해당 지점에서 구성의 다른 부분을 트리거하지 않도록 해야 하기 때문에 특히 의미가 있다.
정적 @Bean 메소드에 대한 호출은 기술적 한계로 인해 @Configuration 클래스(이 섹션의 앞부분에서 설명한 대로) 내에서도 컨테이너에 의해 차단되지 않는니다.
CGLIB 서브클래싱은 비정적 메소드만 재정의할 수 있다. 결과적으로 다른 @Bean 메소드에 대한 직접 호출은 표준 Java 시맨틱을 가지므로 독립 인스턴스가 팩토리 메소드 자체에서 직접 리턴된다.
@Bean 메소드의 Java 언어 가시성은 Spring 컨테이너의 결과 bean 정의에 즉각적인 영향을 미치지 않는다.
@Configuration 클래스가 아닌 클래스와 어디에서나 정적 메서드에 적합하다고 생각되는 대로 팩토리 메서드를 자유롭게 선언할 수 있으나 @Configuration 클래스의 일반 @Bean 메소드는 재정의 가능해야 한다.
즉, private or final으로 선언되어서는 안된다. @Bean 메서드는 주어진 구성 요소 또는 구성 클래스의 기본 클래스와 구성 요소 또는 구성 클래스에 의해 구현된 인터페이스에서 선언된 Java 8 기본 메서드에서도 발견된다.
이를 통해 Spring 4.2부터 Java 8 기본 메서드를 통해 다중 상속이 가능하여 복잡한 구성 배열을 구성하는 데 많은 유연성이 허용된다.
마지막으로 단일 클래스는 런타임에 사용 가능한 종속성에 따라 사용할 여러 팩터리 메서드의 배열로 동일한 빈에 대해 여러 @Bean 메서드를 보유할 수 있다. 이것은 다른 구성 시나리오에서 "greediest" constructor 또는 팩토리 메서드를 선택하는 것과 동일한 알고리즘이다. 컨테이너가 여러 @Autowired 생성자 중에서 선택하는 방식과 유사하게 만족할 수 있는 종속성이 가장 많은 변형이 구성 시간에 선택된다.
1.10.6. Naming Autodetected Components
구성 요소가 검색 프로세스의 일부로 자동 감지되면 해당 스캐너에 알려진 BeanNameGenerator 전략에 의해 빈 이름이 생성된다.
기본적으로 이름 값을 포함하는 모든 Spring 스테레오타입 주석(@Component, @Repository, @Service 및 @Controller)은 해당 빈 정의에 해당 이름을 제공한다. 이러한 주석에 이름 값이 없거나 다른 감지된 구성 요소(예: 사용자 정의 필터에 의해 발견된 구성 요소)에 대한 경우 기본 빈 이름 생성기는 대문자가 아닌 정규화되지 않은 클래스 이름을 반환한다.
예를 들어 다음 구성 요소 클래스가 감지된 경우 이름은 myMovieLister 및 movieFinderImpl이 된다.
@Service("myMovieLister")
public class SimpleMovieLister {
// ...
}
@Repository
public class MovieFinderImpl implements MovieFinder {
// ...
}
기본 bean name autodetected components 말고 내가 직접 지정하고 싶다면
BeanNameGenerator interface를 구현하여 인수가 없는 기본 constructor를 포함해야한다
다음 애노테이션 및 Bean definition에 표시된 완전한 클래스 이름을 제공하면 된다
* 동일한 규정되지 않은 클래스 이름(즉, 동일한 이름을 갖지만 다른 패키지에 상주하는 클래스)을 갖는 여러 자동 감지 구성 요소로 인해 이름 충돌이 발생하는 경우 기본적으로 완전한 클래스 이름으로 설정되는 BeanNameGenerator를 구성해야한다.
생성된 빈 이름. Spring Framework 5.2.3부터는 org.springframework.context.annotation 패키지에 있는 FullyQualifiedAnnotationBeanNameGenerator를 이러한 목적으로 사용할 수 있다
@Configuration
@ComponentScan(basePackages = "org.example", nameGenerator = MyNameGenerator.class)
public class AppConfig {
// ...
}
<beans>
<context:component-scan base-package="org.example"
name-generator="org.example.MyNameGenerator" />
</beans>
일반적으로 다른 constructor 요소가 해당 이름을 명시적으로 참조할 수 있을 때마다 주석으로 이름을 지정하는 것이 좋다 auto-generated names을 사용할 경우에는 은 컨테이너가 responsible 될때마다가 적절하다
1.10.7. Providing a Scope for Autodetected Components
일반적으로 Spring 관리 구성 요소와 마찬가지로 자동 감지된 구성 요소의 기본 범위와 가장 일반적인 범위는 싱글톤이다. 그러나 @Scope 애노테이션으로 으로 지정할 수 있는 다른 범위가 필요한 경우도 있다. 주석 내에서 Scope의 이름을 제공할 수 있다.
@Scope("prototype")
@Repository
public class MovieFinderImpl implements MovieFinder {
// ...
}
** @Scope 애노테이션은 구체적인 빈 클래스(주석이 있는 구성 요소의 경우) 또는 팩토리 메서드(@Bean 메서드의 경우)에서만 검사된다. XML bean 정의와 달리 bean definition 상속에 대한 개념이 없으며 클래스 수준의 상속 계층은 메타데이터 목적는 관련이 없다.
Spring 컨텍스트의 "request" 또는 "session"과 같은 웹 관련 범위에 대한 자세한 내용은 Request, Session, Application, and WebSocket Scope를 참조하면 된다. 해당 Scope에 대한 미리 빌드된 주석과 마찬가지로 @Scope("prototype")을 이용하여 Spring의 meta-annotated 접근 방식을 사용하여 자신만의 범위 지정 주석을 작성할 수도 있다.
애노테이션 기반 접근 방식에 의존하지 않고s scope resolution을 위한 custom strategy 를 제공하려면 ScopeMetadataResolver 인터페이스를 구현할 수 있다. 인수가 없는 기본 constructor를 포함해야 한다. 그 다음 애노테이션과 빈 정의에 대한 다음 예제가 보여주는 것처럼 스캐너를 구성할 때 완전한 클래스 이름을 제공할 수 있다.
@Configuration
@ComponentScan(basePackages = "org.example", scopeResolver = MyScopeResolver.class)
public class AppConfig {
// ...
}
<beans>
<context:component-scan base-package="org.example" scope-resolver="org.example.MyScopeResolver"/>
</beans>
Singleton이 아닌 특정 범위에서 사용하려면 해당 범위가 지정된 개체에 대한 proxy를 생성해야할 수 있다
https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-factory-scopes-other-injection이를 위해서는 component-scan 요소에서 scoped-proxy 속성을 사용할 수 있다
>> The three possible values are: no, interfaces, and targetClass.
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
@Configuration
@ComponentScan(basePackages = "org.example", scopedProxy = ScopedProxyMode.INTERFACES)
public class AppConfig {
// ...
}
<beans>
<context:component-scan base-package="org.example" scoped-proxy="interfaces"/>
</beans>
1.10.8. Providing Qualifier Metadata with Annotations
https://delightpip.tistory.com/120 1.9.3. Fine-tuning Annotation-based Autowiring with Qualifiers 참고
다음 예제에서는 @Qualifier 애노테이션 및 Custom qualifier annotation을 이용하여 autowire 될 후보들을 확인할 때 세분화된 control을 제공하는 방법이다.
@Component
@Qualifier("Action")
public class ActionMovieCatalog implements MovieCatalog {
// ...
}
@Component
@Genre("Action")
public class ActionMovieCatalog implements MovieCatalog {
// ...
}
@Component
@Offline
public class CachingMovieCatalog implements MovieCatalog {
// ...
}
1.10.9. Generating an Index of Candidate Components
While classpath scanning 는 매우 빠르기에 컴파일 시간에 static 후보 리스트를 생성하여 대형 Application 의 시작 성능을 향상시킬 수 있다. 이 모드에서는 구성 요소 검색 대상인 모든 모듈이 이 메커니즘을 사용해야한다
+
특정 package의 후보를 스캔하기 위해 컨텍스트를 요청하려면 기존 @ComponentScan또는 지시문을 변경하지 않고 유지해야한다. <context:component-scan/>에서 ApplicationContext이러한 인덱스를 감지하면 클래스 경로를 스캔하지 않고 자동으로 사용한다.
To generate the index, add an additional dependency to each module that contains components that are targets for component scan directives. The following example shows how to do so with Maven:
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-indexer</artifactId>
<version>6.0.6</version>
<optional>true</optional>
</dependency>
</dependencies>
With Gradle 4.5 and earlier, the dependency should be declared in the compileOnly configuration, as shown in the following example:
dependencies {
compileOnly "org.springframework:spring-context-indexer:6.0.6"
}
With Gradle 4.6 and later, the dependency should be declared in the annotationProcessor configuration, as shown in the following example:
dependencies {
annotationProcessor "org.springframework:spring-context-indexer:6.0.6"
}
The spring-context-indexer artifact generates a META-INF/spring.components file that is included in the jar file.
IDE에서 이 모드로 작업할 때 후보 구성 요소가 update 중에 index의 최싱 상태를 확인하려면 spring-context-indexer 를 annotation processor로 등록해야한다
클래스 경로에서 META-INF/spring.components 파일이 발견되면 색인이 자동으로 활성화된다.
인덱스가 일부 라이브러리(또는 사용 사례)에 대해 부분적으로 사용 가능하지만 전체 애플리케이션에 대해 빌드할 수 없는 경우 spring.index.ignore를 설정하여 일반 클래스 경로 배열로 폴백할 수 있다(인덱스가 전혀 없는 것처럼).
JVM 시스템 속성으로 또는 SpringProperties 메커니즘을 통해 true로 설정한다.
'Web > spring' 카테고리의 다른 글
[Spring Batch] The Domain Language of Batch - (1) Job (0) | 2023.03.11 |
---|---|
[Spring Batch] Architecture (0) | 2023.03.11 |
[Spring Framework core] 1.10. Classpath Scanning and Managed Components (1) (0) | 2023.03.10 |
[String Batch] FlatFileItemReader (0) | 2023.03.09 |
[Spring Framework core] 1.9. Annotation-based Container Configuration (3) (0) | 2023.03.09 |