Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring Hibernate: reload entity mappings

on a web application we use Spring 3.2 and Hibernate 4.1.1 and implement a plugin-like architecture. Plugins can be added and removed on runtime. For each module we defined a separate class loader and create separate child application context on spring. Complete configuration is done using annotations, no XML config for the beans anymore.

Spring Hibernate configuration class

@Configuration
@EnableTransactionManagement
public class HibernateConfigurationFactory {

@Bean
public JndiObjectFactoryBean dataSource() {
    JndiObjectFactoryBean ds = new JndiObjectFactoryBean();
    ds.setJndiName("java:jboss/datasources/OurOwnDS");
    ds.setResourceRef(true);
    return ds;
}

@Bean
public LocalSessionFactoryBean sessionFactory() {
    LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
    sessionFactory.setPackagesToScan("com.foo.bar");
    sessionFactory.setDataSource((DataSource) dataSource().getObject());

    Properties hibernateProperties = new Properties();
    hibernateProperties.put("hibernate.hbm2ddl.auto", "update");

    sessionFactory.setHibernateProperties(hibernateProperties);

    return sessionFactory;
}

@Bean
public HibernateTransactionManager transactionManager() {
    HibernateTransactionManager transactionManager = new HibernateTransactionManager();
    transactionManager.setSessionFactory(sessionFactory().getObject());
    return transactionManager;
}

}

Now the problem: Some plugins contain their own entity (+DAO) classes which are added with the module during runtime.

Is it possible to create some kind of separate context on hibernate (as we do it on spring) or even add/reload the additional entity classes?

Will reloading the EntityManager fit my needs? But what will happen to already loaded entities in the context?

Thanks for any help and comment in advance.

Update: Actually i did the following and solved the issue (but ran into an other issue.. later on).

I create a new DataSource + SessionFactory + TransactionManager for each module/context and insert them to the new child ApplicationContext. Now i use the class loader to scann for all annotated classes and register them manually on the application context and the session factory by using

LocalSessionFactorybean#setAnnotatedClasses(...)

This works quite well... but...

Next Problem: I get a ClassNotFoundException which seems to be a class loader issue. Hibernate uses the system class loader instead of my own pluginClassloader.

Does someone know how to inject own class loader to Hibernate?

like image 272
NeoP5 Avatar asked Oct 20 '22 12:10

NeoP5


1 Answers

Is it feasible to inject Environment and use it as an extra source for Hibernate resources?

@Configuration
@EnableTransactionManagement
public class HibernateConfigurationFactory {

    @Autowired
    Environment env;

    @Bean 
    public LocalSessionFactoryBean sessionFactory() {
        LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
        sessionFactory.setPackagesToScan("com.foo.bar");
        if (env.containsProperty("some.extra.classes.property") {
            sessionFactory.setAnnotatedClasses(some extrapolation here);
            // Or similarly add extra packages for scanning
            ...
        }
    }
}

As for the extra DAO beans, you can use @Profile for that, or - if using Spring 4 - use @Conditional.

EDIT

The Environment is not something you create, it's "there for you" . It's basically a container for Property Source and Profile sets.

A Good reference point is Spring reference documentation, the IoC container chapter. Also you can look at the SpringSource blog. There are few good article by Chris Beams, related to Spring 3.1, but most of the stuff is there.

As an example, you can use something as bellow to bootstrap a child application context:

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
ConfigurableEnvironment environment = context.getEnvironment();

// this is how you set different properties per a sub context. 
Map subContextMap = new HashMap();
subContextMap.put("some.extra.classes.property", [unique value here]);
environment.getPropertySources().addFirst(new MapPropertySource("SUB_CTX_MAP", subContextMap);

// this is the generic configuration class(es).
context.register(HibernateConfigurationFactory.class);

context.refresh();
like image 94
Ori Dar Avatar answered Oct 27 '22 23:10

Ori Dar