Use a single MongoClient across a JavaEE web service
Asked Answered
A

2

7

After reading the mongo documentation that says each instance of a MongoClient handles its own pooling, how would I go about only having one instance across my whole application?

This seems like it could be a scenario for using a singleton bean, but this seems like it would defeat the purpose of connection pooling. If only one user would be able to access the bean that contains the MongoClient instance at a time, surely multiple connections in the pool would never be used at the same time.

Have I got my understanding of singletons wrong, or is that indeed the right way to go about it?

Afroasian answered 28/9, 2014 at 12:44 Comment(3)
it would defeat the purpose of connection poolingFlashboard
Are you using Spring to create mongo client ??Pigeonhearted
No, I'm not using Spring I am using JavaEE, sorry I should have put that in the question (I've added it to the tags and will update the question title)Afroasian
P
9

but this seems like it would defeat the purpose of connection pooling.If only one user would be able to access the bean that contains the MongoClient instance at a time, surely multiple connections in the pool would never be used at the same time.

The javadoc says:

The Java MongoDB driver is thread safe. If you are using in a web serving environment, for example, you should create a single MongoClient instance, and you can use it in every request. The MongoClient object maintains an internal pool of connections to the database (default maximum pool size of 100). For every request to the DB (find, insert, etc) the Java thread will obtain a connection from the pool, execute the operation, and release the connection. This means the connection (socket) used may be different each time.

So, when you create a singleton with the client in it. It can be re-used as mentioned in the Javadoc. No synchronization is required, since it is thread safe.

how would I go about only having one instance across my whole application?

One of the implementations could be:

public enum ConnectionFactory {
    CONNECTION;
    private MongoClient client = null;

    private ConnectionFactory() {
        try {
            client = new MongoClient();
        } catch (Exception e) {
            // Log it.
        }
    }

    public MongoClient getClient() {
        if (client == null)
            throw new RuntimeException();
        return client;
    }
}

and use the client as, throughout the application. Connection pooling will be taken care by the MongoClient as documented.

MongoClient client = ConnectionFactory.CONNECTION.getClient();

or use the @singleton annotation:

@Singleton
public class SingletonA {

}

Refer: http://tomee.apache.org/singleton-example.html

Priestridden answered 28/9, 2014 at 14:20 Comment(3)
Thanks for the answer, what would be the difference between doing this and using the @Singleton annotation to create a singleton bean be? Would it have the same effect?Afroasian
@MattWilliams - The first one is an implementation of a singleton pattern and can be used both in a normal java app and a Java EE app, @singleton abstracts the implementation of singleton from the developer. So the underlying framework takes care of implementing an singleton instance for the class. Have updated my answer w.r.t your comments.Priestridden
@BatScrem - Brilliant, thanks for clearing that up. So in my ConnectionFactory (or whatever I call it) class that uses the annotation I can just have a private MongoClient variable, instantiate it in the constructor and have a simple getter. Can these just be one line methods e.g. in the constructor client = new MongoClient(); as the annotation and injecting handles the case where you could call the getter when it hasn't been instantiated, or do I still need to include the exception handling?Afroasian
G
3

Since you are in a java ee environment, the best way to implement this would be to use CDI producers:

@Stateless
public class ConnetionFactory {

  @ApplicationScoped
  @Produces
  public MongoClient mongoClient() {
    return new MongoClient();
  }
}

Then in every bean you want to use it in:

@Stateless
public class MyServiceBean {

  @Inject
  private MongoClient mongoClient;
}
Govea answered 28/9, 2014 at 14:32 Comment(1)
I agree that this is the way to go in the JavaEE environment.Sparling

© 2022 - 2024 — McMap. All rights reserved.