Skip to content

Commit 55233eb

Browse files
committed
Merge pull request #8881 from vpavic:integration-jdbc
* pr/8881: Polish "Add database initializer for Spring Integration" Add database initializer for Spring Integration
2 parents 50b3b30 + 3e60ec6 commit 55233eb

File tree

7 files changed

+253
-10
lines changed

7 files changed

+253
-10
lines changed

spring-boot-autoconfigure/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,11 @@
329329
<artifactId>spring-integration-core</artifactId>
330330
<optional>true</optional>
331331
</dependency>
332+
<dependency>
333+
<groupId>org.springframework.integration</groupId>
334+
<artifactId>spring-integration-jdbc</artifactId>
335+
<optional>true</optional>
336+
</dependency>
332337
<dependency>
333338
<groupId>org.springframework.integration</groupId>
334339
<artifactId>spring-integration-jmx</artifactId>

spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/integration/IntegrationAutoConfiguration.java

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2016 the original author or authors.
2+
* Copyright 2012-2017 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -17,6 +17,7 @@
1717
package org.springframework.boot.autoconfigure.integration;
1818

1919
import javax.management.MBeanServer;
20+
import javax.sql.DataSource;
2021

2122
import org.springframework.beans.BeansException;
2223
import org.springframework.beans.factory.BeanFactory;
@@ -25,17 +26,21 @@
2526
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
2627
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
2728
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
29+
import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;
2830
import org.springframework.boot.autoconfigure.condition.SearchStrategy;
2931
import org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration;
3032
import org.springframework.boot.bind.RelaxedPropertyResolver;
33+
import org.springframework.boot.context.properties.EnableConfigurationProperties;
3134
import org.springframework.context.EnvironmentAware;
3235
import org.springframework.context.annotation.Bean;
3336
import org.springframework.context.annotation.Configuration;
3437
import org.springframework.context.annotation.Import;
3538
import org.springframework.core.env.Environment;
39+
import org.springframework.core.io.ResourceLoader;
3640
import org.springframework.integration.config.EnableIntegration;
3741
import org.springframework.integration.config.EnableIntegrationManagement;
3842
import org.springframework.integration.gateway.GatewayProxyFactoryBean;
43+
import org.springframework.integration.jdbc.store.JdbcMessageStore;
3944
import org.springframework.integration.jmx.config.EnableIntegrationMBeanExport;
4045
import org.springframework.integration.monitor.IntegrationMBeanExporter;
4146
import org.springframework.integration.support.management.IntegrationManagementConfigurer;
@@ -48,10 +53,12 @@
4853
* @author Artem Bilan
4954
* @author Dave Syer
5055
* @author Stephane Nicoll
56+
* @author Vedran Pavic
5157
* @since 1.1.0
5258
*/
5359
@Configuration
5460
@ConditionalOnClass(EnableIntegration.class)
61+
@EnableConfigurationProperties(IntegrationProperties.class)
5562
@AutoConfigureAfter(JmxAutoConfiguration.class)
5663
public class IntegrationAutoConfiguration {
5764

@@ -131,4 +138,24 @@ protected static class IntegrationComponentScanAutoConfiguration {
131138

132139
}
133140

141+
/**
142+
* Integration JDBC configuration.
143+
*/
144+
@Configuration
145+
@ConditionalOnClass(JdbcMessageStore.class)
146+
@ConditionalOnSingleCandidate(DataSource.class)
147+
protected static class IntegrationJdbcConfiguration {
148+
149+
@Bean
150+
@ConditionalOnMissingBean
151+
@ConditionalOnProperty(prefix = "spring.integration.jdbc.initializer", name = "enabled")
152+
public IntegrationDatabaseInitializer integrationDatabaseInitializer(
153+
DataSource dataSource, ResourceLoader resourceLoader,
154+
IntegrationProperties properties) {
155+
return new IntegrationDatabaseInitializer(dataSource, resourceLoader,
156+
properties);
157+
}
158+
159+
}
160+
134161
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/*
2+
* Copyright 2012-2017 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.integration;
18+
19+
import javax.sql.DataSource;
20+
21+
import org.springframework.boot.autoconfigure.AbstractDatabaseInitializer;
22+
import org.springframework.core.io.ResourceLoader;
23+
import org.springframework.util.Assert;
24+
25+
/**
26+
* Initializer for Spring Integration schema.
27+
*
28+
* @author Vedran Pavic
29+
* @since 2.0.0
30+
*/
31+
public class IntegrationDatabaseInitializer extends AbstractDatabaseInitializer {
32+
33+
private final IntegrationProperties.Jdbc properties;
34+
35+
public IntegrationDatabaseInitializer(DataSource dataSource,
36+
ResourceLoader resourceLoader, IntegrationProperties properties) {
37+
super(dataSource, resourceLoader);
38+
Assert.notNull(properties, "IntegrationProperties must not be null");
39+
this.properties = properties.getJdbc();
40+
}
41+
42+
@Override
43+
protected boolean isEnabled() {
44+
return this.properties.getInitializer().isEnabled();
45+
}
46+
47+
@Override
48+
protected String getSchemaLocation() {
49+
return this.properties.getSchema();
50+
}
51+
52+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
/*
2+
* Copyright 2012-2017 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.integration;
18+
19+
import org.springframework.boot.context.properties.ConfigurationProperties;
20+
21+
/**
22+
* Configuration properties for Spring Integration.
23+
*
24+
* @author Vedran Pavic
25+
* @author Stephane Nicoll
26+
* @since 2.0.0
27+
*/
28+
@ConfigurationProperties(prefix = "spring.integration")
29+
public class IntegrationProperties {
30+
31+
private final Jdbc jdbc = new Jdbc();
32+
33+
public Jdbc getJdbc() {
34+
return this.jdbc;
35+
}
36+
37+
public static class Jdbc {
38+
39+
private static final String DEFAULT_SCHEMA_LOCATION = "classpath:org/springframework/"
40+
+ "integration/jdbc/schema-@@platform@@.sql";
41+
42+
/**
43+
* Path to the SQL file to use to initialize the database schema.
44+
*/
45+
private String schema = DEFAULT_SCHEMA_LOCATION;
46+
47+
private final Initializer initializer = new Initializer();
48+
49+
public String getSchema() {
50+
return this.schema;
51+
}
52+
53+
public void setSchema(String schema) {
54+
this.schema = schema;
55+
}
56+
57+
public Initializer getInitializer() {
58+
return this.initializer;
59+
}
60+
61+
public class Initializer {
62+
63+
/**
64+
* Create the required integration tables on startup.
65+
*/
66+
private boolean enabled = false;
67+
68+
public boolean isEnabled() {
69+
return this.enabled;
70+
}
71+
72+
public void setEnabled(boolean enabled) {
73+
this.enabled = enabled;
74+
}
75+
76+
}
77+
78+
}
79+
80+
}

spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/integration/IntegrationAutoConfigurationTests.java

Lines changed: 68 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2016 the original author or authors.
2+
* Copyright 2012-2017 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -22,10 +22,16 @@
2222
import javax.management.MBeanServer;
2323

2424
import org.junit.After;
25+
import org.junit.Rule;
2526
import org.junit.Test;
27+
import org.junit.rules.ExpectedException;
2628

2729
import org.springframework.boot.autoconfigure.integration.IntegrationAutoConfiguration.IntegrationComponentScanAutoConfiguration;
30+
import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration;
31+
import org.springframework.boot.autoconfigure.jdbc.EmbeddedDataSourceConfiguration;
32+
import org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration;
2833
import org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration;
34+
import org.springframework.boot.test.util.EnvironmentTestUtils;
2935
import org.springframework.context.ConfigurableApplicationContext;
3036
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
3137
import org.springframework.context.annotation.Bean;
@@ -36,6 +42,8 @@
3642
import org.springframework.integration.gateway.RequestReplyExchanger;
3743
import org.springframework.integration.support.channel.HeaderChannelRegistry;
3844
import org.springframework.integration.support.management.IntegrationManagementConfigurer;
45+
import org.springframework.jdbc.BadSqlGrammarException;
46+
import org.springframework.jdbc.core.JdbcOperations;
3947
import org.springframework.jmx.export.MBeanExporter;
4048
import org.springframework.test.context.support.TestPropertySourceUtils;
4149

@@ -47,9 +55,13 @@
4755
*
4856
* @author Artem Bilan
4957
* @author Stephane Nicoll
58+
* @author Vedran Pavic
5059
*/
5160
public class IntegrationAutoConfigurationTests {
5261

62+
@Rule
63+
public ExpectedException thrown = ExpectedException.none();
64+
5365
private AnnotationConfigApplicationContext context;
5466

5567
@After
@@ -126,12 +138,62 @@ public void customizeJmxDomain() {
126138

127139
@Test
128140
public void primaryExporterIsAllowed() {
129-
load(CustomMBeanExporter.class);
141+
load(new Class[] { CustomMBeanExporter.class });
130142
assertThat(this.context.getBeansOfType(MBeanExporter.class)).hasSize(2);
131143
assertThat(this.context.getBean(MBeanExporter.class))
132144
.isSameAs(this.context.getBean("myMBeanExporter"));
133145
}
134146

147+
@Test
148+
public void integrationJdbcDatabaseInitializerEnabled() {
149+
load(new Class[] { EmbeddedDataSourceConfiguration.class,
150+
DataSourceTransactionManagerAutoConfiguration.class,
151+
JdbcTemplateAutoConfiguration.class,
152+
IntegrationAutoConfiguration.class},
153+
"spring.datasource.generate-unique-name=true",
154+
"spring.integration.jdbc.initializer.enabled=true");
155+
assertThat(this.context.getBean(IntegrationProperties.class).getJdbc()
156+
.getInitializer().isEnabled()).isTrue();
157+
JdbcOperations jdbcOperations = this.context.getBean(JdbcOperations.class);
158+
assertThat(jdbcOperations.queryForList("select * from INT_MESSAGE")).isEmpty();
159+
assertThat(jdbcOperations.queryForList("select * from INT_GROUP_TO_MESSAGE"))
160+
.isEmpty();
161+
assertThat(jdbcOperations.queryForList("select * from INT_MESSAGE_GROUP"))
162+
.isEmpty();
163+
assertThat(jdbcOperations.queryForList("select * from INT_LOCK")).isEmpty();
164+
assertThat(jdbcOperations.queryForList("select * from INT_CHANNEL_MESSAGE"))
165+
.isEmpty();
166+
}
167+
168+
@Test
169+
public void integrationJdbcDatabaseInitializerDisabled() {
170+
load(new Class[] { EmbeddedDataSourceConfiguration.class,
171+
DataSourceTransactionManagerAutoConfiguration.class,
172+
JdbcTemplateAutoConfiguration.class,
173+
IntegrationAutoConfiguration.class },
174+
"spring.datasource.generate-unique-name=true",
175+
"spring.integration.jdbc.initializer.enabled=false");
176+
assertThat(this.context.getBean(IntegrationProperties.class).getJdbc()
177+
.getInitializer().isEnabled()).isFalse();
178+
JdbcOperations jdbcOperations = this.context.getBean(JdbcOperations.class);
179+
this.thrown.expect(BadSqlGrammarException.class);
180+
jdbcOperations.queryForList("select * from INT_MESSAGE");
181+
}
182+
183+
@Test
184+
public void integrationJdbcDatabaseInitializerDisabledByDefault() {
185+
load(new Class[] { EmbeddedDataSourceConfiguration.class,
186+
DataSourceTransactionManagerAutoConfiguration.class,
187+
JdbcTemplateAutoConfiguration.class,
188+
IntegrationAutoConfiguration.class },
189+
"spring.datasource.generate-unique-name=true");
190+
assertThat(this.context.getBean(IntegrationProperties.class).getJdbc()
191+
.getInitializer().isEnabled()).isFalse();
192+
JdbcOperations jdbcOperations = this.context.getBean(JdbcOperations.class);
193+
this.thrown.expect(BadSqlGrammarException.class);
194+
jdbcOperations.queryForList("select * from INT_MESSAGE");
195+
}
196+
135197
private static void assertDomains(MBeanServer mBeanServer, boolean expected,
136198
String... domains) {
137199
List<String> actual = Arrays.asList(mBeanServer.getDomains());
@@ -144,12 +206,12 @@ public void load(String... environment) {
144206
load(null, environment);
145207
}
146208

147-
private void load(Class<?> config, String... environment) {
209+
private void load(Class<?>[] configs, String... environment) {
148210
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
149-
if (config != null) {
150-
ctx.register(config);
211+
EnvironmentTestUtils.addEnvironment(ctx, environment);
212+
if (configs != null) {
213+
ctx.register(configs);
151214
}
152-
TestPropertySourceUtils.addInlinedPropertiesToEnvironment(ctx, environment);
153215
ctx.register(JmxAutoConfiguration.class, IntegrationAutoConfiguration.class);
154216
ctx.refresh();
155217
this.context = ctx;

spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -890,6 +890,10 @@ content into your application; rather pick only the properties that you need.
890890
spring.batch.schema=classpath:org/springframework/batch/core/schema-@@platform@@.sql # Path to the SQL file to use to initialize the database schema.
891891
spring.batch.table-prefix= # Table prefix for all the batch meta-data tables.
892892
893+
# SPRING INTEGRATION ({sc-spring-boot-autoconfigure}/integration/IntegrationProperties.{sc-ext}[IntegrationProperties])
894+
spring.integration.jdbc.initializer.enabled=false # Create the required integration tables on startup.
895+
spring.integration.jdbc.schema=classpath:org/springframework/integration/jdbc/schema-@@platform@@.sql # Path to the SQL file to use to initialize the database schema.
896+
893897
# JMS ({sc-spring-boot-autoconfigure}/jms/JmsProperties.{sc-ext}[JmsProperties])
894898
spring.jms.jndi-name= # Connection factory JNDI name. When set, takes precedence to others connection factory auto-configurations.
895899
spring.jms.listener.acknowledge-mode= # Acknowledge mode of the container. By default, the listener is transacted with automatic acknowledgment.

spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5113,10 +5113,23 @@ Spring Boot offers several conveniences for working with Spring Integration, inc
51135113
the `spring-boot-starter-integration` '`Starter`'. Spring Integration provides
51145114
abstractions over messaging and also other transports such as HTTP, TCP etc. If Spring
51155115
Integration is available on your classpath it will be initialized through the
5116-
`@EnableIntegration` annotation. Message processing statistics will be published over JMX
5117-
if `'spring-integration-jmx'` is also on the classpath. See the
5116+
`@EnableIntegration` annotation.
5117+
5118+
Spring Boot will also configure some features that are triggered by the presence of
5119+
additional Spring Integration modules. Message processing statistics will be published
5120+
over JMX if `'spring-integration-jmx'` is also on the classpath. If
5121+
`'spring-integration-jdbc'` is available, the default database schema can be created
5122+
on startup:
5123+
5124+
[source,properties,indent=0]
5125+
----
5126+
spring.integration.jdbc.initializer.enabled=true
5127+
----
5128+
5129+
See the
51185130
{sc-spring-boot-autoconfigure}/integration/IntegrationAutoConfiguration.{sc-ext}[`IntegrationAutoConfiguration`]
5119-
class for more details.
5131+
and {sc-spring-boot-autoconfigure}/integration/IntegrationProperties.{sc-ext}[`IntegrationProperties`]
5132+
classes for more details.
51205133

51215134

51225135

0 commit comments

Comments
 (0)