最近写了一个发邮件的模块,JavaMail提供了SMTP协议的封装,接下来只需要写一些连接管理的逻辑即可,之前分析过tomcat-jdbc-pool的源码,感觉再实现一遍没有必要,所以就想起了Apache Commons Pool这个项目。

三个类

GenericObjectPool

public class GenericObjectPool<T> extends BaseGenericObjectPool<T>
        implements ObjectPool<T>, GenericObjectPoolMXBean, UsageTracking<T> {

该类即是对连接池通用逻辑的封装,通常使用中只需要关注下述三个方法:

public T borrowObject() throws Exception {
public T borrowObject(long borrowMaxWaitMillis) throws Exception {
public void returnObject(T obj) {

在borrow和return过程中如果需要自定义逻辑,只需要继承该类override对应的方法即可。

再看一下构造方法:

public GenericObjectPool(PooledObjectFactory<T> factory) {
public GenericObjectPool(PooledObjectFactory<T> factory, GenericObjectPoolConfig config) {
public GenericObjectPool(PooledObjectFactory<T> factory, GenericObjectPoolConfig config, AbandonedConfig abandonedConfig) {

PooledObjectFactory

public interface PooledObjectFactory<T> {

该接口做为GenericObjectPool的参数,规定了连接构建、注销等方法,使用者需要根据具体的连续构建、注销逻辑实现该接口。

// Create an instance that can be served by the pool and wrap it in a {@link PooledObject} to be managed by the pool.
PooledObject<T> makeObject() throws Exception;

// Destroys an instance no longer needed by the pool.
void destroyObject(PooledObject<T> p) throws Exception;

// Ensures that the instance is safe to be returned by the pool.
boolean validateObject(PooledObject<T> p);

// Reinitialize an instance to be returned by the pool.
void activateObject(PooledObject<T> p) throws Exception;

// Uninitialize an instance to be returned to the idle object pool.
void passivateObject(PooledObject<T> p) throws Exception;

前三个方法顾名思义,后两个方法需要说明一下:activateObjectborrowObject中调用,如果抛出异常,那么重新从池子中再取一个,但是如果是新构建的连接,那么将异常抛出;passivateObjectreturnObject中调用,如果抛出异常,那么注销该连接。

GenericObjectPoolConfig

该类做为GenericObjectPool的参数,封装了连接池的配置信息:

private int maxTotal = DEFAULT_MAX_TOTAL;
private int maxIdle = DEFAULT_MAX_IDLE;
private int minIdle = DEFAULT_MIN_IDLE;

顾名思义,就不多做解释。

实现SMTP连接池

PooledSmtpConnection

包装JavaMail中的SMTP连接类Transport

public class PooledSmtpConnection implements AutoCloseable {

    private final Transport delegate;

    private SmtpConnectionPool pool;

    public PooledSmtpConnection(Transport delegate) {
        this.delegate = delegate;
    }

    public void send(MimeMessage message) throws MessagingException {
        if (message.getSentDate() == null) {
            message.setSentDate(new Date());
        }
        message.saveChanges();

        delegate.sendMessage(message, message.getAllRecipients());
    }

    public boolean isConnected() {
        return delegate.isConnected();
    }

    public void setPool(SmtpConnectionPool pool) {
        this.pool = pool;
    }

    public Transport getDelegate() {
        return delegate;
    }

    public Session getSession() {
        return pool.getSession();
    }

    @Override
    public void close() throws Exception {
        pool.returnObject(this);
    }
}

SmtpConnectionFactory

实现连接工厂类

public class SmtpConnectionFactory extends BasePooledObjectFactory<PooledSmtpConnection> {

    private static final Logger LOGGER = LoggerFactory.getLogger(SmtpConnectionFactory.class);

    private final Session session;
    private final ConnectionStrategy connectionStrategy;

    private SmtpConnectionFactory(Session session, ConnectionStrategy connectionStrategy) {
        this.session = session;
        this.connectionStrategy = connectionStrategy;
    }

    @Override
    public PooledSmtpConnection create() throws Exception {
        Transport transport = session.getTransport();
        connectionStrategy.connect(transport);

        return new PooledSmtpConnection(transport);
    }

    @Override
    public PooledObject<PooledSmtpConnection> wrap(PooledSmtpConnection obj) {
        return new DefaultPooledObject<>(obj);
    }

    @Override
    public void destroyObject(PooledObject<PooledSmtpConnection> pooledObject) throws Exception {
        pooledObject.getObject().getDelegate().close();
    }

    @Override
    public void activateObject(PooledObject<PooledSmtpConnection> pooledObject) throws Exception {
        if (!pooledObject.getObject().isConnected()) {
            throw new Exception("Smtp Transport is not connected");
        }
    }

    public Session getSession() {
        return session;
    }

    public static Builder newBuilder() {
        return new Builder();
    }

    ......
    
}

SmtpConnectionPool

实现连接池

public class SmtpConnectionPool extends GenericObjectPool<PooledSmtpConnection> {

    private SmtpConnectionPool(PooledObjectFactory<PooledSmtpConnection> factory, GenericObjectPoolConfig config) {
        super(factory, config);
    }

    @Override
    public PooledSmtpConnection borrowObject() throws Exception {
        PooledSmtpConnection object = super.borrowObject();
        object.setPool(this);
        return object;
    }

    @Override
    public PooledSmtpConnection borrowObject(long borrowMaxWaitMillis) throws Exception {
        PooledSmtpConnection object = super.borrowObject(borrowMaxWaitMillis);
        object.setPool(this);
        return object;
    }

    public Session getSession() {
        return ((SmtpConnectionFactory) getFactory()).getSession();
    }

    public static Builder newBuilder() {
        return new Builder();
    }
    
    ......
    
}