복붙노트

[SPRING] Spring 애플리케이션 컨텍스트에 사전 구성된 Bean 추가하기

SPRING

Spring 애플리케이션 컨텍스트에 사전 구성된 Bean 추가하기

다음 메소드를 구현하는 클래스를 작성 중입니다.

public void run(javax.sql.DataSource dataSource);

이 메서드 내에서 다음과 비슷한 구성 파일을 사용하여 Spring 응용 프로그램 컨텍스트를 구성하고자합니다.

<bean id="dataSource" abstract="true" />

<bean id="dao" class="my.Dao">
  <property name="dataSource" ref="dataSource" />
</bean>

"dataSource"bean이 환경 설정 파일에서 참조되는 곳이라면 Spring이 내 메소드에 전달 된 DataSource 객체를 사용하도록 강제 할 수 있습니까?

해결법

  1. ==============================

    1.나는 똑같은 상황에 처해 있었다. 아무도 내 솔루션을 제안하지 않았기 때문에 (그리고 제 솔루션이 더 우아하다고 생각합니다), 저는 그것을 미래 세대를 위해 여기에 추가 할 것입니다 :-)

    나는 똑같은 상황에 처해 있었다. 아무도 내 솔루션을 제안하지 않았기 때문에 (그리고 제 솔루션이 더 우아하다고 생각합니다), 저는 그것을 미래 세대를 위해 여기에 추가 할 것입니다 :-)

    솔루션은 두 단계로 구성됩니다.

    1 단계:

    //create parent BeanFactory
    DefaultListableBeanFactory parentBeanFactory = new DefaultListableBeanFactory();
    //register your pre-fabricated object in it
    parentBeanFactory.registerSingleton("dataSource", dataSource);
    //wrap BeanFactory inside ApplicationContext
    GenericApplicationContext parentContext = 
            new GenericApplicationContext(parentBeanFactory);
    parentContext.refresh(); //as suggested "itzgeoff", to overcome a warning about events
    

    2 단계:

    //create your "child" ApplicationContext that contains the beans from "beans.xml"
    //note that we are passing previously made parent ApplicationContext as parent
    ApplicationContext context = new ClassPathXmlApplicationContext(
            new String[] {"beans.xml"}, parentContext);
    
  2. ==============================

    2.두 개의 Spring 인터페이스가 필요한 것을 구현하는 데 사용될 수 있다는 것을 발견했습니다. BeanNameAware 인터페이스를 사용하면 Spring은 setBeanName (String) 메소드를 호출하여 애플리케이션 컨텍스트 내에서 오브젝트의 이름을 알릴 수있다. FactoryBean 인터페이스는 Spring에게 객체 자체를 사용하지 말고, getObject () 메소드가 호출 될 때 리턴 된 객체를 알려줍니다. 함께 모으면 다음과 같이됩니다.

    두 개의 Spring 인터페이스가 필요한 것을 구현하는 데 사용될 수 있다는 것을 발견했습니다. BeanNameAware 인터페이스를 사용하면 Spring은 setBeanName (String) 메소드를 호출하여 애플리케이션 컨텍스트 내에서 오브젝트의 이름을 알릴 수있다. FactoryBean 인터페이스는 Spring에게 객체 자체를 사용하지 말고, getObject () 메소드가 호출 될 때 리턴 된 객체를 알려줍니다. 함께 모으면 다음과 같이됩니다.

    public class PlaceholderBean implements BeanNameAware, FactoryBean {
    
        public static Map<String, Object> beansByName = new HashMap<String, Object>();
    
        private String beanName;
    
        @Override
        public void setBeanName(String beanName) {
            this.beanName = beanName;
        }
    
        @Override
        public Object getObject() {
            return beansByName.get(beanName);
        }
    
        @Override
        public Class<?> getObjectType() {
            return beansByName.get(beanName).getClass();
        }
    
        @Override
        public boolean isSingleton() {
            return true;
        }
    
    }
    

    이제 Bean 정의가 다음과 같이 축소되었습니다.

    <bean id="dataSource" class="PlaceholderBean" />
    

    자리 표시자는 응용 프로그램 컨텍스트를 만들기 전에 값을받습니다.

    public void run(DataSource externalDataSource) {
        PlaceholderBean.beansByName.put("dataSource", externalDataSource);
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        assert externalDataSource == context.getBean("dataSource");
    }
    

    상황이 성공적으로 작동하는 것 같습니다!

  3. ==============================

    3.두 번째 솔루션은 새로 고침 문제로 인해 예외가 발생합니다. 보다 우아한 방법은 컨텍스트에 개체를 추가 한 다음 xmlreader를 사용하여 xml 정의를로드하는 것입니다. 그러므로:

    두 번째 솔루션은 새로 고침 문제로 인해 예외가 발생합니다. 보다 우아한 방법은 컨텍스트에 개체를 추가 한 다음 xmlreader를 사용하여 xml 정의를로드하는 것입니다. 그러므로:

     ObjectToBeAddedDynamically objectInst = new ObjectToBeAddedDynamically();
      DefaultListableBeanFactory parentBeanFactory = new DefaultListableBeanFactory();  
      parentBeanFactory.registerSingleton("parameterObject", objectInst);
    
      GenericApplicationContext parentContext = new GenericApplicationContext(parentBeanFactory);
    
      XmlBeanDefinitionReader xmlReader = new XmlBeanDefinitionReader(parentContext);
       xmlReader.loadBeanDefinitions(new FileSystemResource("beandefinitions.xml"));
       parentContext.refresh();
    
       ObjectUsingDynamicallyAddedObject userObjectInst= (ObjectUsingDynamicallyAddedObject )parentContext.getBean("userObject");
    

        <?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 id="userObject" class="com.beanwiring.ObjectUsingDynamicallyAddedObject"
          >
          <constructor-arg ref="parameterObject" />
    
    </bean>
    
    </beans>
    

    완벽하게 작동합니다!

  4. ==============================

    4.포함 된 DataSource에 단순히 위임하는 DataSource에 대한 래퍼 클래스를 만들 수 있습니다.

    포함 된 DataSource에 단순히 위임하는 DataSource에 대한 래퍼 클래스를 만들 수 있습니다.

    public class DataSourceWrapper implements DataSource {
    
    DataSource dataSource;
    
    public void setDataSource(DataSource dataSource) {
        this.dataSource = dataSource;
    }
    
    @Override
    public Connection getConnection() throws SQLException {
        return dataSource.getConnection();
    }
    
    @Override
    public Connection getConnection(String username, String password)
            throws SQLException {
        return dataSource.getConnection(username, password);
    }
    //delegate to all the other DataSource methods
    }
    

    그런 다음 Spring 컨텍스트 파일에서 DataSourceWrapper를 선언하고 모든 빈에 연결합니다. 그런 다음 메서드에서 DataSourceWrapper에 대한 참조를 가져온 다음 래핑 된 DataSource를 메서드에 전달 된 것으로 설정합니다.

    이 모든 작업은로드 될 때 Spring 컨텍스트 파일에서 일어나는 일에 크게 의존합니다. Bean이 컨텍스트가로드 될 때 BeanFactoryPostProcessor를 작성해야하는 경우 BeanFactoryPostProcessor를 작성하여로드 할 때 Spring 컨텍스트 파일을 변경하는 대신 BeanFactoryPostProcessor를 작성해야 할 수도 있습니다 (로드가 끝나면 Lazy-init이이 문제를 해결할 수도 있음). ).

  5. ==============================

    5."new"를 호출하여 객체를 생성하면 Spring factory의 제어를받지 않습니다.

    "new"를 호출하여 객체를 생성하면 Spring factory의 제어를받지 않습니다.

    Spring이 DataSource를 run ()에 전달하는 대신 객체에 삽입하는 것이 어떻습니까?

  6. ==============================

    6.외부 XML 파일을 사용하여 파일 시스템 리소스로로드 한 다음 응용 프로그램 컨텍스트에 구성된 빈을 주입하는보다 우아한 방법이 있습니다. 그러므로:

    외부 XML 파일을 사용하여 파일 시스템 리소스로로드 한 다음 응용 프로그램 컨텍스트에 구성된 빈을 주입하는보다 우아한 방법이 있습니다. 그러므로:

    import org.springframework.beans.BeansException;
    import org.springframework.beans.factory.InitializingBean;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.beans.factory.support.BeanDefinitionRegistry;
    import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.ApplicationContextAware;
    import org.springframework.context.support.GenericApplicationContext;
    import org.springframework.core.annotation.Order;
    import org.springframework.core.io.FileSystemResource;
    import org.springframework.stereotype.Service;
    
    @Service
    @Order(-100)
    public class XmlBeanInitializationService implements ApplicationContextAware, InitializingBean {
    
        private ApplicationContext applicationContext;
    
        @Value("${xmlConfigFileLocation}")
        private String xmlConfigFileLocation;
    
        @Override
        public void afterPropertiesSet() throws Exception {
            XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader((BeanDefinitionRegistry)applicationContext);
            reader.loadBeanDefinitions(new FileSystemResource(xmlConfigFileLocation));
        }
    
        @Override
        public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
            this.applicationContext = applicationContext;
    
        }
    }
    

    여기서 $ {xmlConfigFileLocation}은 application.properties 파일에 지정된 속성으로 시스템의 파일 위치를 가리 킵니다.

    xmlConfigFileLocation="your-file-path-anywhere-in-your-system"
    

    xml 파일에는 다음 항목이 포함될 수 있습니다.

    <?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="com.yourpackage.YourBean1Class"></bean>
            <bean class="com.yourpackage.YourBean2Class"></bean>
            <bean class="com.yourpackage.YourBean3Class"></bean>
    
        </beans>
    

    따라서 애플리케이션이 스프링을 시작하면 클래스를로드하고 애플리케이션 컨텍스트에 Bean을로드한다.

    희망이 사람을 도움이됩니다.

  7. from https://stackoverflow.com/questions/496711/adding-a-pre-constructed-bean-to-a-spring-application-context by cc-by-sa and MIT license