spring application takes too long to start - java

I have a java application in which I'm using Spring and Hibernate frameworks. On my production environment, it would take too long (upto an hour) to start the application properly, as in, within 10 minutes. I could see the login page but if I try to login, it would just keep processing. Only after an hour or so, I would be able to login.
After some research I found that by default hibernate.temp.use_jdbc_metadata_defaults is set to true, in which case it takes time, so I set it to false. Now my application is starting up quickly in my local system when I point it to production db to test. Even in test environment it performs as expected. But when I rolled it out to production, it worked fine initially but now it again is taking too long to start up.
Any idea how to approach it now?
EDITED: adding more details:
initial startup time is huge. once it is up then pages would load fine. we are using postgres db and have multiple schemas. Please suggest what other details are needed
Below is session factory onfiguration:
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="mydb"/>
<property name="entityInterceptor" ref="nullToEmptyStringInterceptor" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</prop>
<prop key="hibernate.multiTenancy">SCHEMA</prop>
<prop key="hibernate.tenant_identifier_resolver">path_to.DataBaseResolver</prop>
<prop key="hibernate.multi_tenant_connection_provider">path_to.MultiTenantProvider</prop>
<prop key="hibernate.show_sql">false</prop>
<prop key="hibernate.temp.use_jdbc_metadata_defaults">false</prop>
</props>
</property>
<property name="packagesToScan">
<list>
<value>path_to_model_package</value>
</list>
</property>
</bean>
Below is entityManagerFactory configuration
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="mydb" />
<property name="jpaVendorAdapter" ref="jpaVendorAdapter" />
<property name="jpaDialect" ref="jpaDialect" />
<property name="persistenceUnitName" value="myPersistenceUnit" />
<property name="packagesToScan" >
<list>
<value>path_to_model_package</value>
</list>
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</prop>
<prop key="hibernate.temp.use_jdbc_metadata_defaults">false</prop>
<prop key="hibernate.jdbc.use_get_generated_keys" >true</prop>
</props>
</property>
</bean>

I don't think we can tell you what the problem is. It will be something to do what the applications is doing during startup, and we can only guess what that would be.
However ...
What you should do is to profile the application during startup, and use the profiling to identify where most of the time is being spent. Then look to see if you can work out what it its doing ... and optimize it.
It would also be work turning on GC logging to see if memory usage / garbage collection is part of the problem. Ditto for checking if database activity is a significant bottleneck.
Finally, an important step in finding the cause of this problem is likely to be understanding the internal architecture of the application. Especially if this is code that has been passed from developer to developer over a number of years.

As you did not posted full details of your problem, like hibernate, spring and other app configurations so suggesting you a solution is bit difficult. The following could be possibilities:
Somewhere there could be deadlock during application load time. For example, so batch job running in background before the container completely starts.
If your db schema is always checked to be updated after the container start and your db is having a large number of tables and columns with a lot of data inside then it would definitely take time before that application loading completes.
Check server configurations like if there is another instance of application running in parallel which is causing delay.

Related

Performance Issue after upgrading to Hibernate 5.0.2 - Tomcat Server start-up time increased

After upgrading Hibernate version from 4.3.9.Final to 5.0.2.Final, Tomcat Server start-up time has increased.
After debugging, I realized that hibernate takes too much time in adding mapping locations (*.hbm.xml files) in its metadata sources.
I have added mapping location in session factory using following code, and in my project there are around 1000 hbm.xml files.
<bean id="baseSessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop>
<prop key="hibernate.show_sql">false</prop>
<prop key="hibernate.cache.use_query_cache">true</prop>
<prop key="hibernate.jdbc.fetch_size">300</prop>
<prop key="net.sf.ehcache.configurationResourceName">/ehcache.xml</prop>
<prop key="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory</prop>
</props>
</property>
<property name="dataSource" ref="dataSource" />
<property name="mappingLocations">
<list>
<value>classpath*:com/*/**/*.hbm.xml</value>
</list>
</property>
</bean>
While starting tomcat server, I debugged and fournd that in method
org.springframework.orm.hibernate5.LocalSessionFactoryBean.afterPropertiesSet
following for loop takes too much time to add all mapping locations in metadata sources object of configuration class.
if (this.mappingLocations != null) {
// Register given Hibernate mapping definitions, contained in resource files.
for (Resource resource : this.mappingLocations) {
sfb.addInputStream(resource.getInputStream());
}
}
Is there any solution to improve performance here? Anyone noticed such issue after upgrading to Hibernate-5?

HSQL file based database from script

I have a question. I was playing around with JSF/ Spring/ Hibernate and HSQL.
I have a small test application for this purpose and for one feature I wanted to implement I needed a possiblity to persist some data. I didn't wanted to have a full fledged database, so I choose HSQL. Starting from this tutorial (http://devcrumb.com/hibernate/hibernate-jpa-spring-and-hsqldb) I build my application. I had some problems with datatypes and I have chosen to build my database from a script.
Like in the tuorial I had defined my datasource like this in my application.xml, except that I had changed the url property to use a file.
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName">
<value>org.hsqldb.jdbcDriver</value>
</property>
<property name="url">
<value>jdbc:hsqldb:hsql://localhost/testdb</value>
</property>
<property name="username">
<value>sa</value>
</property>
<property name="password">
<value></value>
</property>
</bean>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="persistenceUnitName" value="jpaData" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.HSQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">false</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>
</bean>
Now, I have changed the datasource to something like this:
<jdbc:embedded-database id="dataSource" type="HSQL">
<jdbc:script location="classpath:embeddedDbStructure.sql" />
</jdbc:embedded-database>
Everything works fine so far.
My problem is, that this database is deleted when the server is shut down. Is there a possibility to use both? A script as base for the structure of my database but the db itself is written to a file on my filesystem so that it is available after a server restart? I know there are propably a few solutions to achieve this via some code, but is there a possibility to configure it that way?
Thanks in advance
Actually for your case, you are using the hsqldb in-memory mode, the spring is house a inmemory database indeed. To reuse the file database you need to update the hsqldb mode to use the "In-Process Mode" like "jdbc:hsqldb:file:testdb"
And a sample question is Embedded HSQLDB persist data to a file, you can refer to this.

Spring app should start even though DB is down

I have a spring app which do minimal operations with DB.
And I have a requirment that my application should run under the absence of DB(or when db is down).Below is my datasource configuration.
<bean id="dt31DataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close" depends-on="systemPropertyInitializer"
p:driverClass="${dt31.driver_class}"
p:jdbcUrl="${dt31.url}"
p:user="${dt31.username}"
p:password="${dt31.password}"
p:idleConnectionTestPeriod="1000"
p:maxPoolSize="4"
p:minPoolSize="2"
p:maxIdleTime="2000"
p:unreturnedConnectionTimeout="600"
p:contextClassLoaderSource="library"
p:privilegeSpawnedThreads="true"
p:initialize=false
/>
<bean id="dt31SessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dt31DataSource"/>
<property name="packagesToScan" value="com.t22.dt31"/>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">
${dt31.dialect}
</prop>
<prop key="hibernate.show_sql">
false
</prop>
<prop key="hibernate.hbm2ddl.auto">
update
</prop>
</props>
</property>
</bean>
I found a page in google,saying to use "initialize: false" in spring data source configuration.But I am using "ComboPooledDataSource" datasource which does not have this property.Is there any other way to achieve this ?
The application service layer can operate with two DAO layers (file system and database), so when the DB is down you catch the connection acquire exception and switch to the file system instead.
Having two sources of truth is going to make it difficult to preserve consistency across two different data sources, especially if one resource is not available.
When both resources are available you can use XADisk and Bitronix for XADataSource and JTA transaction management.

Jersey Service Initialization with HIbernate default dataset

I have a stack that consists of Hibernate, Spring, and Jersey.
While a great deal of things are RESTFUL, not everything in our application is (and cannot be, for various reasons. I realize I break REST best practices in places.)
I need to do two things and cannot figure out how to make both happen.
in my application-context.xml I have the following
<!-- Configure the entity manager factory bean -->
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="jpaVendorAdapter" ref="hibernateJpaVendorAdapter"/>
<property name="packagesToScan" value="com.mystuff.model"/>
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</prop>
<prop key="hibernate.ejb.naming_strategy">org.hibernate.cfg.ImprovedNamingStrategy</prop>
<prop key="hibernate.format_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">create</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.hbm2ddl.import_files">data.sql</prop>
</props>
</property>
This normally loads some hibernate data into the database for me.
However, I also need to initialize some in memory structures in the service.
The moment i try to have my service extend ServletContainer and override initiate despite a call to super.initiate()
or implement AbstractResourceModelListener and then provide onLoaded(AbstractResourceModelContext modelContext)
I am getting null pointers because my initial data provided by data.sql is not there.
How can I do this correctly so I both get my data.sql loaded and can execute a few statements when the service is loaded?
(If anyone is curious, yes the service is a #Singleton)
Any help appreciated.
So, it turns out the right answer here, is to use #PostConstruct despite the warnings eclipse may give you about restrictions and libraries. I'm not sure why that warning appears, or why it proceeds to work anyways, but #PostConstruct is the way to go to not trash other loading in Spring.
(That said, if you aren't pinned in, doing the initialization outside and injecting it is more RESTFUL and better and not needing #Singleton, but I assume in both the question and answer that it isn't an option for you for whatever reason.)

Out of heap memory when executing <jdbc:initalize-database>

Context.xml
<jdbc:initialize-database data-source="dataSource" ignore-failures="ALL">
<jdbc:script location="classpath:scrubd.sql"/>
</jdbc:initialize-database>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.hsqldb.jdbc.JDBCDriver"/>
<property name="url" value="jdbc:hsqldb:mem:mydb"/>
<property name="username" value="sa"/>
<property name="password" value=""/>
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"
depends-on="dataSource"
name="_sessFac">
<property name="dataSource" ref="dataSource"/>
<property name="configLocation" value="hibernate.cfg.xml.incDTD"/>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.HSQLDialect</prop>
<prop key="hibernate.hbm2ddl.auto">create</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.connection.shutdown">true</prop>
</props>
</property>
</bean>
When I am running my ant target on my unit tests, after spring gets initialized the first time, I get an out of memory error. Yet, when I populate my tables by simply naming my database import.sql and letting hibernate handle it, I do not get this out of memory error.
Why does this happen?
Also, it takes Spring about a second longer to load the data in the database than hibernate. Bonus points to anyone that can explain why.
StackTrace (from ant)
Caused by: java.lang.OutOfMemoryError: Java heap space
at java.util.Arrays.copyOfRange(Arrays.java:2694)
at java.lang.String.<init>(String.java:234)
at java.lang.StringBuffer.toString(StringBuffer.java:561)
at org.apache.tools.ant.util.StringUtils.replace(StringUtils.java:92)
at org.apache.tools.ant.util.DOMElementWriter.encodedata(DOMElementWriter.java:501)
at org.apache.tools.ant.util.DOMElementWriter.write(DOMElementWriter.java:236)
at org.apache.tools.ant.util.DOMElementWriter.write(DOMElementWriter.java:221)
And the bean causing it has got to be my session factory, since I wouldn't call <jdbc:initialize-database/> a 'bean'.
I want to say based on the stack trace that it is reading the entirety of my sql script into a string, since it is quite large; ~38K lines.
Ended up just saying screw it, and letting hibernate populate my tables. The fact that I am now reading in a 20mB file when doing my unit tests, and I am still not getting an out of memory error with hibernate makes me think that if you want to populate your tables before doing unit tests on them, don't let spring do it. Live and learn.

Categories