21

コミュニティによって評価されたものが必要なだけです。次のコード スニペットは、特定の型のインスタンスを作成する単純なファクトリです。このメソッドは、Bean をプロトタイプとしてコンテキストに登録し、インスタンスを返します。実行時に 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を使用しています。貴重なご意見をお聞かせください。

敬具。

4

3 に答える 3

25

これは純粋に私の意見であり、専門家の見解ではありません。

Spring は、アプリケーション コンテキストのカスタム変更のための 2 つのメカニズムを提供します。既存の Bean 定義の変更または新しい Bean 定義の追加を可能にするBeanFactoryPostProcessorと、Bean インスタンスの変更を可能にするBeanPostProcessorを使用します (それらをプロキシにラップするなど)。

Spring は、実行時に Bean 定義または Bean インスタンスを動的に追加する他のネイティブな方法を提供しませんが、基礎となる Bean ファクトリ インスタンスを取得して Bean 定義を追加することによって行ったように、1 つの方法です。機能しますが、リスクがあります。

  • 既存の Bean 名を新しいタイプで上書きするとどうなりますか?この Bean が既に注入されている場所はどのように処理されますか? また、既存の Bean 名がまったく異なるタイプで上書きされた場合はどうなりますか?

  • この新しく登録された Bean にはフィールドが自動配線されず、他の Bean にも注入されません。つまり、基本的に Bean ファクトリは純粋に Bean を保持するためのレジストリとして機能し、実際には依存性注入機能ではありません!

  • アプリケーションコンテキストでarefresh()が呼び出された場合、バッキング Bean ファクトリが上書きされ、新しいものが作成されるため、Bean ファクトリに対して直接登録された Bean インスタンスはすべて失われます。

目的が、Spring によって自動配線された Bean を作成することのみである場合は、 @Configurableのようなものを使用します。上記のリスクが許容できる場合は、アプローチも機能するはずです。

于 2012-08-01T01:42:34.723 に答える
11

これは私にとってはうまくいきました: http://random-thoughts-vortex.blogspot.com/2009/03/create-dynamically-spring-beans.html

ApplicationContextAware および BeanFactoryPostProcessor インターフェースを実装する 1 つの専用 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 を宣言することにより、Spring がこの Bean をそのコンテキストにロードできるようにします。

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

これで、この Bean を参照することで、アプリケーションの他の 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 はセッション スコープで作成され、ユーザー セッションに格納されます。プロパティ自動ワイヤ候補は、セッターやゲッター、またはコンストラクター引数などの Bean の依存関係が Spring によって自動的に処理される必要があるかどうかを Spring に伝えます。プロパティ lazy init は、必要に応じてこの Bean をインスタンス化する必要があるかどうかを Spring に伝えます。

Spring Bean のハンドルを取得するには、次のように Spring アプリケーション コンテキストを使用します。

Object bean= 
 getApplicationContext().getBean("dynamicBean");
 if(bean instanceof MyBeanClass){
 MyBeanClass myBean = (MyBeanClass) bean;

   // do with the bean what ever you have to do.
 } 
于 2013-02-05T20:41:55.230 に答える
0

あなたのソリューションは良さそうです。BeanNameAware および FactoryBean インターフェースを実装する Bean を作成し、コンテキストを作成する前に値を設定することによっても達成できると思います。

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;
    }

}
于 2012-08-06T18:50:39.477 に答える