Announcement Announcement Module
Collapse
No announcement yet.
performance-problem with loading applicationContext Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • performance-problem with loading applicationContext

    Hi,
    i have the following applicationContext.xml:

    Code:
    <beans  ... >
    		
    	<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    		<property name="location">
    			<value>/config.ini</value>
    		</property>
    	</bean>
    	
    	<util:list id="mappingClasses">
    		<value>de.gebitms.geplan.datastructures.data.BenutzerDOM</value>
    	</util:list>
    
    	<util:list id="mappingPackages">
    		<value>de.gebitms.geplan.datastructures.data</value>
    	</util:list>
    
    	<bean id="hibernatePropertiesSQL" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
    		<property name="properties">
    	  		<props>
    				<prop key="hibernate.dialect">${hbn.dialect.sql}</prop>
    				<prop key="hibernate.connection.isolation">${hbn.isolation}</prop>
    				<prop key="hibernate.jdbc.batch_size">${hbn.jdbc.batch_size}</prop>
    				<prop key="hibernate.order_updates">${hbn.order_updates}</prop>
    				<prop key="hibernate.show_sql">${hbn.show_sql}</prop>
    				<prop key="hibernate.transaction.factory_class">${hbn.transaction.factory_class}</prop>
    				<prop key="hibernate.c3p0.initial_pool_size">${hbn.c3p0.initial_pool_size}</prop>
    				<prop key="hibernate.c3p0.min_size">${hbn.c3p0.min_size}</prop>
    				<prop key="hibernate.c3p0.max_size">${hbn.c3p0.max_size}</prop>
    				<prop key="hibernate.c3p0.timeout">${hbn.c3p0.timeout}</prop>
    				<prop key="hibernate.c3p0.max_statements">${hbn.c3p0.max_statements}</prop>
    				<prop key="hibernate.c3po.idle_test_period">${hbn.c3po.idle_test_period}</prop>
    				<prop key="hibernate.c3po.max_idle_time">${hbn.c3po.max_idle_time}</prop>
    				<prop key="hibernate.c3po.acquire_increment">${hbn.c3po.acquire_increment}</prop>
    				<prop key="hibernate.c3po.auto_commit_on_close">${hbn.c3po.auto_commit_on_close}</prop>
    				<prop key="hibernate.c3po.num_helper_threads">${hbn.c3po.num_helper_threads}</prop>
    				<prop key="hibernate.connection.use_compression">${hbn.connection.use_compression}</prop>
    				<prop key="hibernate.connection.cache_result_set_metadata">${hbn.connection.cache_result_set_metadata}</prop>
    				<prop key="hibernate.connection.dont_track_open_resources">${hbn.connection.dont_track_open_resources}</prop>
    				<prop key="hibernate.connection.dynamic_calendars">${hbn.connection.dynamic_calendars}</prop>
    				<prop key="hibernate.connection.zero_date_time_behavior">${hbn.connection.zero_date_time_behavior}</prop>
    				<prop key="hibernate.connection.rollback_on_pooled_close">%{hbn.connection.rollback_on_pooled_close}</prop>
    				<prop key="hibernate.cache.provider_class">${hbn.cache.provider_class}</prop>
    				<prop key="hibernate.query.factory_class">${hbn.query.factory_class}</prop>
    		  	</props>
    	 	</property>
    	</bean>
    	<bean id="hibernatePropertiesOracle" parent="hibernatePropertiesSQL">
    		<property name="properties">
    			<props merge="true">
    				<prop key="hibernate.dialect">${hbn.dialect.oracle}</prop>
    			</props>
    		</property>
    	</bean>
    
    	<bean id="abstractDataSourceSQL" abstract="true" class="org.apache.commons.dbcp.BasicDataSource">
    		<property name="driverClassName" value="${database.sql.driverclass}"/>
    		<property name="url" value="${database.sql.url}"/>
    		<property name="username" value="${database.user}"/>
    		<property name="password" value="${database.password}"/>
    	</bean>
    	<bean id="abstractDataSourceOracle" abstract="true" class="org.apache.commons.dbcp.BasicDataSource">
    		<property name="driverClassName" value="${database.oracle.driverclass}"/>
    		<property name="url" value="${database.oracle.url}"/>
    		<property name="username" value="${database.user}"/>
    		<property name="password" value="${database.password}"/>
    	</bean>
    	<bean id="dataSourceSQL" parent="abstractDataSourceSQL"/>
    	<bean id="dataSourceSQLTest" parent="abstractDataSourceSQL">
    		<property name="url" value="${database.sql.url.test}"/>
    		<property name="username" value="${database.user.test}"/>
    	</bean>
    	<bean id="dataSourceOracle" parent="abstractDataSourceOracle"/>
    	<bean id="dataSourceOracleTest" parent="abstractDataSourceOracle">
    		<property name="username" value="${database.user.test}"/>
    	</bean>
    
    	<bean id="abstractSessionFactorySQL" abstract="true" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean" scope="singleton">
    		<property name="dataSource" ref="dataSourceSQL"/>
    		<property name="hibernateProperties" ref="hibernatePropertiesSQL"/>
     	    <property name="annotatedPackages" ref="mappingPackages"/>
     	    <property name="annotatedClasses" ref="mappingClasses"/>
    		<property name="exposeTransactionAwareSessionFactory"><value>false</value></property>
    	</bean>
    	<bean id="abstractSessionFactoryOracle" abstract="true" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean" scope="singleton">
    		<property name="dataSource" ref="dataSourceOracle"/>
    		<property name="hibernateProperties" ref="hibernatePropertiesOracle"/>
     	    <property name="annotatedPackages" ref="mappingPackages"/>
     	    <property name="annotatedClasses" ref="mappingClasses"/>
    		<property name="exposeTransactionAwareSessionFactory"><value>false</value></property>
    	</bean>
    	<bean id="sessionFactorySQL" parent="abstractSessionFactorySQL"/>
    	<bean id="sessionFactorySQLTest" parent="abstractSessionFactorySQL">
    		<property name="dataSource" ref="dataSourceSQLTest"/>
    	</bean>
    	<bean id="sessionFactoryOracle" parent="abstractSessionFactoryOracle"/>
    	<bean id="sessionFactoryOracleTest" parent="abstractSessionFactoryOracle">
    		<property name="dataSource" ref="dataSourceOracleTest"/>
    	</bean>
    
    	<bean id="abstractHibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate">
    		<property name="sessionFactory" ref="sessionFactorySQL"/>
    		<property name="allowCreate" value="true"/>
    		<property name="cacheQueries" value="true"/>
    	</bean>
    	<bean id="hibernateTemplateSQL" parent="abstractHibernateTemplate"/>
    	<bean id="hibernateTemplateSQLTest" parent="abstractHibernateTemplate">
    		<property name="sessionFactory" ref="sessionFactorySQLTest"/>
    	</bean>
    	<bean id="hibernateTemplateOracle" parent="abstractHibernateTemplate">
    		<property name="sessionFactory" ref="sessionFactoryOracle"/>
    	</bean>
    	<bean id="hibernateTemplateOracleTest" parent="abstractHibernateTemplate">
    		<property name="sessionFactory" ref="sessionFactoryOracleTest"/>
    	</bean>
    
    	<bean id="multipleHibernateTemplate" class="de.gebitms.geplan.springwrapper.MultipleHibernateTemplate"
    		scope="prototype">
    		<constructor-arg>
    			<map>
    				<entry key="sql" value-ref="hibernateTemplateSQL"/>
    				<entry key="sqlTest" value-ref="hibernateTemplateSQLTest"/>
    				<entry key="oracle" value-ref="hibernateTemplateOracle"/>
    				<entry key="oracleTest" value-ref="hibernateTemplateOracleTest"/>
    			</map>
    		</constructor-arg>
    	</bean>
    
    	<bean id="dataAccessExceptionInterceptor" class="de.gebitms.geplan.springwrapper.advices.DataAccessExceptionAdvice"/>
    	<bean id="dataAccessExceptionAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
    		<property name="pattern" value="de.gebitms.geplan.+"/>
    		<property name="advice">
    			<ref bean="dataAccessExceptionInterceptor"/>
    		</property>
    	</bean>
    	
    	<bean id="autoProxyCreator" class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator">
    		<property name="proxyTargetClass" value="true"/>
    	</bean>
    
    	<bean id="txManagerSQL" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
    		<property name="sessionFactory" ref="sessionFactorySQL"></property>
    	</bean>
    	<bean id="txManagerSQLTest" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
    		<property name="sessionFactory" ref="sessionFactorySQLTest"></property>
    	</bean>
    	<bean id="txManagerOracle" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
    		<property name="sessionFactory" ref="sessionFactoryOracle"></property>
    	</bean>
    	<bean id="txManagerOracleTest" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
    		<property name="sessionFactory" ref="sessionFactoryOracleTest"></property>
    	</bean>
    
    	<bean id="multipleTxManager" class="de.gebitms.geplan.springwrapper.MultipleTransactionManager"
    		scope="prototype">
    		<constructor-arg>
    			<map>
    				<entry key="sql" value-ref="txManagerSQL"/>
    				<entry key="sqlTest" value-ref="txManagerSQLTest"/>
    				<entry key="oracle" value-ref="txManagerOracle"/>
    				<entry key="oracleTest" value-ref="txManagerOracleTest"/>
    			</map>
    		</constructor-arg>
    	</bean>
    
    	<tx:annotation-driven transaction-manager="multipleTxManager" proxy-target-class="true"/>
    Here i define 4 database-connections. 2 of the databases are on the same computer, the other 2 are on another computer in the network.
    As far as i understand spring, the configuration is loaded lazy. So i assume that he is not trying to connect to the databases while loading the context. BUT: when i load it with the following line:

    Code:
    appContext = new ClassPathXmlApplicationContext("/de/gebitms/geplan/springwrapper/applicationContext.xml");
    this takes more then 30 seconds. And my computer isnīt that slow. Why does it take so long to load my context. What can i do to get a better performance. Can you help me out with this?

    Thanks very much for any help.
    Christoph

    PS: I had to shorten this post to get below the 10000 characters, so i omitted my own beans from the context (there are only 5 of them and they are not very spectacular)

    Spring 2.0.1
    Windows 2000
    SQL-Server 7.0
    Oracle 9i
    Eclipse 3.2.1
    Hibernate 3.2

  • #2
    As far as i understand spring, the configuration is loaded lazy. So i assume that he is not trying to connect to the databases while loading the context.
    Your assumption is wrong. The configuration is loaded eagerly, instantiating all the beans, connections etc unless you specify otherwise.

    However there are at least a few things which take time to create:
    * remote database connections (depending on speed of remote computer, network speeds)
    * creating one or more hibernate session factories, hibernate factories take a relative long time to instantiate and it also has some database activity so if one of the other databases is slow, hibernate startsup even slower.

    Comment


    • #3
      Hi Marten,

      thanks for your answer. That clears thinks up. Now i know why it takes so long. My problem is, that i have to develop for SQL-Server and Oracle, and that i start my application either to test it or to work with it. So i have a production database and a test database for sql-server as well as for oracle. That are 4 databases, 4 database connections, 4 sessionFactories :-(

      Is there a way to decide at runtime which beans to load? So that i can connect to the two production databases only while i start the application for working and connect to the test databases only for testing? Or can i load the connections and sessionFactories lazy? And how can i do that?

      Your help is much appreciated. Thanks.
      Christoph

      Comment


      • #4
        Search the forum for PropertyPlaceHolderConfigurer. This lets you provide property files which include the settings. So either load the production one or load the testing one.

        That way your configuration would also be cut in half...

        Comment


        • #5
          PropertyPlaceHolderConfigurer is a great way of cutting down on config as Marten said. If you do really want to lazy init beans though, you can do this.
          http://www.springframework.org/docs/...tory-lazy-init

          Comment


          • #6
            thanks guys. I see that i have to cut my configuration in half. Setting default-lazy-init="true" doesnīt help, because all my beans depend upon each other, so by the time i load one eagerly, all other beans are loaded eagerly as well.

            I allready load all my connection parameters from a file called config.ini (iīm developing a rcp-application). So now i write two config.ini files one with the connection-properties for the production databases and the other one with the connection-properties for the test database. But what comes then? Do i have to rename the files each time i switch between production and testing? Or can i somehow set a condition in the applicationContext.xml loading the correct context.ini depending (for example) on a environment variable which i could set via my eclipse-launch-configuration.

            Is that possible?
            Thanks
            Christoph

            Comment


            • #7
              Have you checked this thread out?
              http://forum.springframework.org/showthread.php?t=33622

              Comment


              • #8
                A short example:

                Code:
                <bean id="propertyConfigurer"
                  class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
                    <property name="location" value="classpath:/${runtime_environment}.properties" />
                </bean>
                
                <bean id="batchContainerDataSource"
                  class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"
                  scope="singleton" depends-on="propertyConfigurer">
                
                    <property name="username" value="${jdbc.username}" />
                    <property name="password" value="${jdbc.password}" />
                    ...
                </bean>
                then you can pass -Druntime_environment=TEST to your JVM and spring will look for the file TEST.properties

                -Patrick

                Comment


                • #9
                  thanks for the link. I understand now, that i could reduce the number of datasources i define to 1 or 2 and decide via a property-file to which databases my programm should connect. But actually that is not what i want.

                  For me it would be better to keep all 4 datasoures (and sessionFactories) defined in the applicationContext.xml file and decide at runtime which of these should be initialized and which should not.

                  So i assume that i have to write my own custom BeanFactoryPostProcessor and edit the configuration after it has been loaded but before the beans are initialized. Right? Is it possible to delete certain bean definitions manually from the configuration and with that preventing them from being initialized? Or did i get this all wrong? Do you know where i can find an example of how this is done (if it is possible at all)?

                  Thanks
                  Christoph

                  Comment


                  • #10
                    You may have a look at HotSwappableTargetSource (http://static.springframework.org/sp...getSource.html)
                    or at LazyInitTargetSource (http://static.springframework.org/sp...getSource.html)



                    -Patrick

                    Comment


                    • #11
                      What I usually do is keep a separate set of datasource context files (dsContext.xml, dsTestContext.xml, dsTestHSQLContext.xml, etc) defining only different datasources, under the same bean name. At runtime, in different environments I can load the needed ds context together with the main context.

                      This allows you to have structurally different datasources - jndi lookup ds, connection pool ds, simple drivermanager ds, etc.

                      Comment


                      • #12
                        thanks guys, i almost have it. I integrated a couple of ProxyFactoryBean with LazyInitTargetSources into my configuration and set all my beans to lazy-init=true. That gets the perfomance up to 7 sec. loading time which i would accept. BUT ... i have the following problem now:

                        I use HibernateAnnotations to map my domain-classes to the database. Here is an extract from one of that classes:

                        Code:
                        @Entity 
                        @Table(name="S_Benutzer",  
                        	uniqueConstraints = {@UniqueConstraint(columnNames={"b_nr"})})
                        @org.hibernate.annotations.Table(appliesTo="S_Benutzer", indexes={@Index(name="b_nr", columnNames={"b_nr"})})
                        @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
                        @AccessType("property")
                        @Transactional(propagation=Propagation.MANDATORY, rollbackFor=GeplanException.class)
                        public class BenutzerDOM implements Serializable, IBenutzerDOM {
                        	private static final long serialVersionUID = 1L;
                        	private Long id;
                        	private String name;
                        	private String vorname;
                        	private int art;
                        	private String kennung;
                        	private String passwort;
                        	private int sperre;
                        	private int standard;
                        		
                        	public BenutzerDOM() {}
                        
                        	@Id 
                        	@GeneratedValue(generator="pk_creator")
                        	@Column(name="b_nr", nullable=false, unique=true, length=4)
                        	public Long getId() {
                        		return id;
                        	}
                        
                        	@Basic 
                        	@Column(name="b_name", length=200)
                        	public String getName() {
                        		return name;
                        	}
                        
                        	@Basic
                        	@Column(name="b_vname", length=200)
                        	public String getVorname() {
                        		return vorname;
                        	}
                        
                               .....
                        the id-generator called "pk_creator" is a global variable set in a file called "package-info.java". Here it is:

                        Code:
                        @GenericGenerator(name="pk_creator", strategy = "increment")
                        package de.gebitms.geplan.datastructures.data;
                        
                        import org.hibernate.annotations.GenericGenerator;
                        Then i define my sessionFactorys in the Spring-Config:

                        Code:
                        <!-- Hibernate-Session-Factories -->
                        <!-- Abstract Classes -->
                        <bean id="abstractSessionFactorySQL" abstract="true" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean" 
                         	scope="singleton" lazy-init="true">
                        	<property name="dataSource" ref="dataSourceProxySQL"/>
                        	<property name="hibernateProperties" ref="hibernatePropertiesSQL"/>
                        	<property name="annotatedPackages" ref="mappingPackages"/>
                        	<property name="annotatedClasses" ref="mappingClasses"/>
                        	<property name="exposeTransactionAwareSessionFactory"><value>false</value></property>
                        </bean>
                        <bean id="abstractSessionFactoryOracle" abstract="true" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean" 
                        		scope="singleton" lazy-init="true">
                        	<property name="dataSource" ref="dataSourceProxyOracle"/>
                        	<property name="hibernateProperties" ref="hibernatePropertiesOracle"/>
                        	<property name="annotatedPackages" ref="mappingPackages"/>
                        	<property name="annotatedClasses" ref="mappingClasses"/>
                        	<property name="exposeTransactionAwareSessionFactory"><value>false</value></property>
                        </bean>
                        <!-- Derived Classes -->
                        <bean id="sessionFactorySQL" parent="abstractSessionFactorySQL" lazy-init="true"/>
                        <bean id="sessionFactorySQLTest" parent="abstractSessionFactorySQL" lazy-init="true">
                        	<property name="dataSource" ref="dataSourceProxySQLTest"/>
                        </bean>
                        <bean id="sessionFactoryOracle" parent="abstractSessionFactoryOracle" lazy-init="true"/>
                        <bean id="sessionFactoryOracleTest" parent="abstractSessionFactoryOracle" lazy-init="true">
                        	<property name="dataSource" ref="dataSourceProxyOracleTest"/>
                        </bean>
                        Where the beans "mappingPackages" and "mappingClasses" point to the following declarations:

                        Code:
                        <util:list id="mappingClasses">
                             <value>de.gebitms.geplan.datastructures.data.BenutzerDOM</value>
                        </util:list>
                        
                        <util:list id="mappingPackages">
                        	<value>de.gebitms.geplan.datastructures.data</value>
                        </util:list>
                        If i start my test i get the following error when i try to load a sessionFactory:

                        org.springframework.beans.factory.BeanCreationExce ption: Error creating bean with name 'sessionFactorySQL' defined in class path resource [de/gebitms/geplan/springwrapper/applicationContext.xml]: Invocation of init method failed; nested exception is org.hibernate.AnnotationException: Unknown Id.generator: pk_creator
                        All of this works fine when i change the initialization-strategy for the above beans sessionFactorySQL, sessionFactorySQLTest, sessionFactoryOracle and sessionFactoryOracleTest to an eager loading (lazy-init=false). But that drops my loading time by a second.

                        I mean, i could tolerate this one second, but i still wonder whatīs wrong here. It seems that he doesnīt recognize the mapped Package and the id-generator that is declared there, as soon as i proxy the sessionFactory. Why is that or what am i doing wrong? Or is this a bug?

                        Could you clear this up?
                        Thanks
                        Christoph

                        Comment


                        • #13
                          Originally posted by kopinsky View Post
                          For me it would be better to keep all 4 datasoures (and sessionFactories) defined in the applicationContext.xml file and decide at runtime which of these should be initialized and which should not.

                          So i assume that i have to write my own custom BeanFactoryPostProcessor and edit the configuration after it has been loaded but before the beans are initialized. Right? Is it possible to delete certain bean definitions manually from the configuration and with that preventing them from being initialized? Or did i get this all wrong? Do you know where i can find an example of how this is done (if it is possible at all)?

                          Thanks
                          Christoph
                          If you know the various combinations of data sources and session factories that you want to use for your system, I would recommend breaking each data source and session factory into its own file, rather than trying to define everything in one XML file and trying to convince some of them not to load, else you're quickly going to run into a maintenance nightmare. Use a bean ref context (accessed by a SingletonBeanFactoryLocator) to group the logical combinations of these files together and access via the ID of the bean ref context. You can load the ID in from a system property, external file, etc.

                          Comment


                          • #14
                            I would agree with the previous author. I think this could be really complicated and as you have already seen. I would guess that you are loading a Hibernate object which references your generator, but the generator hasn't been included.

                            Comment

                            Working...
                            X