Lately I have been maintaining several Spring-MVC applications written from the ground up with Spring 3.1. They use the purely Java based configuration scheme that comes in version 3.1, Hibernate. The apps do not have the pattern of "an interface for every class" that some Spring apps have, so it proxies concrete classes using Cglib. When the apps are deployed to Tomcat, we do a full instance restart, but when developing inside of Eclipse JEE and the embedded Tomcat instance, after about 5 redeploys the apps will crash due to running out of perm gen space.
When we created these services, I relied heavily on several blog posts detailing how to do Spring without XML. One of these posts suggested setting up Hibernate like so:
@Bean public AbstractSessionFactoryBean mySessionFactory() { AnnotationSessionFactoryBean b = new AnnotationSessionFactoryBean(); b.setDataSource(dataSource); b.setPackagesToScan(new String[] { this.getClass().getPackage().getName() + ".model" }); Properties hiberProps = new Properties(); hiberProps.setProperty("hibernate.show_sql", Boolean.toString(hibernateShowSql)); hiberProps.setProperty("hibernate.dialect", hibernateDialect); b.setHibernateProperties(hiberProps); return b; } @Bean public AbstractPlatformTransactionManager transactionManager() { HibernateTransactionManager tm = new HibernateTransactionManager(); tm.setSessionFactory(mySessionFactory().getObject());//Error is here return tm; }
The problem seems to arise in transactionManager() - it calls mySessionFactory(), without using the actual bean. My understanding of Spring is still not the greatest, but even with all of the magic that Spring performs, I do believe this leaves two instances of AbstractSessionFactoryBean in memory - one directly in Spring's context, the other hidden inside the HibernateTransactionManager. One of these two is not collected properly on a Tomcat redeploy, causing the entire classloader to get stuck in permgen.
Changing to the following has fixed the issue:
@Bean public AbstractSessionFactoryBean paymentSessionFactory() {/* no change */} @Bean @Autowired //Added this public AbstractPlatformTransactionManager transactionManager(AbstractSessionFactoryBean bean) {//Added parameter HibernateTransactionManager tm = new HibernateTransactionManager(); tm.setSessionFactory(bean.getObject());//Changed this return tm; }
Dan, could you post more complete source code of your spring / hibernate java configuration?
I want to translate your solution to fix my xml spring configuration because I have permgem problem with tomcat/spring3.1/hibernate4(jpa2) using xml.
Thanks in advance.