All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.zxyinfo.queue.PersistentBusAutoConfiguration Maven / Gradle / Ivy

package com.zxyinfo.queue;

import com.codahale.metrics.MetricRegistry;
import com.google.common.collect.ImmutableMap;
import com.google.common.io.Resources;
import com.zxyinfo.exception.InitializeDatabaseException;
import com.zxyinfo.interceptor.RegisterInterceptor;
import com.zxyinfo.queue.PersistentQueueProperties.DDL;
import com.zxyinfo.surpport.DefaultRetryer;
import com.zxyinfo.surpport.RetryQueueDao;
import com.zxyinfo.surpport.RetryQueueSqlDao;
import com.zxyinfo.util.PropertiesUtils;
import java.io.IOException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;
import javax.sql.DataSource;
import org.killbill.bus.api.PersistentBus;
import org.killbill.bus.api.PersistentBusConfig;
import org.killbill.clock.DefaultClock;
import org.killbill.commons.jdbi.notification.DatabaseTransactionNotificationApi;
import org.killbill.queue.InTransaction;
import org.killbill.queue.OptimizePersistentBus;
import org.skife.config.ConfigurationObjectFactory;
import org.skife.jdbi.v2.DBI;
import org.skife.jdbi.v2.Handle;
import org.slf4j.Logger;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.framework.AopProxyUtils;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.support.AopUtils;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;
import org.springframework.jdbc.datasource.init.ScriptException;
import org.springframework.lang.NonNull;
import org.springframework.util.StringUtils;

/**
 * @author joewee
 * @version 1.0.0
 * @date 2021/9/20 17:55
 */

@EnableConfigurationProperties(PersistentBusProperties.class)
@AutoConfigureAfter({ DataSourceAutoConfiguration.class})
public class PersistentBusAutoConfiguration implements BeanPostProcessor {

  private static final Logger log = org.slf4j.LoggerFactory.getLogger(
      PersistentBusAutoConfiguration.class);
  private final PersistentBusProperties queueProperties;

  public PersistentBusAutoConfiguration(PersistentBusProperties queueProperties) {
    this.queueProperties = queueProperties;
  }

  @Override
  public Object postProcessBeforeInitialization(@NonNull Object bean,@NonNull String beanName)
      throws BeansException {
    return bean;
  }

  @Override
  public Object postProcessAfterInitialization(@NonNull Object bean,@NonNull String beanName) throws BeansException {
    if (!(bean instanceof PersistentBus)) {
      return bean;
    }
    log.info("post process {} bean of {}  ",bean.getClass().getName(),beanName);
    ProxyFactory factory = new ProxyFactory();
    factory.setTarget(bean);
    factory.addAdvisor(registerAdvisor((PersistentBus)bean));
    return factory.getProxy();
  }

  public DefaultPointcutAdvisor registerAdvisor(PersistentBus bus) {
    if (AopUtils.isAopProxy(bus)) {
      bus = (PersistentBus)AopProxyUtils.getSingletonTarget(bus);
    }
    RegisterInterceptor interceptor = new RegisterInterceptor(bus);
    AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
    // 配置增强类advisor
    pointcut.setExpression("execution(* org.killbill.bus.DefaultPersistentBus.register(*))");
    return new DefaultPointcutAdvisor(pointcut, interceptor);
  }
  /**
   * 定义持久化的eventBus
   */
  @ConditionalOnMissingBean
  @Bean(initMethod = "initQueue", destroyMethod = "stopQueue")
  @Primary
  public PersistentBus defaultPersistentBus(DataSource dataSource) {
    final Properties properties = new Properties();
    PropertiesUtils.put(properties, "org.killbill.persistent.bus.main.inMemory", queueProperties.getInMemory());
    PropertiesUtils.put(properties, "org.killbill.persistent.bus.main.max.failure.retry", queueProperties.getFailureRetries());
    PropertiesUtils.put(properties, "org.killbill.persistent.bus.main.claimed", queueProperties.getClaimed());
    PropertiesUtils.put(properties, "org.killbill.persistent.bus.main.queue.mode", queueProperties.getQueueMode());
    PropertiesUtils.put(properties, "org.killbill.persistent.bus.main.claim.time", queueProperties.getClaimTime());
    PropertiesUtils.put(properties, "org.killbill.persistent.bus.main.sleep", queueProperties.getSleep());
    PropertiesUtils.put(properties, "org.killbill.persistent.bus.main.off", queueProperties.getOff());
    PropertiesUtils.put(properties, "org.killbill.persistent.bus.main.nbThreads", queueProperties.getMaxDispatchThreads());
    PropertiesUtils.put(properties, "org.killbill.persistent.bus.main.lifecycle.dispatch.nbThreads", queueProperties.getLifecycleDispatchThreads());
    PropertiesUtils.put(properties, "org.killbill.persistent.bus.main.lifecycle.complete.nbThreads", queueProperties.getLifecycleCompleteThreads());
    PropertiesUtils.put(properties, "org.killbill.persistent.bus.main.queue.capacity", queueProperties.getQueueCapacity());
    PropertiesUtils.put(properties, "org.killbill.persistent.bus.main.reapThreshold", queueProperties.getReapThreshold());
    PropertiesUtils.put(properties, "org.killbill.persistent.bus.main.maxReDispatchCount", queueProperties.getMaxReDispatchCount());
    PropertiesUtils.put(properties, "org.killbill.persistent.bus.main.reapSchedule", queueProperties.getReapSchedule());
    PropertiesUtils.put(properties, "org.killbill.persistent.bus.main.tableName", queueProperties.getTableName());
    PropertiesUtils.put(properties, "org.killbill.persistent.bus.main.historyTableName", queueProperties.getHistoryTableName());
    final PersistentBusConfig busConfig = new ConfigurationObjectFactory(properties).buildWithReplacements(PersistentBusConfig.class,
        ImmutableMap.of("instanceName",  "main"));
    final DBI dbi = InTransaction.buildDDBI(dataSource);
    if ( DDL.AUTO.equals(queueProperties.getDdl())) {
      initialize(dbi);
    }
    final DefaultClock clock = new DefaultClock();
    DefaultRetryer defaultRetryer = null;
    if (Boolean.TRUE.equals(queueProperties.getEnableRetry())) {
      //启用重试线程
      final Long retryClaimedTime = queueProperties.getRetryClaimedTime();
      final Integer maxRetries = queueProperties.getMaxRetries();
      final RetryQueueDao retryQueueDao = new RetryQueueDao(dbi, RetryQueueSqlDao.class,busConfig,maxRetries,retryClaimedTime);
      defaultRetryer =new DefaultRetryer(retryQueueDao, busConfig, clock);
    }
    return new OptimizePersistentBus(dbi, clock,
        busConfig, new MetricRegistry(),
        new DatabaseTransactionNotificationApi(), defaultRetryer);
  }

  @Bean
  public OptimizePersistentBus optimizePersistentBus(PersistentBus defaultPersistentBus) {
    return (OptimizePersistentBus) defaultPersistentBus;
  }
  @Bean
  public DeadEventHandler deadEventHandler(PersistentBus defaultPersistentBus){
    return new DeadEventHandler(defaultPersistentBus);
  }
  private void initialize(final DBI dbi){
    try(final Handle handle = dbi.open()) {
      final Connection connection = handle.getConnection();
      final String database = connection.getMetaData().getDatabaseProductName();
      URL resource = loadResource(database);
      if (resource==null) {
        log.warn("自动创建不支持当前数据库类型:"+database);
        return;
      }
      String tableName = StringUtils.isEmpty(queueProperties.getTableName()) ?
          PersistentBusProperties.TABLE_NAME : queueProperties.getTableName();
      String historyTableName = StringUtils.isEmpty(queueProperties.getHistoryTableName()) ?
          PersistentBusProperties.HISTORY_TABLE_NAME : queueProperties.getHistoryTableName();
      final String sql = PropertiesUtils.load(resource.openStream()).replace("${tableName}", tableName)
          .replace("${historyTableName}", historyTableName);
      final ResourceDatabasePopulator populator = new ResourceDatabasePopulator();
      populator.addScripts(new ByteArrayResource(sql.getBytes(StandardCharsets.UTF_8)));
      populator.populate(connection);
    } catch (ScriptException e){
      final String message = e.getMessage();
      if (message!=null&&(message.contains("Duplicate")||message.contains("already exists"))) {
        //创建重复
        log.warn(message);
      }else{
        throw new InitializeDatabaseException("初始化数据库表失败:", e);
      }
    }catch(  IOException | SQLException e) {
      throw new InitializeDatabaseException("初始化数据库表失败:", e);
    }
  }
  private URL loadResource(String database){
    try {
      if(database.contains("MySQL")){
        return Resources.getResource("org/killbill/queue/bus_events_mysql.sql");
      }
    }catch (Exception e){
      log.error(e.getMessage(),e);

    }
    return null;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy