Skip to content

Commit 903a2d1

Browse files
committed
#95 - Use customized ConnectionFactory lookup to avoid AbstractR2dbcConfiguration proxying.
We now attempt to lookup ConnectionFactory from ApplicationContext and fall back to a local method call if ConnectionFactory is not exposed as bean.
1 parent db49eda commit 903a2d1

File tree

2 files changed

+127
-6
lines changed

2 files changed

+127
-6
lines changed

src/main/java/org/springframework/data/r2dbc/config/AbstractR2dbcConfiguration.java

+33-6
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@
2020
import java.util.Collections;
2121
import java.util.Optional;
2222

23+
import org.springframework.beans.BeansException;
24+
import org.springframework.context.ApplicationContext;
25+
import org.springframework.context.ApplicationContextAware;
2326
import org.springframework.context.annotation.Bean;
2427
import org.springframework.context.annotation.Configuration;
2528
import org.springframework.core.convert.converter.Converter;
@@ -37,6 +40,7 @@
3740
import org.springframework.data.relational.core.conversion.BasicRelationalConverter;
3841
import org.springframework.data.relational.core.mapping.NamingStrategy;
3942
import org.springframework.data.relational.core.mapping.RelationalMappingContext;
43+
import org.springframework.lang.Nullable;
4044
import org.springframework.util.Assert;
4145

4246
/**
@@ -48,8 +52,19 @@
4852
* @see DatabaseClient
4953
* @see org.springframework.data.r2dbc.repository.config.EnableR2dbcRepositories
5054
*/
51-
@Configuration
52-
public abstract class AbstractR2dbcConfiguration {
55+
@Configuration(proxyBeanMethods = false)
56+
public abstract class AbstractR2dbcConfiguration implements ApplicationContextAware {
57+
58+
private @Nullable ApplicationContext context;
59+
60+
/*
61+
* (non-Javadoc)
62+
* @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext)
63+
*/
64+
@Override
65+
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
66+
this.context = applicationContext;
67+
}
5368

5469
/**
5570
* Return a R2DBC {@link ConnectionFactory}. Annotate with {@link Bean} in case you want to expose a
@@ -91,7 +106,7 @@ public DatabaseClient databaseClient(ReactiveDataAccessStrategy dataAccessStrate
91106
Assert.notNull(exceptionTranslator, "ExceptionTranslator must not be null!");
92107

93108
return DatabaseClient.builder() //
94-
.connectionFactory(connectionFactory()) //
109+
.connectionFactory(lookupConnectionFactory()) //
95110
.dataAccessStrategy(dataAccessStrategy) //
96111
.exceptionTranslator(exceptionTranslator) //
97112
.build();
@@ -137,7 +152,7 @@ public ReactiveDataAccessStrategy reactiveDataAccessStrategy(RelationalMappingCo
137152

138153
MappingR2dbcConverter converter = new MappingR2dbcConverter(mappingContext, r2dbcCustomConversions);
139154

140-
return new DefaultReactiveDataAccessStrategy(getDialect(connectionFactory()), converter);
155+
return new DefaultReactiveDataAccessStrategy(getDialect(lookupConnectionFactory()), converter);
141156
}
142157

143158
/**
@@ -160,7 +175,7 @@ public R2dbcCustomConversions r2dbcCustomConversions() {
160175
*/
161176
protected StoreConversions getStoreConversions() {
162177

163-
Dialect dialect = getDialect(connectionFactory());
178+
Dialect dialect = getDialect(lookupConnectionFactory());
164179
return StoreConversions.of(dialect.getSimpleTypeHolder(), R2dbcCustomConversions.STORE_CONVERTERS);
165180
}
166181

@@ -172,6 +187,18 @@ protected StoreConversions getStoreConversions() {
172187
*/
173188
@Bean
174189
public R2dbcExceptionTranslator exceptionTranslator() {
175-
return new SqlErrorCodeR2dbcExceptionTranslator(connectionFactory());
190+
return new SqlErrorCodeR2dbcExceptionTranslator(lookupConnectionFactory());
191+
}
192+
193+
private ConnectionFactory lookupConnectionFactory() {
194+
195+
ApplicationContext context = this.context;
196+
Assert.notNull(context, "ApplicationContext is not yet initialized");
197+
198+
if (context.getBeanNamesForType(ConnectionFactory.class).length != 0) {
199+
return context.getBean(ConnectionFactory.class);
200+
}
201+
202+
return connectionFactory();
176203
}
177204
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
/*
2+
* Copyright 2019 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+
* https://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+
package org.springframework.data.r2dbc.config;
17+
18+
import static org.assertj.core.api.Assertions.*;
19+
20+
import io.r2dbc.h2.H2ConnectionConfiguration;
21+
import io.r2dbc.h2.H2ConnectionFactory;
22+
import io.r2dbc.spi.ConnectionFactory;
23+
24+
import org.junit.Test;
25+
26+
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
27+
import org.springframework.context.annotation.Bean;
28+
import org.springframework.context.annotation.Configuration;
29+
import org.springframework.data.r2dbc.function.DatabaseClient;
30+
31+
/**
32+
* Tests for {@link AbstractR2dbcConfiguration}.
33+
*
34+
* @author Mark Paluch
35+
*/
36+
public class R2dbcConfigurationTests {
37+
38+
@Test // gh-95
39+
public void shouldLookupConnectionFactoryThroughLocalCall() {
40+
41+
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
42+
NonBeanConnectionFactoryConfiguration.class);
43+
44+
context.getBean(DatabaseClient.class);
45+
46+
NonBeanConnectionFactoryConfiguration bean = context.getBean(NonBeanConnectionFactoryConfiguration.class);
47+
48+
assertThat(context.getBeanNamesForType(ConnectionFactory.class)).isEmpty();
49+
assertThat(bean.callCounter).isGreaterThan(2);
50+
51+
context.stop();
52+
}
53+
54+
@Test // gh-95
55+
public void shouldRegisterConnectionFactory() {
56+
57+
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
58+
BeanConnectionFactoryConfiguration.class);
59+
60+
context.getBean(DatabaseClient.class);
61+
62+
BeanConnectionFactoryConfiguration bean = context.getBean(BeanConnectionFactoryConfiguration.class);
63+
64+
assertThat(bean.callCounter).isEqualTo(1);
65+
assertThat(context.getBeanNamesForType(ConnectionFactory.class)).hasSize(1);
66+
67+
context.stop();
68+
}
69+
70+
@Configuration(proxyBeanMethods = false)
71+
static class NonBeanConnectionFactoryConfiguration extends AbstractR2dbcConfiguration {
72+
73+
int callCounter;
74+
75+
@Override
76+
public ConnectionFactory connectionFactory() {
77+
78+
callCounter++;
79+
return new H2ConnectionFactory(
80+
H2ConnectionConfiguration.builder().inMemory("foo").username("sa").password("").build());
81+
}
82+
}
83+
84+
@Configuration(proxyBeanMethods = false)
85+
static class BeanConnectionFactoryConfiguration extends NonBeanConnectionFactoryConfiguration {
86+
87+
@Override
88+
@Bean
89+
public ConnectionFactory connectionFactory() {
90+
return super.connectionFactory();
91+
}
92+
}
93+
94+
}

0 commit comments

Comments
 (0)