2016-05-17 19 views
2

Ich versuche, eine benutzerdefinierte DeltaSpike ConfigSource zu definieren. Die benutzerdefinierte Konfigurationsquelle hat die höchste Priorität und überprüft die Datenbank auf den Parameter config.DeltaSpike benutzerdefinierte ConfigSource mit CDI

Ich habe eine ConfigParameter-Entität, die einfach einen Schlüssel und einen Wert hat.

@Entity 
@Cacheable 
public class ConfigParameter ... { 

     private String key; 
     private String value; 

} 

Ich habe einen @Dependent DAO, das alle Parameter Config findet.

Was ich jetzt versuche, ist eine benutzerdefinierte ConfigSource zu definieren, die in der Lage ist, den config-Parameter von der Datenbank zu bekommen. Daher möchte ich mein DAO in die ConfigSource einspeisen. Also im Grunde so etwas wie

@ApplicationScoped 
public class DatabaseConfigSource implements ConfigSource { 

    @Inject 
    private ConfigParameterDao configParameterDao; 

    .... 
} 

Wenn jedoch die ConfigSource über META-INF Registrierung/services/org.apache.deltaspike.core.spi.config.ConfigSource, wird die Klasse instanziiert und CDI wird nicht funktionieren .

Gibt es eine Möglichkeit, CDI in diesem Fall zu arbeiten?

Vielen Dank im Voraus, wenn Sie weitere Informationen benötigen, lassen Sie es mich bitte wissen.

Antwort

0

Das Hauptproblem ist, dass die ConfigSource sehr früh instanziiert wird, wenn der BeanManager noch nicht verfügbar ist. Selbst die JNDI-Suche funktioniert zu diesem Zeitpunkt nicht. Daher muss ich die Injektion/Suche verzögern.

Was ich jetzt gemacht habe, ist ein statischer boolean zu meiner Config-Quelle hinzuzufügen, die ich manuell einstelle. Wir haben einen InitializerService, der sicherstellt, dass das System richtig eingerichtet ist. Am Ende des Initialisierungsprozesses rufe ich allowInitialization() an, um der Konfigurationsquelle mitzuteilen, dass die Bean jetzt injizierbar ist. Wenn die ConfigSource das nächste Mal gefragt wird, kann sie die Bean unter Verwendung von BeanProvider.injectFields injizieren.

public class DatabaseConfigSource implements ConfigSource { 

    private static boolean allowInit; 

    @Inject 
    private ConfigParameterProvider configParameterProvider; 

    @Override 
    public int getOrdinal() { 
     return 500; 
    } 

    @Override 
    public String getPropertyValue(String key) { 
     initIfNecessary(); 

     if (configParameterProvider == null) { 
      return null; 
     } 

     return configParameterProvider.getProperty(key); 
    } 

    public static void allowInitialization() { 
     allowInit = true; 
    } 

    private void initIfNecessary() { 
     if (allowInit) { 
      BeanProvider.injectFields(this); 
     } 
    } 

} 

Ich habe eine Anfrage-Bean, die alle meine Config-Variablen für Typ-Safe-Zugriff enthält.

@RequestScoped 
public class Configuration { 

    @Inject 
    @ConfigProperty(name = "myProperty") 
    private String myProperty; 

    @Inject 
    @ConfigProperty(name = "myProperty2") 
    private String myProperty2; 

    .... 

} 

Beim Injizieren der Konfigurationsklasse in eine andere Bean wird jede ConfigProperty aufgelöst. Da meine benutzerdefinierte DatabaseConfigSource die höchste Ordnungszahl (500) hat, wird sie zuerst für die Eigenschaftsauflösung verwendet. Wenn die Eigenschaft nicht gefunden wird, wird die Auflösung an die nächste ConfigSource delegiert.

Für jede ConfigProperty wird die getPropertyValue-Funktion von DatabaseConfigSource aufgerufen. Da ich die Parameter für jede Konfigurationseigenschaft nicht aus der Datenbank abrufen möchte, habe ich die Auflösung der Konfigurationseigenschaft in eine Anforderungsbereichs-Bean verschoben.

@RequestScoped 
public class ConfigParameterProvider { 

    @Inject 
    private ConfigParameterDao configParameterDao; 

    private Map<String, String> configParameters = new HashMap<>(); 

    @PostConstruct 
    public void init() { 
     List<ConfigParameter> configParams = configParameterDao.findAll(); 
     configParameters = configParams.stream() 
      .collect(toMap(ConfigParameter::getId, ConfigParameter::getValue)); 
    } 

    public String getProperty(String key) { 
     return configParameters.get(key); 
    } 

} 

Ich könnte sicher die Request-Bereich ConfigParameterProvider zu ApplicationScoped ändern. Wir haben jedoch ein Multi-Tenant-Setup und die Parameter müssen pro Anfrage aufgelöst werden.

Wie Sie sehen können, ist dies ein bisschen hacky, weil wir explizit die ConfigSource mitteilen müssen, wenn es richtig instanziiert werden darf (inject the bean).

Ich würde eine standardisierte Lösung von DeltaSpike für die Verwendung von CDI in einer ConfigSource bevorzugen. Wenn Sie eine Idee haben, wie Sie dies richtig umsetzen können, lassen Sie es mich wissen.

+0

Sie können 'initIfNecessary()' noch verbessern - im Moment funktioniert es eher wie 'initIfPossible()', dh die Felder werden nicht zu früh injiziert, aber sie werden bei jedem Aufruf von 'getPropertyValue()' injiziert . –

+0

Die Version 1.8 wird dies beheben. –

0

DS verwendet dafür den Java-Mechanismus spi, der nicht CD'Injectable 'ist. Eine Lösung wäre, die BeanProvider zu verwenden, um Ihre DatabaseConfigSource zu erhalten und Vorgänge an sie zu delegieren.

+0

Die ConfigSources werden initialisiert, bevor der Beanprovider initialisiert wird. Wenn also versucht wird, den Beanprovider in der ConfigSource zu verwenden, wird eine Ausnahme ausgelöst, dass kein Provider verfügbar ist. – kevcodez

+0

Ok, aber wenn Sie auf BeanProvider in getPropery/getProperties Methoden zugreifen, ist es nicht in Ordnung? Werden diese 2 Eigenschaften init aufgerufen? – Franck

+0

Die Funktion 'getProperty' wird während verschiedener Phasen des Anwendungs ​​/ Container-Starts aufgerufen. DS versucht zunächst einige interne Eigenschaften zu erhalten, bevor versucht wird, meine benutzerdefinierten Konfigurationseigenschaften aufzulösen. Während des ersten "Durchlaufs" ist der BeanProvider nicht verfügbar. Die Funktion 'getProperties' wird nicht aufgerufen. Ich brauche die ConfigSource oder etwas Ähnliches, das initialisiert wird, wenn die CDI-Beans initialisiert sind. – kevcodez