Browse Source

Document client disposal using MongoDatabaseFactory.

Closes #5012
pull/5026/head
Mark Paluch 5 months ago
parent
commit
0bb302cb8e
No known key found for this signature in database
GPG Key ID: 55BC6374BAA9D973
  1. 54
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoDatabaseFactorySupport.java
  2. 12
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/SimpleMongoClientDatabaseFactory.java
  3. 63
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/SimpleReactiveMongoDatabaseFactory.java

54
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoDatabaseFactorySupport.java

@ -16,6 +16,7 @@
package org.springframework.data.mongodb.core; package org.springframework.data.mongodb.core;
import org.jspecify.annotations.Nullable; import org.jspecify.annotations.Nullable;
import org.springframework.aop.framework.ProxyFactory; import org.springframework.aop.framework.ProxyFactory;
import org.springframework.dao.DataAccessException; import org.springframework.dao.DataAccessException;
import org.springframework.dao.support.PersistenceExceptionTranslator; import org.springframework.dao.support.PersistenceExceptionTranslator;
@ -23,7 +24,6 @@ import org.springframework.data.mongodb.MongoDatabaseFactory;
import org.springframework.data.mongodb.SessionAwareMethodInterceptor; import org.springframework.data.mongodb.SessionAwareMethodInterceptor;
import org.springframework.lang.Contract; import org.springframework.lang.Contract;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import com.mongodb.ClientSessionOptions; import com.mongodb.ClientSessionOptions;
import com.mongodb.WriteConcern; import com.mongodb.WriteConcern;
@ -33,8 +33,7 @@ import com.mongodb.client.MongoDatabase;
/** /**
* Common base class for usage with both {@link com.mongodb.client.MongoClients} defining common properties such as * Common base class for usage with both {@link com.mongodb.client.MongoClients} defining common properties such as
* database name and exception translator. <br /> * database name and exception translator. Not intended to be used directly.
* Not intended to be used directly.
* *
* @author Christoph Strobl * @author Christoph Strobl
* @author Mark Paluch * @author Mark Paluch
@ -126,6 +125,7 @@ public abstract class MongoDatabaseFactorySupport<C> implements MongoDatabaseFac
*/ */
protected abstract MongoDatabase doGetMongoDatabase(String dbName); protected abstract MongoDatabase doGetMongoDatabase(String dbName);
public void destroy() throws Exception { public void destroy() throws Exception {
if (mongoInstanceCreated) { if (mongoInstanceCreated) {
closeClient(); closeClient();
@ -164,15 +164,8 @@ public abstract class MongoDatabaseFactorySupport<C> implements MongoDatabaseFac
* @author Christoph Strobl * @author Christoph Strobl
* @since 2.1 * @since 2.1
*/ */
static final class ClientSessionBoundMongoDbFactory implements MongoDatabaseFactory { record ClientSessionBoundMongoDbFactory(ClientSession session,
MongoDatabaseFactory delegate) implements MongoDatabaseFactory {
private final ClientSession session;
private final MongoDatabaseFactory delegate;
public ClientSessionBoundMongoDbFactory(ClientSession session, MongoDatabaseFactory delegate) {
this.session = session;
this.delegate = delegate;
}
@Override @Override
public MongoDatabase getMongoDatabase() throws DataAccessException { public MongoDatabase getMongoDatabase() throws DataAccessException {
@ -201,7 +194,7 @@ public abstract class MongoDatabaseFactorySupport<C> implements MongoDatabaseFac
@Override @Override
public boolean isTransactionActive() { public boolean isTransactionActive() {
return session != null && session.hasActiveTransaction(); return session.hasActiveTransaction();
} }
private MongoDatabase proxyMongoDatabase(MongoDatabase database) { private MongoDatabase proxyMongoDatabase(MongoDatabase database) {
@ -230,39 +223,6 @@ public abstract class MongoDatabaseFactorySupport<C> implements MongoDatabaseFac
return targetType.cast(factory.getProxy(target.getClass().getClassLoader())); return targetType.cast(factory.getProxy(target.getClass().getClassLoader()));
} }
public ClientSession getSession() {
return this.session;
}
public MongoDatabaseFactory getDelegate() {
return this.delegate;
}
@Override
public boolean equals(@Nullable Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
ClientSessionBoundMongoDbFactory that = (ClientSessionBoundMongoDbFactory) o;
if (!ObjectUtils.nullSafeEquals(this.session, that.session)) {
return false;
}
return ObjectUtils.nullSafeEquals(this.delegate, that.delegate);
}
@Override
public int hashCode() {
int result = ObjectUtils.nullSafeHashCode(this.session);
result = 31 * result + ObjectUtils.nullSafeHashCode(this.delegate);
return result;
}
public String toString() {
return "MongoDatabaseFactorySupport.ClientSessionBoundMongoDbFactory(session=" + this.getSession() + ", delegate="
+ this.getDelegate() + ")";
}
} }
} }

12
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/SimpleMongoClientDatabaseFactory.java

@ -34,7 +34,8 @@ public class SimpleMongoClientDatabaseFactory extends MongoDatabaseFactorySuppor
implements DisposableBean { implements DisposableBean {
/** /**
* Creates a new {@link SimpleMongoClientDatabaseFactory} instance for the given {@code connectionString}. * Creates a new {@link SimpleMongoClientDatabaseFactory} instance for the given {@code connectionString}. Using this
* constructor will create a new {@link MongoClient} instance that will be closed when calling {@link #destroy()}.
* *
* @param connectionString connection coordinates for a database connection. Must contain a database name and must not * @param connectionString connection coordinates for a database connection. Must contain a database name and must not
* be {@literal null} or empty. * be {@literal null} or empty.
@ -45,7 +46,8 @@ public class SimpleMongoClientDatabaseFactory extends MongoDatabaseFactorySuppor
} }
/** /**
* Creates a new {@link SimpleMongoClientDatabaseFactory} instance from the given {@link MongoClient}. * Creates a new {@link SimpleMongoClientDatabaseFactory} instance from the given {@link MongoClient}. Using this
* constructor will create a new {@link MongoClient} instance that will be closed when calling {@link #destroy()}.
* *
* @param connectionString connection coordinates for a database connection. Must contain also a database name and not * @param connectionString connection coordinates for a database connection. Must contain also a database name and not
* be {@literal null}. * be {@literal null}.
@ -55,7 +57,10 @@ public class SimpleMongoClientDatabaseFactory extends MongoDatabaseFactorySuppor
} }
/** /**
* Creates a new {@link SimpleMongoClientDatabaseFactory} instance from the given {@link MongoClient}. * Creates a new {@link SimpleMongoClientDatabaseFactory} instance from the given {@link MongoClient}. Note that the
* client will not be closed when calling {@link #destroy()} as we assume a managed client instance that we do not
* want to close on {@link #destroy()} meaning that you (or the application container) must dispose the client
* instance once it is no longer required for use.
* *
* @param mongoClient must not be {@literal null}. * @param mongoClient must not be {@literal null}.
* @param databaseName must not be {@literal null} or empty. * @param databaseName must not be {@literal null} or empty.
@ -89,4 +94,5 @@ public class SimpleMongoClientDatabaseFactory extends MongoDatabaseFactorySuppor
protected MongoDatabase doGetMongoDatabase(String dbName) { protected MongoDatabase doGetMongoDatabase(String dbName) {
return getMongoClient().getDatabase(dbName); return getMongoClient().getDatabase(dbName);
} }
} }

63
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/SimpleReactiveMongoDatabaseFactory.java

@ -19,6 +19,7 @@ import reactor.core.publisher.Mono;
import org.bson.codecs.configuration.CodecRegistry; import org.bson.codecs.configuration.CodecRegistry;
import org.jspecify.annotations.Nullable; import org.jspecify.annotations.Nullable;
import org.springframework.aop.framework.ProxyFactory; import org.springframework.aop.framework.ProxyFactory;
import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.DisposableBean;
import org.springframework.dao.DataAccessException; import org.springframework.dao.DataAccessException;
@ -26,7 +27,6 @@ import org.springframework.dao.support.PersistenceExceptionTranslator;
import org.springframework.data.mongodb.ReactiveMongoDatabaseFactory; import org.springframework.data.mongodb.ReactiveMongoDatabaseFactory;
import org.springframework.data.mongodb.SessionAwareMethodInterceptor; import org.springframework.data.mongodb.SessionAwareMethodInterceptor;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import com.mongodb.ClientSessionOptions; import com.mongodb.ClientSessionOptions;
import com.mongodb.ConnectionString; import com.mongodb.ConnectionString;
@ -55,7 +55,9 @@ public class SimpleReactiveMongoDatabaseFactory implements DisposableBean, React
private @Nullable WriteConcern writeConcern; private @Nullable WriteConcern writeConcern;
/** /**
* Creates a new {@link SimpleReactiveMongoDatabaseFactory} instance from the given {@link ConnectionString}. * Creates a new {@link SimpleReactiveMongoDatabaseFactory} instance from the given {@link ConnectionString}. Using
* this constructor will create a new {@link MongoClient} instance that will be closed when calling
* {@link #destroy()}.
* *
* @param connectionString must not be {@literal null}. * @param connectionString must not be {@literal null}.
*/ */
@ -64,7 +66,10 @@ public class SimpleReactiveMongoDatabaseFactory implements DisposableBean, React
} }
/** /**
* Creates a new {@link SimpleReactiveMongoDatabaseFactory} instance from the given {@link MongoClient}. * Creates a new {@link SimpleReactiveMongoDatabaseFactory} instance from the given {@link MongoClient}. Note that the
* client will not be closed when calling {@link #destroy()} as we assume a managed client instance that we do not
* want to close on {@link #destroy()} meaning that you (or the application container) must dispose the client
* instance once it is no longer required for use.
* *
* @param mongoClient must not be {@literal null}. * @param mongoClient must not be {@literal null}.
* @param databaseName must not be {@literal null}. * @param databaseName must not be {@literal null}.
@ -163,16 +168,8 @@ public class SimpleReactiveMongoDatabaseFactory implements DisposableBean, React
* @author Christoph Strobl * @author Christoph Strobl
* @since 2.1 * @since 2.1
*/ */
static final class ClientSessionBoundMongoDbFactory implements ReactiveMongoDatabaseFactory { record ClientSessionBoundMongoDbFactory(ClientSession session,
ReactiveMongoDatabaseFactory delegate) implements ReactiveMongoDatabaseFactory {
private final ClientSession session;
private final ReactiveMongoDatabaseFactory delegate;
ClientSessionBoundMongoDbFactory(ClientSession session, ReactiveMongoDatabaseFactory delegate) {
this.session = session;
this.delegate = delegate;
}
@Override @Override
public Mono<MongoDatabase> getMongoDatabase() throws DataAccessException { public Mono<MongoDatabase> getMongoDatabase() throws DataAccessException {
@ -206,7 +203,7 @@ public class SimpleReactiveMongoDatabaseFactory implements DisposableBean, React
@Override @Override
public boolean isTransactionActive() { public boolean isTransactionActive() {
return session != null && session.hasActiveTransaction(); return session.hasActiveTransaction();
} }
private MongoDatabase decorateDatabase(MongoDatabase database) { private MongoDatabase decorateDatabase(MongoDatabase database) {
@ -217,7 +214,8 @@ public class SimpleReactiveMongoDatabaseFactory implements DisposableBean, React
return createProxyInstance(session, database, MongoDatabase.class); return createProxyInstance(session, database, MongoDatabase.class);
} }
private MongoCollection proxyCollection(com.mongodb.session.ClientSession session, MongoCollection collection) { private MongoCollection<?> proxyCollection(com.mongodb.session.ClientSession session,
MongoCollection<?> collection) {
return createProxyInstance(session, collection, MongoCollection.class); return createProxyInstance(session, collection, MongoCollection.class);
} }
@ -234,39 +232,6 @@ public class SimpleReactiveMongoDatabaseFactory implements DisposableBean, React
return targetType.cast(factory.getProxy(target.getClass().getClassLoader())); return targetType.cast(factory.getProxy(target.getClass().getClassLoader()));
} }
public ClientSession getSession() {
return this.session;
}
public ReactiveMongoDatabaseFactory getDelegate() {
return this.delegate;
}
@Override
public boolean equals(@Nullable Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
ClientSessionBoundMongoDbFactory that = (ClientSessionBoundMongoDbFactory) o;
if (!ObjectUtils.nullSafeEquals(this.session, that.session)) {
return false;
}
return ObjectUtils.nullSafeEquals(this.delegate, that.delegate);
}
@Override
public int hashCode() {
int result = ObjectUtils.nullSafeHashCode(this.session);
result = 31 * result + ObjectUtils.nullSafeHashCode(this.delegate);
return result;
}
public String toString() {
return "SimpleReactiveMongoDatabaseFactory.ClientSessionBoundMongoDbFactory(session=" + this.getSession()
+ ", delegate=" + this.getDelegate() + ")";
}
} }
} }

Loading…
Cancel
Save