2929import org .springframework .boot .autoconfigure .condition .ConditionalOnMissingBean ;
3030import org .springframework .boot .autoconfigure .condition .ConditionalOnProperty ;
3131import org .springframework .boot .autoconfigure .condition .SpringBootCondition ;
32+ import org .springframework .boot .autoconfigure .r2dbc .R2dbcProperties .Pool ;
3233import org .springframework .boot .context .properties .PropertyMapper ;
34+ import org .springframework .boot .context .properties .bind .BindResult ;
35+ import org .springframework .boot .context .properties .bind .Bindable ;
36+ import org .springframework .boot .context .properties .bind .Binder ;
3337import org .springframework .boot .r2dbc .EmbeddedDatabaseConnection ;
3438import org .springframework .context .annotation .Bean ;
3539import org .springframework .context .annotation .Condition ;
3640import org .springframework .context .annotation .ConditionContext ;
3741import org .springframework .context .annotation .Conditional ;
3842import org .springframework .context .annotation .Configuration ;
43+ import org .springframework .core .env .Environment ;
3944import org .springframework .core .io .ResourceLoader ;
4045import org .springframework .core .type .AnnotatedTypeMetadata ;
46+ import org .springframework .util .ClassUtils ;
4147import org .springframework .util .StringUtils ;
4248
4349/**
@@ -51,39 +57,54 @@ abstract class ConnectionFactoryConfigurations {
5157
5258 protected static ConnectionFactory createConnectionFactory (R2dbcProperties properties , ClassLoader classLoader ,
5359 List <ConnectionFactoryOptionsBuilderCustomizer > optionsCustomizers ) {
54- return org .springframework .boot .r2dbc .ConnectionFactoryBuilder
55- .withOptions (new ConnectionFactoryOptionsInitializer ().initialize (properties ,
56- () -> EmbeddedDatabaseConnection .get (classLoader )))
57- .configure ((options ) -> {
58- for (ConnectionFactoryOptionsBuilderCustomizer optionsCustomizer : optionsCustomizers ) {
59- optionsCustomizer .customize (options );
60- }
61- }).build ();
60+ try {
61+ return org .springframework .boot .r2dbc .ConnectionFactoryBuilder
62+ .withOptions (new ConnectionFactoryOptionsInitializer ().initialize (properties ,
63+ () -> EmbeddedDatabaseConnection .get (classLoader )))
64+ .configure ((options ) -> {
65+ for (ConnectionFactoryOptionsBuilderCustomizer optionsCustomizer : optionsCustomizers ) {
66+ optionsCustomizer .customize (options );
67+ }
68+ }).build ();
69+ }
70+ catch (IllegalStateException ex ) {
71+ String message = ex .getMessage ();
72+ if (message != null && message .contains ("driver=pool" )
73+ && !ClassUtils .isPresent ("io.r2dbc.pool.ConnectionPool" , classLoader )) {
74+ throw new MissingR2dbcPoolDependencyException ();
75+ }
76+ throw ex ;
77+ }
6278 }
6379
6480 @ Configuration (proxyBeanMethods = false )
65- @ ConditionalOnClass (ConnectionPool .class )
6681 @ Conditional (PooledConnectionFactoryCondition .class )
6782 @ ConditionalOnMissingBean (ConnectionFactory .class )
68- static class Pool {
83+ static class PoolConfiguration {
84+
85+ @ Configuration (proxyBeanMethods = false )
86+ @ ConditionalOnClass (ConnectionPool .class )
87+ static class PooledConnectionFactoryConfiguration {
88+
89+ @ Bean (destroyMethod = "dispose" )
90+ ConnectionPool connectionFactory (R2dbcProperties properties , ResourceLoader resourceLoader ,
91+ ObjectProvider <ConnectionFactoryOptionsBuilderCustomizer > customizers ) {
92+ ConnectionFactory connectionFactory = createConnectionFactory (properties ,
93+ resourceLoader .getClassLoader (), customizers .orderedStream ().collect (Collectors .toList ()));
94+ R2dbcProperties .Pool pool = properties .getPool ();
95+ PropertyMapper map = PropertyMapper .get ().alwaysApplyingWhenNonNull ();
96+ ConnectionPoolConfiguration .Builder builder = ConnectionPoolConfiguration .builder (connectionFactory );
97+ map .from (pool .getMaxIdleTime ()).to (builder ::maxIdleTime );
98+ map .from (pool .getMaxLifeTime ()).to (builder ::maxLifeTime );
99+ map .from (pool .getMaxAcquireTime ()).to (builder ::maxAcquireTime );
100+ map .from (pool .getMaxCreateConnectionTime ()).to (builder ::maxCreateConnectionTime );
101+ map .from (pool .getInitialSize ()).to (builder ::initialSize );
102+ map .from (pool .getMaxSize ()).to (builder ::maxSize );
103+ map .from (pool .getValidationQuery ()).whenHasText ().to (builder ::validationQuery );
104+ map .from (pool .getValidationDepth ()).to (builder ::validationDepth );
105+ return new ConnectionPool (builder .build ());
106+ }
69107
70- @ Bean (destroyMethod = "dispose" )
71- ConnectionPool connectionFactory (R2dbcProperties properties , ResourceLoader resourceLoader ,
72- ObjectProvider <ConnectionFactoryOptionsBuilderCustomizer > customizers ) {
73- ConnectionFactory connectionFactory = createConnectionFactory (properties , resourceLoader .getClassLoader (),
74- customizers .orderedStream ().collect (Collectors .toList ()));
75- R2dbcProperties .Pool pool = properties .getPool ();
76- PropertyMapper map = PropertyMapper .get ().alwaysApplyingWhenNonNull ();
77- ConnectionPoolConfiguration .Builder builder = ConnectionPoolConfiguration .builder (connectionFactory );
78- map .from (pool .getMaxIdleTime ()).to (builder ::maxIdleTime );
79- map .from (pool .getMaxLifeTime ()).to (builder ::maxLifeTime );
80- map .from (pool .getMaxAcquireTime ()).to (builder ::maxAcquireTime );
81- map .from (pool .getMaxCreateConnectionTime ()).to (builder ::maxCreateConnectionTime );
82- map .from (pool .getInitialSize ()).to (builder ::initialSize );
83- map .from (pool .getMaxSize ()).to (builder ::maxSize );
84- map .from (pool .getValidationQuery ()).whenHasText ().to (builder ::validationQuery );
85- map .from (pool .getValidationDepth ()).to (builder ::validationDepth );
86- return new ConnectionPool (builder .build ());
87108 }
88109
89110 }
@@ -92,7 +113,7 @@ ConnectionPool connectionFactory(R2dbcProperties properties, ResourceLoader reso
92113 @ ConditionalOnProperty (prefix = "spring.r2dbc.pool" , value = "enabled" , havingValue = "false" ,
93114 matchIfMissing = true )
94115 @ ConditionalOnMissingBean (ConnectionFactory .class )
95- static class Generic {
116+ static class GenericConfiguration {
96117
97118 @ Bean
98119 ConnectionFactory connectionFactory (R2dbcProperties properties , ResourceLoader resourceLoader ,
@@ -105,26 +126,35 @@ ConnectionFactory connectionFactory(R2dbcProperties properties, ResourceLoader r
105126
106127 /**
107128 * {@link Condition} that checks that a {@link ConnectionPool} is requested. The
108- * condition matches if pooling was opt-in via configuration and the r2dbc url does
109- * not contain pooling-related options.
129+ * condition matches if pooling was opt-in via configuration. If any of the
130+ * spring.r2dbc.pool.* properties have been configured, an exception is thrown if the
131+ * URL also contains pooling-related options or io.r2dbc.pool.ConnectionPool is not on
132+ * the class path.
110133 */
111134 static class PooledConnectionFactoryCondition extends SpringBootCondition {
112135
113136 @ Override
114137 public ConditionOutcome getMatchOutcome (ConditionContext context , AnnotatedTypeMetadata metadata ) {
115- boolean poolEnabled = context .getEnvironment ().getProperty ("spring.r2dbc.pool.enabled" , Boolean .class ,
116- true );
117- if (poolEnabled ) {
118- // Make sure the URL does not have pool options
119- String url = context .getEnvironment ().getProperty ("spring.r2dbc.url" );
120- boolean pooledUrl = StringUtils .hasText (url ) && url .contains (":pool:" );
121- if (pooledUrl ) {
122- return ConditionOutcome .noMatch ("R2DBC Connection URL contains pooling-related options" );
138+ BindResult <Pool > pool = Binder .get (context .getEnvironment ()).bind ("spring.r2dbc.pool" ,
139+ Bindable .of (Pool .class ));
140+ if (hasPoolUrl (context .getEnvironment ())) {
141+ if (pool .isBound ()) {
142+ throw new MultipleConnectionPoolConfigurationsException ();
123143 }
124- return ConditionOutcome
125- .match ("Pooling is enabled and R2DBC Connection URL does not contain pooling-related options" );
144+ return ConditionOutcome .noMatch ("URL-based pooling has been configured" );
145+ }
146+ if (pool .isBound () && !ClassUtils .isPresent ("io.r2dbc.pool.ConnectionPool" , context .getClassLoader ())) {
147+ throw new MissingR2dbcPoolDependencyException ();
148+ }
149+ if (pool .orElseGet (Pool ::new ).isEnabled ()) {
150+ return ConditionOutcome .match ("Property-based pooling is enabled" );
126151 }
127- return ConditionOutcome .noMatch ("Pooling is disabled" );
152+ return ConditionOutcome .noMatch ("Property-based pooling is disabled" );
153+ }
154+
155+ private boolean hasPoolUrl (Environment environment ) {
156+ String url = environment .getProperty ("spring.r2dbc.url" );
157+ return StringUtils .hasText (url ) && url .contains (":pool:" );
128158 }
129159
130160 }
0 commit comments