Skip to content

Commit 93aefa8

Browse files
author
Phillip Webb
committed
Polish Flyway and Liquibase
Extract common "depends on" functionality to a new EntityManagerFactoryDependsOnPostProcessor class. Apply consistent formatting. Fix issue with Flyway location detection.
1 parent 4a6e66f commit 93aefa8

File tree

4 files changed

+173
-165
lines changed

4 files changed

+173
-165
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
/*
2+
* Copyright 2012-2014 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.autoconfigure.data.jpa;
18+
19+
import java.util.Arrays;
20+
import java.util.HashSet;
21+
import java.util.Set;
22+
23+
import javax.persistence.EntityManagerFactory;
24+
25+
import org.springframework.beans.factory.BeanFactory;
26+
import org.springframework.beans.factory.BeanFactoryUtils;
27+
import org.springframework.beans.factory.ListableBeanFactory;
28+
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
29+
import org.springframework.beans.factory.config.BeanDefinition;
30+
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
31+
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
32+
import org.springframework.orm.jpa.AbstractEntityManagerFactoryBean;
33+
import org.springframework.util.StringUtils;
34+
35+
/**
36+
* {@link BeanFactoryPostProcessor} that can be used to dynamically declare that all
37+
* {@link EntityManagerFactory} beans should "depend on" a specific bean.
38+
*
39+
* @author Marcel Overdijk
40+
* @author Dave Syer
41+
* @author Phillip Webb
42+
* @since 1.1.0
43+
* @see BeanDefinition#setDependsOn(String[])
44+
*/
45+
public class EntityManagerFactoryDependsOnPostProcessor implements
46+
BeanFactoryPostProcessor {
47+
48+
private final String dependsOn;
49+
50+
public EntityManagerFactoryDependsOnPostProcessor(String dependsOn) {
51+
this.dependsOn = dependsOn;
52+
}
53+
54+
@Override
55+
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
56+
for (String beanName : getEntityManagerFactoryBeanNames(beanFactory)) {
57+
BeanDefinition definition = getBeanDefinition(beanName, beanFactory);
58+
definition.setDependsOn(StringUtils.addStringToArray(
59+
definition.getDependsOn(), this.dependsOn));
60+
}
61+
}
62+
63+
private static BeanDefinition getBeanDefinition(String beanName,
64+
ConfigurableListableBeanFactory beanFactory) {
65+
try {
66+
return beanFactory.getBeanDefinition(beanName);
67+
}
68+
catch (NoSuchBeanDefinitionException ex) {
69+
BeanFactory parentBeanFactory = beanFactory.getParentBeanFactory();
70+
if (parentBeanFactory instanceof ConfigurableListableBeanFactory) {
71+
return getBeanDefinition(beanName,
72+
(ConfigurableListableBeanFactory) parentBeanFactory);
73+
}
74+
throw ex;
75+
}
76+
}
77+
78+
private Iterable<String> getEntityManagerFactoryBeanNames(
79+
ListableBeanFactory beanFactory) {
80+
Set<String> names = new HashSet<String>();
81+
names.addAll(Arrays.asList(BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
82+
beanFactory, EntityManagerFactory.class, true, false)));
83+
for (String factoryBeanName : BeanFactoryUtils
84+
.beanNamesForTypeIncludingAncestors(beanFactory,
85+
AbstractEntityManagerFactoryBean.class, true, false)) {
86+
names.add(BeanFactoryUtils.transformedBeanName(factoryBeanName));
87+
}
88+
return names;
89+
}
90+
91+
}

spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/flyway/FlywayAutoConfiguration.java

Lines changed: 20 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -16,49 +16,36 @@
1616

1717
package org.springframework.boot.autoconfigure.flyway;
1818

19-
import java.util.HashSet;
20-
import java.util.Set;
21-
2219
import javax.annotation.PostConstruct;
2320
import javax.persistence.EntityManagerFactory;
2421
import javax.sql.DataSource;
2522

2623
import org.flywaydb.core.Flyway;
27-
import org.springframework.beans.factory.BeanFactory;
28-
import org.springframework.beans.factory.ListableBeanFactory;
29-
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
3024
import org.springframework.beans.factory.annotation.Autowired;
31-
import org.springframework.beans.factory.config.BeanDefinition;
32-
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
33-
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
3425
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
3526
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
3627
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
3728
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
3829
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
3930
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
31+
import org.springframework.boot.autoconfigure.data.jpa.EntityManagerFactoryDependsOnPostProcessor;
4032
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
4133
import org.springframework.boot.context.properties.ConfigurationProperties;
4234
import org.springframework.boot.context.properties.EnableConfigurationProperties;
4335
import org.springframework.context.annotation.Bean;
4436
import org.springframework.context.annotation.Configuration;
4537
import org.springframework.context.annotation.Import;
4638
import org.springframework.core.io.DefaultResourceLoader;
47-
import org.springframework.core.io.Resource;
4839
import org.springframework.core.io.ResourceLoader;
4940
import org.springframework.orm.jpa.AbstractEntityManagerFactoryBean;
5041
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
5142
import org.springframework.util.Assert;
52-
import org.springframework.util.StringUtils;
53-
54-
import static java.util.Arrays.asList;
55-
import static org.springframework.beans.factory.BeanFactoryUtils.beanNamesForTypeIncludingAncestors;
56-
import static org.springframework.beans.factory.BeanFactoryUtils.transformedBeanName;
5743

5844
/**
5945
* {@link EnableAutoConfiguration Auto-configuration} for Flyway database migrations.
6046
*
6147
* @author Dave Syer
48+
* @author Phillip Webb
6249
* @since 1.1.0
6350
*/
6451
@Configuration
@@ -90,20 +77,24 @@ public static class FlywayConfiguration {
9077
@PostConstruct
9178
public void checkLocationExists() {
9279
if (this.properties.isCheckLocation()) {
93-
9480
Assert.state(!this.properties.getLocations().isEmpty(),
9581
"Migration script locations not configured");
96-
boolean exists = false;
97-
for (String location : this.properties.getLocations()) {
98-
Resource resource = this.resourceLoader.getResource(location);
99-
exists = (!exists && resource.exists());
100-
}
82+
boolean exists = hasAtLeastOneLocation();
10183
Assert.state(exists, "Cannot find migrations location in: "
10284
+ this.properties.getLocations()
10385
+ " (please add migrations or check your Flyway configuration)");
10486
}
10587
}
10688

89+
private boolean hasAtLeastOneLocation() {
90+
for (String location : this.properties.getLocations()) {
91+
if (this.resourceLoader.getResource(location).exists()) {
92+
return true;
93+
}
94+
}
95+
return false;
96+
}
97+
10798
@Bean(initMethod = "migrate")
10899
@ConfigurationProperties(prefix = "flyway")
109100
public Flyway flyway() {
@@ -124,55 +115,18 @@ else if (this.flywayDataSource != null) {
124115

125116
}
126117

118+
/**
119+
* Additional configuration to ensure that {@link EntityManagerFactory} beans
120+
* depend-on the liquibase bean.
121+
*/
127122
@Configuration
128123
@ConditionalOnClass(LocalContainerEntityManagerFactoryBean.class)
129124
@ConditionalOnBean(AbstractEntityManagerFactoryBean.class)
130-
protected static class FlywayJpaDependencyConfiguration implements
131-
BeanFactoryPostProcessor {
132-
133-
public static final String FLYWAY_JPA_BEAN_NAME = "flyway";
134-
135-
@Override
136-
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
137-
138-
for (String beanName : getEntityManagerFactoryBeanNames(beanFactory)) {
139-
BeanDefinition definition = getBeanDefinition(beanName, beanFactory);
140-
definition.setDependsOn(StringUtils.addStringToArray(
141-
definition.getDependsOn(), FLYWAY_JPA_BEAN_NAME));
142-
}
143-
}
144-
145-
private static BeanDefinition getBeanDefinition(String beanName,
146-
ConfigurableListableBeanFactory beanFactory) {
147-
try {
148-
return beanFactory.getBeanDefinition(beanName);
149-
}
150-
catch (NoSuchBeanDefinitionException e) {
151-
152-
BeanFactory parentBeanFactory = beanFactory.getParentBeanFactory();
153-
154-
if (parentBeanFactory instanceof ConfigurableListableBeanFactory) {
155-
return getBeanDefinition(beanName,
156-
(ConfigurableListableBeanFactory) parentBeanFactory);
157-
}
158-
159-
throw e;
160-
}
161-
}
162-
163-
private static Iterable<String> getEntityManagerFactoryBeanNames(
164-
ListableBeanFactory beanFactory) {
165-
166-
Set<String> names = new HashSet<String>();
167-
names.addAll(asList(beanNamesForTypeIncludingAncestors(beanFactory,
168-
EntityManagerFactory.class, true, false)));
169-
170-
for (String factoryBeanName : beanNamesForTypeIncludingAncestors(beanFactory,
171-
AbstractEntityManagerFactoryBean.class, true, false)) {
172-
names.add(transformedBeanName(factoryBeanName));
173-
}
125+
protected static class FlywayJpaDependencyConfiguration extends
126+
EntityManagerFactoryDependsOnPostProcessor {
174127

175-
return names;
128+
public FlywayJpaDependencyConfiguration() {
129+
super("flyway");
176130
}
177131

178132
}

spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/liquibase/LiquibaseAutoConfiguration.java

Lines changed: 12 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -16,28 +16,20 @@
1616

1717
package org.springframework.boot.autoconfigure.liquibase;
1818

19-
import java.util.HashSet;
20-
import java.util.Set;
21-
2219
import javax.annotation.PostConstruct;
2320
import javax.persistence.EntityManagerFactory;
2421
import javax.sql.DataSource;
2522

2623
import liquibase.integration.spring.SpringLiquibase;
2724

28-
import org.springframework.beans.factory.BeanFactory;
29-
import org.springframework.beans.factory.ListableBeanFactory;
30-
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
3125
import org.springframework.beans.factory.annotation.Autowired;
32-
import org.springframework.beans.factory.config.BeanDefinition;
33-
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
34-
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
3526
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
3627
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
3728
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
3829
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
3930
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
4031
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
32+
import org.springframework.boot.autoconfigure.data.jpa.EntityManagerFactoryDependsOnPostProcessor;
4133
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
4234
import org.springframework.boot.context.properties.EnableConfigurationProperties;
4335
import org.springframework.context.annotation.Bean;
@@ -49,17 +41,13 @@
4941
import org.springframework.orm.jpa.AbstractEntityManagerFactoryBean;
5042
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
5143
import org.springframework.util.Assert;
52-
import org.springframework.util.StringUtils;
53-
54-
import static java.util.Arrays.asList;
55-
import static org.springframework.beans.factory.BeanFactoryUtils.beanNamesForTypeIncludingAncestors;
56-
import static org.springframework.beans.factory.BeanFactoryUtils.transformedBeanName;
5744

5845
/**
5946
* {@link EnableAutoConfiguration Auto-configuration} for Liquibase.
6047
*
6148
* @author Marcel Overdijk
6249
* @author Dave Syer
50+
* @author Phillip Webb
6351
* @since 1.1.0
6452
*/
6553
@Configuration
@@ -90,8 +78,8 @@ public void checkChangelogExists() {
9078
Resource resource = this.resourceLoader.getResource(this.properties
9179
.getChangeLog());
9280
Assert.state(resource.exists(), "Cannot find changelog location: "
93-
+ resource
94-
+ " (please add changelog or check your Liquibase configuration)");
81+
+ resource + " (please add changelog or check your Liquibase "
82+
+ "configuration)");
9583
}
9684
}
9785

@@ -108,55 +96,18 @@ public SpringLiquibase liquibase() {
10896
}
10997
}
11098

99+
/**
100+
* Additional configuration to ensure that {@link EntityManagerFactory} beans
101+
* depend-on the liquibase bean.
102+
*/
111103
@Configuration
112104
@ConditionalOnClass(LocalContainerEntityManagerFactoryBean.class)
113105
@ConditionalOnBean(AbstractEntityManagerFactoryBean.class)
114-
protected static class LiquibaseJpaDependencyConfiguration implements
115-
BeanFactoryPostProcessor {
116-
117-
public static final String LIQUIBASE_JPA_BEAN_NAME = "liquibase";
118-
119-
@Override
120-
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
121-
122-
for (String beanName : getEntityManagerFactoryBeanNames(beanFactory)) {
123-
BeanDefinition definition = getBeanDefinition(beanName, beanFactory);
124-
definition.setDependsOn(StringUtils.addStringToArray(
125-
definition.getDependsOn(), LIQUIBASE_JPA_BEAN_NAME));
126-
}
127-
}
128-
129-
private static BeanDefinition getBeanDefinition(String beanName,
130-
ConfigurableListableBeanFactory beanFactory) {
131-
try {
132-
return beanFactory.getBeanDefinition(beanName);
133-
}
134-
catch (NoSuchBeanDefinitionException e) {
135-
136-
BeanFactory parentBeanFactory = beanFactory.getParentBeanFactory();
137-
138-
if (parentBeanFactory instanceof ConfigurableListableBeanFactory) {
139-
return getBeanDefinition(beanName,
140-
(ConfigurableListableBeanFactory) parentBeanFactory);
141-
}
142-
143-
throw e;
144-
}
145-
}
146-
147-
private static Iterable<String> getEntityManagerFactoryBeanNames(
148-
ListableBeanFactory beanFactory) {
149-
150-
Set<String> names = new HashSet<String>();
151-
names.addAll(asList(beanNamesForTypeIncludingAncestors(beanFactory,
152-
EntityManagerFactory.class, true, false)));
153-
154-
for (String factoryBeanName : beanNamesForTypeIncludingAncestors(beanFactory,
155-
AbstractEntityManagerFactoryBean.class, true, false)) {
156-
names.add(transformedBeanName(factoryBeanName));
157-
}
106+
protected static class LiquibaseJpaDependencyConfiguration extends
107+
EntityManagerFactoryDependsOnPostProcessor {
158108

159-
return names;
109+
public LiquibaseJpaDependencyConfiguration() {
110+
super("liquibase");
160111
}
161112

162113
}

0 commit comments

Comments
 (0)