Register hazelcast post processor only when necessary
Commit 8e0a94f
introduced a post processor that adds an explicit link
between the `HazelcastInstance` and the `EntityManagerFactory` so that
Hazelcast is fully initialized before Hibernate actually kicks in.
Unfortunately, the conditions that were implemented to register this post
processor are wrong and any app that has both JPA and Hazelcast support
blows up if no bean with name `hazelcastInstance` is defined.
This commit fixes the situation and reworks the configuration in a
separate auto-configuration that runs after the Hazelcast and JPA support
and check both the presence of an `EntityManagerFactory` and a bean of
name `hazelcastInstance`. If any of those conditions does not apply the
post processor is no longer registered.
Closes gh-4158
pull/3817/merge
parent
195880c7c0
commit
157c0b6cae
@ -0,0 +1,79 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012-2015 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.springframework.boot.autoconfigure.hazelcast;
|
||||||
|
|
||||||
|
import javax.persistence.EntityManagerFactory;
|
||||||
|
|
||||||
|
import com.hazelcast.core.HazelcastInstance;
|
||||||
|
|
||||||
|
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.AllNestedConditions;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||||
|
import org.springframework.boot.autoconfigure.data.jpa.EntityManagerFactoryDependsOnPostProcessor;
|
||||||
|
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Conditional;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.orm.jpa.AbstractEntityManagerFactoryBean;
|
||||||
|
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Additional configuration to ensure that {@link EntityManagerFactory} beans
|
||||||
|
* depend-on the {@code hazelcastInstance} bean.
|
||||||
|
*
|
||||||
|
* @author Stephane Nicoll
|
||||||
|
* @since 1.3.0
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
@ConditionalOnClass({ HazelcastInstance.class, LocalContainerEntityManagerFactoryBean.class })
|
||||||
|
@AutoConfigureAfter({ HazelcastAutoConfiguration.class, HibernateJpaAutoConfiguration.class })
|
||||||
|
class HazelcastJpaDependencyAutoConfiguration {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@Conditional(OnHazelcastAndJpaCondition.class)
|
||||||
|
public static HazelcastInstanceJpaDependencyPostProcessor hazelcastInstanceJpaDependencyPostProcessor() {
|
||||||
|
return new HazelcastInstanceJpaDependencyPostProcessor();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class HazelcastInstanceJpaDependencyPostProcessor
|
||||||
|
extends EntityManagerFactoryDependsOnPostProcessor {
|
||||||
|
|
||||||
|
HazelcastInstanceJpaDependencyPostProcessor() {
|
||||||
|
super("hazelcastInstance");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class OnHazelcastAndJpaCondition extends AllNestedConditions {
|
||||||
|
|
||||||
|
OnHazelcastAndJpaCondition() {
|
||||||
|
super(ConfigurationPhase.REGISTER_BEAN);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ConditionalOnBean(name = "hazelcastInstance")
|
||||||
|
static class HasHazelcastInstance {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@ConditionalOnBean(AbstractEntityManagerFactoryBean.class)
|
||||||
|
static class HasJpa {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,128 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012-2015 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.springframework.boot.autoconfigure.hazelcast;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.hazelcast.core.HazelcastInstance;
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import org.springframework.boot.autoconfigure.data.jpa.EntityManagerFactoryDependsOnPostProcessor;
|
||||||
|
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
|
||||||
|
import org.springframework.boot.autoconfigure.jdbc.EmbeddedDataSourceConfiguration;
|
||||||
|
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
|
||||||
|
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
import static org.hamcrest.CoreMatchers.not;
|
||||||
|
import static org.hamcrest.Matchers.hasItem;
|
||||||
|
import static org.hamcrest.Matchers.hasKey;
|
||||||
|
import static org.junit.Assert.assertThat;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for {@link HazelcastJpaDependencyAutoConfiguration}.
|
||||||
|
*
|
||||||
|
* @author Stephane Nicoll
|
||||||
|
*/
|
||||||
|
public class HazelcastJpaDependencyAutoConfigurationTests {
|
||||||
|
|
||||||
|
private AnnotationConfigApplicationContext context;
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void closeContext() {
|
||||||
|
if (this.context != null) {
|
||||||
|
this.context.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void registrationIfHazelcastInstanceHasRegularBeanName() {
|
||||||
|
load(HazelcastConfiguration.class);
|
||||||
|
assertThat(this.context.getBeansOfType(EntityManagerFactoryDependsOnPostProcessor.class),
|
||||||
|
hasKey("hazelcastInstanceJpaDependencyPostProcessor"));
|
||||||
|
assertThat(getEntityManagerFactoryDependencies(), hasItem("hazelcastInstance"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void noRegistrationIfHazelcastInstanceHasCustomBeanName() {
|
||||||
|
load(HazelcastCustomNameConfiguration.class);
|
||||||
|
assertThat(getEntityManagerFactoryDependencies(), not(hasItem("hazelcastInstance")));
|
||||||
|
assertThat(this.context.getBeansOfType(EntityManagerFactoryDependsOnPostProcessor.class),
|
||||||
|
not(hasKey("hazelcastInstanceJpaDependencyPostProcessor")));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void noRegistrationWithNoHazelcastInstance() {
|
||||||
|
load(null);
|
||||||
|
assertThat(getEntityManagerFactoryDependencies(), not(hasItem("hazelcastInstance")));
|
||||||
|
assertThat(this.context.getBeansOfType(EntityManagerFactoryDependsOnPostProcessor.class),
|
||||||
|
not(hasKey("hazelcastInstanceJpaDependencyPostProcessor")));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void noRegistrationWithNoEntityManagerFactory() {
|
||||||
|
this.context = new AnnotationConfigApplicationContext();
|
||||||
|
this.context.register(HazelcastConfiguration.class,
|
||||||
|
HazelcastJpaDependencyAutoConfiguration.class);
|
||||||
|
this.context.refresh();
|
||||||
|
assertThat(this.context.getBeansOfType(EntityManagerFactoryDependsOnPostProcessor.class),
|
||||||
|
not(hasKey("hazelcastInstanceJpaDependencyPostProcessor")));
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<String> getEntityManagerFactoryDependencies() {
|
||||||
|
String[] dependsOn = this.context.getBeanDefinition("entityManagerFactory").getDependsOn();
|
||||||
|
return dependsOn != null ? Arrays.asList(dependsOn) : Collections.<String>emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void load(Class<?> config) {
|
||||||
|
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
||||||
|
if (config != null) {
|
||||||
|
ctx.register(config);
|
||||||
|
}
|
||||||
|
ctx.register(EmbeddedDataSourceConfiguration.class,
|
||||||
|
DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class);
|
||||||
|
ctx.register(HazelcastJpaDependencyAutoConfiguration.class);
|
||||||
|
ctx.refresh();
|
||||||
|
this.context = ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
static class HazelcastConfiguration {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public HazelcastInstance hazelcastInstance() {
|
||||||
|
return mock(HazelcastInstance.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
static class HazelcastCustomNameConfiguration {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public HazelcastInstance myHazelcastInstance() {
|
||||||
|
return mock(HazelcastInstance.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue