Spring ApplicationContext: Fortschritt der Instanziierung von Beans?

DarthShader

Erfahrenes Mitglied
Hallo,

ich habe einen recht großen Spring applicationContext.xml, in der viele Beans definiert sind. Meine Frage ist es nun, kann ich den Fortschritt des Instanziierens irgendwie abfragen, bzw. einen Listener an Spring hängen, der mit den Fortschritt des instanziierens der Beans mitteilt?


Danke!
 
Hm, auf die schnelle würde ich wohl einen ApplicationContext um den Ziel ApplicationContext bauen und die entsprechenden Methoden con ApplicationContext mit einem Aspekt versehen:

XML:
<aop:aspectj-autoproxy />

<bean class="org.springframework...ClassPathXmlApplicationContext">
  <constructor-arg value="dein/konfigurations/file.xml" />
</bean>

<bean class="dein.Aspect" />

Im Aspect kannst du dann Pointcuts auf der Spring API beschreiben und z.B. mit @Around die Aufrufe abfangen.

Alternativ geht natürlich AspectJ Loadtimeweaving. Dann werden die Klassen zum Ladezeitpunkt "advised". Ich vermute so arbeitet auch dieses Aplication Management Tool von Spring Source.

Gruß
Ollie
 
Zuletzt bearbeitet von einem Moderator:
Nun, ich bin gerade erst Spring-Einsteiger würde ich mal sagen, und habe nur 70% von dem, was Du vorgeschlagen hast, verstanden :) Aber die restlichen 30% sind mein Part, ich muss noch einiges darüber lernen.

Ich hatte jetzt gehofft, es gäbe eine einfachere Möglichkeit, vielleicht hätte man einen einfachen "AddProgressListener" an den AppContext gehängt :)

Wenn ich AOP einsetze, mache ich mich dann nicht von einem speziellen Compiler abhängig? Funktionieren meine Ant-Skripte dann überhaupt noch?
 
Standardmäßig ist AOP in Spring mit Dynamic Proxies inmplementiert. Das geht, wenn du auf Interfaces arbeitest, ohne 3rd Party Libraries (Dann werden einfach JDKProxies erzeugt. Wenn du klassen "verAOPen" willst, benötigst du CGLib im Classpath und musst proxy-target-class="true" setzen im aop:aspectj-autoproxy.

Es ist auch möglich, AspectJ einzusetzen, jedoch nicht zwingend notwendig.

Der "Trick" bei meiner Idee ist einfach, einen ApplicationContext als Bean zu definieren und ihn somit mit einem Aspekt versehen zu können.

Wenn du noch Fragen hast - raus damit!

REINHAUN!
 
Hi Olli,

vielen Dank für die ganzen Infos. Ehrlich gesagt, Du wirfst mich da gerade in Thematiken rein, über die ich noch einiges zu lesen habe :) Ich will auch nicht jede Einzelheit hier fragen, bevor ich mich nicht ausführlich mit dem Thema auseinander gesetzt habe.

Du hast mir auf jeden Fall schonmal recht viele Stichworte präsentiert, an denen ich mich weiterhangeln kann.

Danke!
 
Hallo,

schau mal hier:

Java:
/**
 * 
 */
package de.tutorials;

import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.BeanPostProcessor;

/**
 * @author Thomas.Darimont
 * 
 */
public interface ApplicationContextInitializationInfoMBean extends
        BeanFactoryPostProcessor, BeanPostProcessor {
    boolean isInitialized();

    double getInitializationProgress();

    int getAlreadyInitializedBeanDefinitionCount();

    String getLatestCompleteInitializedBeanName();

    int getBeanDefinitionCount();
}

Java:
/**
 * 
 */
package de.tutorials;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;

/**
 * @author Thomas.Darimont
 * 
 */
public class ApplicationContextInitializationInfo implements
        ApplicationContextInitializationInfoMBean {

    private volatile int beanDefinitionCount = -1;
    private volatile int alreadyInitializedBeanDefinitionCount;
    private volatile String latestCompleteInitializedBeanName;

    @Override
    public double getInitializationProgress() {
        double progress = 0.0;
        if (beanDefinitionCount != -1) {
            progress = alreadyInitializedBeanDefinitionCount
                    / (double) beanDefinitionCount;
        }
        return progress;
    }

    public int getAlreadyInitializedBeanDefinitionCount() {
        return this.alreadyInitializedBeanDefinitionCount;
    }

    public String getLatestCompleteInitializedBeanName() {
        return this.latestCompleteInitializedBeanName;
    }
    
    public int getBeanDefinitionCount(){
        return this.beanDefinitionCount;
    }

    @Override
    public boolean isInitialized() {
        return beanDefinitionCount == alreadyInitializedBeanDefinitionCount;
    }

    @Override
    public void postProcessBeanFactory(
            ConfigurableListableBeanFactory beanFactory) throws BeansException {
        this.beanDefinitionCount = beanFactory.getBeanDefinitionCount();
        beanFactory.addBeanPostProcessor(this);
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName)
            throws BeansException {
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName)
            throws BeansException {
        System.out.println("postProcessAfterInitialization: " + beanName);
        this.alreadyInitializedBeanDefinitionCount++;
        this.latestCompleteInitializedBeanName = beanName;
        return bean;
    }

}

Java:
/**
 * 
 */
package de.tutorials;

import java.lang.management.ManagementFactory;

import javax.management.MBeanServer;
import javax.management.ObjectName;

import org.springframework.context.support.AbstractXmlApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;

/**
 * @author Thomas.Darimont
 * 
 */
public class ApplicationContextInitializationProgressReportingExample {

    /**
     * @param args
     */
    public static void main(String[] args) throws Exception {

        MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer();
        ObjectName objectName = new ObjectName(
                "de.tutorials:name=ApplicationContextInitializationInfo");
        ApplicationContextInitializationInfoMBean applicationContextInitializationInfo = new ApplicationContextInitializationInfo();
        mbeanServer.registerMBean(applicationContextInitializationInfo,
                objectName);

        AbstractXmlApplicationContext applicationContext = new FileSystemXmlApplicationContext(
                new String[] { "config/context.xml" },false);
        applicationContext
                .addBeanFactoryPostProcessor(applicationContextInitializationInfo);
        applicationContext.refresh();
        System.out.println(applicationContext.getBean("a"));
    }
}

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"
        xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context"
        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
                http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">

    <bean id="a" class="de.tutorials.Bean"/>
    <bean id="b" class="de.tutorials.Bean"/>
    <bean id="c" class="de.tutorials.Bean"/>
    <bean id="d" class="de.tutorials.Bean"/>
</beans>

Java:
/**
 * 
 */
package de.tutorials;

import java.util.concurrent.TimeUnit;

/**
 * @author Thomas.Darimont
 * 
 */
public class Bean {
    public Bean(){
        try {
            TimeUnit.SECONDS.sleep(10L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

Anschließend kann man sich via JConsole ganz einfach ein Bild über den Initialisierungsfortschritt verschaffen.

Gruß Tom
 

Anhänge

  • SpringContextInitializationProgressViaJMX.jpg
    SpringContextInitializationProgressViaJMX.jpg
    69,8 KB · Aufrufe: 70
Zuletzt bearbeitet von einem Moderator:
Hallo Thomas,

vielen Dank für den Beitrag - das hat mir sehr gehoflfen, ich denke ich habe die Codestücke auch komplett verstanden (nachdem ich die Abschnitte über das post processing bei der Bean initialisierung gelesen habe).

Danke dafür, und danke natürlich auch an Olli.
 
Das erschlägt aber dann nur die Instantiierung von Beans. Das heißt zu dem Zeitpunkt, an dem der BeanFactoryPostProcessor gerufen wird, sind schon alle Konfigurationsfiles eingelesen und die Metadaten erzeugt.

Sollte man im Auge haben, da unter Umständen vor allem beim Einsatz von Namespaces vorher schon jede Menge geschieht. Evtl. vorhandene andere BeanFactoryPostProcessoren könnten demnach auch schon instantiiert und ausgeführt worden sein. Das könnte man aber noch ausschließen indem man Ordered implementiert und fest 0 zurückgibt. Dann wird dieser BeanFactoryPostProcessor definitv als erstes erzeugt und ausgeführt.

In Bezug auf die Instantiierung der Beans ist das aber durchaus ein gangbarer Weg.

Gruß
Ollie
 
Hallo,

also ich würde eher sagen dieser "InitializationProgressReportingBeanFactoryPostProcessor " "muss" als letzter BeanFactoryPostProcessor aufgerufen werden. Auch mit Ordered kann man IMHO nicht garantieren, dass ein bestimmter BeanFactoryPostProcessor als "letztes" ausgeführt wird (es könnten ja weitere BeanFactoryPostProcessor mit Ordered und getOrder() -> Integer.MAX_VALUE definiert sein) .

Gruß Tom
 
Zurück