스프링 주석을 사용하여 동일한 클래스의 여러 콩 인스턴스화
XML로 구성된 Springbean 팩토리를 사용하면 동일한 클래스의 여러 인스턴스를 다른 매개 변수로 쉽게 인스턴스화할 수 있습니다.주석을 사용하여 동일한 작업을 수행하려면 어떻게 해야 합니까?저는 다음과 같은 것을 원합니다.
@Component(firstName="joe", lastName="smith")
@Component(firstName="mary", lastName="Williams")
public class Person { /* blah blah */ }
그건 불가능해요.중복된 예외가 발생합니다.
또한 구현 클래스에서 이와 같은 구성 데이터를 사용하는 것은 최적이 아닙니다.
주석을 사용하려면 Java 구성을 사용하여 클래스를 구성할 수 있습니다.
@Configuration
public class PersonConfig {
@Bean
public Person personOne() {
return new Person("Joe", "Smith");
}
@Bean
public Person personTwo() {
return new Person("Mary", "Williams");
}
}
예, 사용자 지정 BeanFactory PostProcessor 구현의 도움을 받아 이 작업을 수행할 수 있습니다.
여기 간단한 예가 있습니다.
두 가지 성분이 있다고 가정합니다.하나는 다른 하나에 대한 의존입니다.
첫 번째 구성 요소:
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;
public class MyFirstComponent implements InitializingBean{
private MySecondComponent asd;
private MySecondComponent qwe;
public void afterPropertiesSet() throws Exception {
Assert.notNull(asd);
Assert.notNull(qwe);
}
public void setAsd(MySecondComponent asd) {
this.asd = asd;
}
public void setQwe(MySecondComponent qwe) {
this.qwe = qwe;
}
}
보시다시피 이 구성 요소에는 특별한 것이 없습니다.MySecondComponent의 두 가지 다른 인스턴스에 종속되어 있습니다.
두 번째 구성 요소:
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.annotation.Qualifier;
@Qualifier(value = "qwe, asd")
public class MySecondComponent implements FactoryBean {
public Object getObject() throws Exception {
return new MySecondComponent();
}
public Class getObjectType() {
return MySecondComponent.class;
}
public boolean isSingleton() {
return true;
}
}
좀 더 까다롭네요.여기에 설명할 두 가지가 있습니다.첫 번째 - @Qualifier - MySecondComponent beans의 이름이 포함된 주석.이것은 표준적인 것이지만, 당신은 당신 자신의 것을 자유롭게 구현할 수 있습니다.그 이유는 나중에 알게 될 것입니다.
두 번째로 언급할 것은 팩토리빈 구현입니다.이 인터페이스를 구현하는 경우 다른 인스턴스를 생성합니다.이 경우 MySecondComponent 유형으로 인스턴스를 만듭니다.
가장 까다로운 부분은 BeanFactory PostProcessor 구현입니다.
import java.util.Map;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
Map<String, Object> map = configurableListableBeanFactory.getBeansWithAnnotation(Qualifier.class);
for(Map.Entry<String,Object> entry : map.entrySet()){
createInstances(configurableListableBeanFactory, entry.getKey(), entry.getValue());
}
}
private void createInstances(
ConfigurableListableBeanFactory configurableListableBeanFactory,
String beanName,
Object bean){
Qualifier qualifier = bean.getClass().getAnnotation(Qualifier.class);
for(String name : extractNames(qualifier)){
Object newBean = configurableListableBeanFactory.getBean(beanName);
configurableListableBeanFactory.registerSingleton(name.trim(), newBean);
}
}
private String[] extractNames(Qualifier qualifier){
return qualifier.value().split(",");
}
}
그것은 무엇을 합니까?@Qualifier로 주석이 달린 모든 빈을 통과하고 주석에서 이름을 추출한 다음 지정된 이름을 사용하여 이 유형의 빈을 수동으로 만듭니다.
스프링 구성은 다음과 같습니다.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean class="MyBeanFactoryPostProcessor"/>
<bean class="MySecondComponent"/>
<bean name="test" class="MyFirstComponent">
<property name="asd" ref="asd"/>
<property name="qwe" ref="qwe"/>
</bean>
</beans>
여기서 마지막으로 주목해야 할 것은 실행할 수는 있지만 반드시 실행해야 하는 경우가 아니라면 실행해서는 안 된다는 것입니다. 왜냐하면 이것은 실제로 자연스러운 구성 방법이 아니기 때문입니다.클래스 인스턴스가 둘 이상인 경우 XML 구성을 유지하는 것이 좋습니다.
저는 단지 비슷한 사건을 해결해야만 했습니다.클래스를 재정의할 수 있는 경우 이 방법이 사용될 수 있습니다.
// This is not a @Component
public class Person {
}
@Component
public PersonOne extends Person {
public PersonOne() {
super("Joe", "Smith");
}
}
@Component
public PersonTwo extends Person {
public PersonTwo() {
super("Mary","Williams");
}
}
그런 다음 특정 인스턴스를 자동으로 연결해야 할 때마다 Person1 또는 Person2를 사용하고, 다른 모든 경우에는 Person을 사용합니다.
왁스의 답변에서 영감을 얻은 이 구현은 생성된 싱글톤이 아닌 정의를 추가하면 다른 사후 처리를 건너뛸 수 있고 더 안전할 수 있습니다.
public interface MultiBeanFactory<T> { // N.B. should not implement FactoryBean
T getObject(String name) throws Exception;
Class<?> getObjectType();
Collection<String> getNames();
}
public class MultiBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
Map<String, MultiBeanFactory> factories = beanFactory.getBeansOfType(MultiBeanFactory.class);
for (Map.Entry<String, MultiBeanFactory> entry : factories.entrySet()) {
MultiBeanFactory factoryBean = entry.getValue();
for (String name : factoryBean.getNames()) {
BeanDefinition definition = BeanDefinitionBuilder
.genericBeanDefinition(factoryBean.getObjectType())
.setScope(BeanDefinition.SCOPE_SINGLETON)
.setFactoryMethod("getObject")
.addConstructorArgValue(name)
.getBeanDefinition();
definition.setFactoryBeanName(entry.getKey());
registry.registerBeanDefinition(entry.getKey() + "_" + name, definition);
}
}
}
}
@Configuration
public class Config {
@Bean
public static MultiBeanFactoryPostProcessor() {
return new MultiBeanFactoryPostProcessor();
}
@Bean
public MultiBeanFactory<Person> personFactory() {
return new MultiBeanFactory<Person>() {
public Person getObject(String name) throws Exception {
// ...
}
public Class<?> getObjectType() {
return Person.class;
}
public Collection<String> getNames() {
return Arrays.asList("Joe Smith", "Mary Williams");
}
};
}
}
콩의 이름은 여전히 왁스의 이름과 같이 어디에서나 나올 수 있습니다.@Qualifier
예문.콩 정의에는 공장 자체에서 상속할 수 있는 기능을 포함하여 다양한 속성이 있습니다.
@espen 답변을 계속하고, 콩에 한정자를 주입하고 외부 값을 사용하여 다르게 구성합니다.
public class Person{
@Configuration
public static class PersonConfig{
@Bean
//@Qualifier("personOne") - doesn't work - bean qualifier is method name
public Person personOne() {
return new Person("Joe", "Smith");
}
@Bean
//@Qualifier("personTwo") - doesn't work - bean qualifier is method name
public Person personTwo(@Value("${myapp.second.lastName}") String lastName) {
return new Person("Mary", lastName);
}
}
/* blah blah */
}
@Component
public class SomePersonReference{
@Autowired
@Qualifier("personTwo")
Person marry;
}
스프링 컨텍스트에서 새로 생성된 개체, 콩 또는 속성을 주입해야 하는 경우 스프링 컨텍스트에서 생성된 콩을 주입하여 에스펜 답변을 확장한 코드의 다음 섹션을 볼 수 있습니다.
@Configuration
public class PersonConfig {
@Autowired
private OtherBean other;
@Bean
public Person personOne() {
return new Person("Joe", "Smith", other);
}
}
가능한 모든 시나리오에 대해 이 기사를 살펴보십시오.
언급URL : https://stackoverflow.com/questions/2902335/instantiating-multiple-beans-of-the-same-class-with-spring-annotations
'programing' 카테고리의 다른 글
HTML 테이블과 함께 정렬 가능한 jQuery UI 사용 (0) | 2023.08.27 |
---|---|
테이블 내부에만 테두리를 적용하려면 어떻게 해야 합니까? (0) | 2023.08.27 |
JavaScript: 문자열의 마지막 텍스트 바꾸기 (0) | 2023.08.27 |
텍스트 영역에 대한 val() vs. text() (0) | 2023.08.27 |
왼쪽/오른쪽 조인이 예상대로 null을 반환하지 않음 (0) | 2023.08.27 |