java gui - Registrieren von Beans(Prototyp)zur Laufzeit im Frühjahr




swing tutorial (4)

Ich brauche nur etwas, das von der Community bewertet wird. Es folgt ein Codefragment, bei dem es sich um eine einfache Factory handelt, die Instanzen eines bestimmten Typs erstellt. Die Methode registriert die Bean im Kontext als Prototyp und gibt die Instanz zurück. Dies ist das erste Mal, dass ich Beans zur Laufzeit konfiguriere. Können Sie uns Feedback geben? Vielen Dank im Voraus.

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 Factory wurde im IoC-Container als Singleton konfiguriert. Um einen neuen Sync Manager zu erstellen, mache ich folgendes:

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

Ich benutze Frühling 3.1. Bitte überprüfen und geben Sie Ihr wertvolles Feedback.

mit freundlichen Grüßen.


Answers

Das hat für mich funktioniert: http://random-thoughts-vortex.blogspot.com/2009/03/create-dynamically-spring-beans.html

Deklarieren Sie eine dedizierte Spring-Context-Bean, die die Schnittstellen ApplicationContextAware und BeanFactoryPostProcessor implementiert:

  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

}

Lassen Sie Spring diese Bean in ihren Kontext laden, indem Sie die Bean in der XML-Konfigurationsdatei deklarieren:

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

Nun kann diese Bean in eine andere Bean der Anwendung geladen werden, indem sie referenziert wird:

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

Verwenden Sie GenericBeanDefinition, um die Bean-Definition zu laden:

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 wird im Sitzungsumfang erstellt und in der Benutzersitzung gespeichert. Der Property-Auto-Wire-Kandidat teilt Spring mit, ob die Abhängigkeiten des Beans wie das des Setter- oder Getter- oder Konstruktorarguments von Spring automatisch verarbeitet werden sollen. Die Eigenschaft fazile init teilt Spring mit, ob diese Bean bei Bedarf instanziiert werden soll.

Um ein Handle von Spring bean zu erhalten, verwenden Sie den Spring-Anwendungskontext wie folgt:

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

   // do with the bean what ever you have to do.
 } 

Ihre Lösung sieht gut aus. Ich glaube, wir können dies auch erreichen, indem wir eine Bean erstellen, die BeanNameAware- und FactoryBean-Schnittstellen implementiert, und dann setzen wir den Wert, bevor wir den Kontext erstellen.

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

Hier ist die Bean-Implementierung

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

}

Dies ist nur meine Meinung, keine Expertenmeinung:

Spring bietet zwei Mechanismen für die benutzerdefinierte Änderung eines Anwendungskontextes - mit BeanFactoryPostProcessor dem vorhandene Bean-Definitionen BeanPostProcessors oder neue Bean-Definitionen BeanPostProcessors können, und BeanPostProcessors denen Bean-Instanzen BeanPostProcessors können (um Proxy usw.).

Spring bietet keine andere native Methode zum dynamischen Hinzufügen von Bean-Definitionen oder Bean-Instanzen zur Laufzeit, aber wie Sie es getan haben, indem Sie die zugrunde liegenden Bean-Factory-Instanzen abgerufen und Bean-Definitionen hinzugefügt haben, ist eine Möglichkeit. Es funktioniert, aber es gibt Risiken:

  • Was passiert, wenn Sie einen vorhandenen Bean-Namen mit einem neuen Typ überschreiben? Wie werden Orte behandelt, an denen diese Bean bereits injiziert wurde? Was passiert auch, wenn ein existierender Bean-Name mit einem völlig anderen Typ überschrieben wird?

  • Diese neu registrierte Bean hat keine Felder, in die automatisch ein Eintrag geschrieben wird, und wird auch nicht in andere Beans injiziert - also fungiert die Bean-Factory im Grunde nur als Registry für die Bean, nicht wirklich als Abhängigkeits-Injection-Funktion!

  • Wenn eine refresh() für den Anwendungskontext aufgerufen wird, wird die Backing-Bean-Factory überschrieben und eine neue erstellt, sodass alle Bean-Instanzen, die direkt bei der Bean-Factory registriert sind, verloren gehen.

Wenn das Ziel nur darin besteht, Beans zu erstellen, die von Spring autowired wurden, würde ich etwas wie @Configurable . Wenn die oben genannten Risiken akzeptabel sind, sollte auch Ihr Ansatz funktionieren.


Hier ist eine Beispielschnittstelle:

public interface GenericDao<T, PK extends Serializable> {
    T create(T t);
    T read(PK id);
    T update(T t);
    void delete(T t);
}

Und eine Implementierung:

public class GenericDaoJpaImpl<T, PK extends Serializable> 
    implements GenericDao<T, PK> {

    protected Class<T> entityClass;

    @PersistenceContext
    protected EntityManager entityManager;

    public GenericDaoJpaImpl() {
        ParameterizedType genericSuperclass = (ParameterizedType) getClass()
             .getGenericSuperclass();
        this.entityClass = (Class<T>) genericSuperclass
             .getActualTypeArguments()[0];
    }

    @Override
    public T create(T t) {
        this.entityManager.persist(t);
        return t;
    }

    @Override
    public T read(PK id) {
        return this.entityManager.find(entityClass, id);
    }

    @Override
    public T update(T t) {
        return this.entityManager.merge(t);
    }

    @Override
    public void delete(T t) {
        t = this.entityManager.merge(t);
        this.entityManager.remove(t);
    }
}






java spring spring-mvc dependency-injection