복붙노트

[SPRING] Spring에서 런타임시 bean (prototype) 등록하기

SPRING

Spring에서 런타임시 bean (prototype) 등록하기

커뮤니티가 평가 한 것을 필요로합니다. 다음은 특정 유형의 인스턴스를 만드는 간단한 팩토리 인 코드 스 니펫입니다. 메소드는 컨텍스트에서 bean을 프로토 타입으로 등록하고 인스턴스를 리턴합니다. 런타임에 콩을 구성하는 것은 이번이 처음입니다. 친절하게 평가하고 피드백을 주시겠습니까? 미리 감사드립니다.

package au.com.flexcontacts.flexoperations;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConstructorArgumentValues;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.support.AbstractApplicationContext;

import au.com.flexcontacts.exceptions.SyncClassCreactionError;

/**
 * @author khushroo.mistry
 * Class purpose: Simple Factory to create an 
 * instance of SynchroniseContactsService and register it in the Spring IoC.
 */
public final class FLEXSyncFactory implements ApplicationContextAware {

    private static AbstractApplicationContext context;


    /**
     * @param username
     * @param password
     * @param syncType
     * @return the correct service class
     * @throws SyncClassCreactionError
     * The method registers the classes dynamically into the Spring IoC
     */
    public final SynchroniseContactsService createSyncService(String username, String password, SyncType syncType) throws SyncClassCreactionError {

        DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) context.getBeanFactory();

        try {

            //Register the bean in the IoC
            BeanDefinition bdb = new GenericBeanDefinition();
            bdb.setBeanClassName(syncType.getClassName());
            bdb.setScope("prototype");
            ConstructorArgumentValues constructor = bdb.getConstructorArgumentValues();
            constructor.addIndexedArgumentValue(0, username);
            constructor.addIndexedArgumentValue(1, password);
            beanFactory.registerBeanDefinition(syncType.getInstanceName(), bdb);

            //Return instance of bean
            return (SynchroniseContactsService) beanFactory.getBean(syncType.getInstanceName());
        } catch (Exception e) {
            e.printStackTrace();
            throw new SyncClassCreactionError("Error: Illegal Handler");
        }

    }

    public void setApplicationContext(ApplicationContext applicationContext)
    throws BeansException {
        context = (AbstractApplicationContext) applicationContext;

    }

}

FLEX Sync 팩토리가 IoC 컨테이너에서 싱글 톤으로 구성되었습니다. 새로운 동기화 관리자를 만들려면 다음을 수행하십시오.

flexSyncFactory.createSyncService(userName, password, SyncType.FULL);

나는 Spring 3.1을 사용하고있다. 귀중한 피드백을 검토하고 제공하십시오.

친절하게 생각해.

해결법

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

    1.이것은 전적으로 내 의견이며 전문적인 견해는 아닙니다.

    이것은 전적으로 내 의견이며 전문적인 견해는 아닙니다.

    Spring은 기존 Bean 정의를 수정하거나 새로운 Bean 정의를 추가 할 수있는 BeanFactoryPostProcessor와 Bean 인스턴스를 수정할 수있는 BeanFactoryPostProcessor (프록시 등을 둘러싼)를 사용하여 애플리케이션 컨텍스트의 사용자 정의 수정을위한 두 가지 메커니즘을 제공한다.

    Spring은 런타임시 bean 정의 나 bean 인스턴스를 동적으로 추가하는 다른 기본적인 방법을 제공하지 않지만, 기본 bean factory 인스턴스를 얻고 bean 정의를 추가하는 것이 한 가지 방법이다. 작동하지만 위험이 있습니다.

    목적이 Spring에 의해 자동으로 실행 된 bean을 생성하는 것이라면 @Configurable과 같은 것을 사용할 것입니다. 위의 위험이 수용 가능한 경우에도 접근 방식이 효과적입니다.

  2. ==============================

    2.이것은 나를 위해 일했다 : http://random-thoughts-vortex.blogspot.com/2009/03/create-dynamically-spring-beans.html

    이것은 나를 위해 일했다 : http://random-thoughts-vortex.blogspot.com/2009/03/create-dynamically-spring-beans.html

    ApplicationContextAware와 BeanFactoryPostProcessor 인터페이스를 구현할 전용 Spring 컨텍스트 bean 하나를 선언하자 :

      public class MyContextWrapper implements ApplicationContextAware,
                 BeanFactoryPostProcessor {
    
       private ApplicationContext appContext;
       private ConfigurableListableBeanFactory factory;
    
       public void postProcessBeanFactory(ConfigurableListableBeanFactory factory)
                  throws BeansException {
       this.factory = factory;
       }
       public void setApplicationContext(ApplicationContext c)
                throws BeansException {
       this.appContext = c;   
       }
    
       //setters and getters
    
    }
    

    스프링이 XML 설정 파일에서 빈을 선언함으로써 컨텍스트에이 빈을로드하자.

    <bean id="appContext" class="my.package.MyContextWrapper">
    </bean>
    

    이제이 빈은 그것을 참조함으로써 애플리케이션의 다른 빈에로드 될 수있다.

    <bean id="myBeanFactory" class="my.package.MyBeanFactory">
     <property name="springContext" ref="appContext">
     </property>
    </bean>
    

    GenericBeanDefinition을 사용하여 Bean 정의를로드한다.

    BeanDefinitionRegistry registry = ((BeanDefinitionRegistry )factory);
    
    GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
    beanDefinition.setBeanClass(MyBeanClass.class);
    beanDefinition.setLazyInit(false);
    beanDefinition.setAbstract(false);
    beanDefinition.setAutowireCandidate(true);
    beanDefinition.setScope("session");
    
    registry.registerBeanDefinition("dynamicBean",beanDefinition);
    

    Bean은 세션 범위에서 작성되며 사용자 세션에 저장됩니다. 프라퍼티 자동 와이어 후보는 setter 또는 getter 또는 생성자 인수와 같은 bean의 종속성이 Spring에 의해 자동으로 처리되어야 하는지를 봄에 알려줍니다. lazy init 속성은 필요할 때이 빈을 인스턴스화해야하는지 Spring에 알린다.

    Spring 빈의 핸들을 얻으려면 다음과 같이 Spring 애플리케이션 컨텍스트를 사용한다.

    Object bean= 
     getApplicationContext().getBean("dynamicBean");
     if(bean instanceof MyBeanClass){
     MyBeanClass myBean = (MyBeanClass) bean;
    
       // do with the bean what ever you have to do.
     } 
    
  3. ==============================

    3.당신의 솔루션은 좋아 보인다. 우리는 BeanNameAware와 FactoryBean 인터페이스를 구현하는 빈을 생성함으로써 달성 할 수 있다고 믿고, 그런 다음 컨텍스트를 생성하기 전에 값을 설정합니다.

    당신의 솔루션은 좋아 보인다. 우리는 BeanNameAware와 FactoryBean 인터페이스를 구현하는 빈을 생성함으로써 달성 할 수 있다고 믿고, 그런 다음 컨텍스트를 생성하기 전에 값을 설정합니다.

    xxxxBean.beansByName.put("synTable", synTable);
    ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
    assert externalDataSource == context.getBean("synTable");
    

    Bean 구현은 다음과 같습니다.

    public class xxxxBean implements BeanNameAware, FactoryBean {
    
        public static Map<String, Object> beans = new HashMap<String, Object>();
    
        private String beanName;
    
        @Override
        public void setBeanName(String beanName) {
            this.beanName = beanName;
        }
    
        @Override
        public Object getObject() {
            return beans.get(beanName);
        }
    
        @Override
        public Class<?> getObjectType() {
            return beans.get(beanName).getClass();
        }
    
        @Override
        public boolean isSingleton() {
            return true;
        }
    
    }
    
  4. from https://stackoverflow.com/questions/11606504/registering-beansprototype-at-runtime-in-spring by cc-by-sa and MIT license