记,一段优雅的程序

编程的小道上,我们都在不断的探索和学习,这将是一条曲折的小道,毕竟天才属于少数.  写一段优雅的代码,献给可爱的猿们微笑.

序:一直都很喜欢优雅的代码,也见过一些糟糕的代码,把编程当作一种享受,一种极致的追求,便能写出现阶段属于自己的优雅的代码.

从提一个简单的需求开始:现阶段需要实现一个同步Redis的小程序,当然有点经验的你自然不在话下,待我们一一道来.

  • 一个优雅的配置文件,如你所见,下列YML配置项目定义了ZK,Oracle数据源,Redis数据源,已经一个工作描述List<Map<String,String>> 格式的 works.

spring:
  application:
    name: ZXBK2REDIS
  #ZK
  cloud:
    zookeeper:
      enabled: true
      connect-string: host1:2181,host2:2181,host3:2181
      discovery:
        root: /services
        register: true
  #REDIS
  redis:
    database: 1
    host: host211
    port: 6379
    timeout: 1800000
    pool:
      max-active: 20
      min-idle: 5   
  #DB
  datasource:
    url: jdbc:oracle:thin:@localhsot:1521/ORCL
    username: root
    password: root
    driver-class-name: oracle.jdbc.driver.OracleDriver
#WORKS
tvc.sync.redis:
  works:
  - id: 1
    name: name1
    sql: select * from t1
    enabled: true
  - id: 2
    name: name2
    sql: select * from t2
    enabled: false
  - id: 3
    name: name3
    sql: select * from t3 
    enabled: true
  - id: 4
    name: name4
    sql: select * from t4
    enabled: true
  - id: 5
    name: name5
    sql: name5
    enabled: true

  • 我们需要做的是基于上述配置文件定义一个数据源,一个Redis的连接池,一个List<Map<String,String>>的集合对象

一个DataSource 数据源的定义

@Bean
@ConfigurationProperties(prefix = "spring.datasource")
public DataSource dataSource() {
	log.debug("DataSource INIT ");
	return DataSourceBuilder.create().build();
}

一个直接拿来使用的RedisTemplate对象

@Autowired
private RedisTemplate<String, String> redisTemplate;

一个直接绑定到Java集合的文本数据模型

@ConfigurationProperties(prefix = "tvc.sync.redis")
public class JobConfig {
	private List<Map<String, String>> works;

  • 经验法则,  代码的分布,并发的潜能,留一条后路. 看一段代码  关键代码加粗

@Component
public class TimerTask extends Thread implements ApplicationContextAware {
	public static final Log log = LogFactory.getLog(TimerTask.class);
	public static final Lock lock = new ReentrantLock();

	@Autowired
	private JobConfig jobConfig;

	@Autowired
	private RedisTemplate<String, String> redisTemplate;
	private ExecutorService workThreadPool;

	@Scheduled(cron = "${tvc.sync.redis.cron:0 0 2 * * ?}")
	public void syncRedisJob() {
		if (workThreadPool == null) {
			workThreadPool = Executors.newFixedThreadPool(jobConfig.getConcurrency());
		}
		if (!lock.tryLock()) {
			log.info("实例已经在同步!!!");
			return;
		}
		//
		List<Map<String, String>> works = new ArrayList<Map<String, String>>();
		for (Map<String, String> work : jobConfig.getWorks()) {
			if ("true".equals(work.get("enabled"))) {
				works.add(work);
			}
		}
		// 同步计数器
		CountDownLatch countDownLatch = new CountDownLatch(works.size());

		try {
			printSysStatus();
			// 同步标记
			redisTemplate.execute(new RedisCallback<Boolean>() {
				@Override
				public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
					connection.set("sync".getBytes(), "0".getBytes());
					log.info("sync:" + 0);
					return true;
				}
			});
			// 清库
			{
				log.info("开始清理数据");
				Set<String> keys = redisTemplate.keys("v:*");
				redisTemplate.delete(keys);
				/*
				 * for (String key : keys) { redisTemplate.delete(key); }
				 */
				log.info("清理结束,共:" + keys.size() + "条");
			}
			// 准备同步
			for (Map<String, String> work : works) {
				TaskRun taskRun = applicationContext.getBean(TaskRun.class);
				taskRun.setCountDownLatch(countDownLatch);
				taskRun.setWork(work);
				workThreadPool.execute(taskRun);
			}
			///
			try {
				countDownLatch.await(jobConfig.getTimeout(), TimeUnit.MINUTES);
			} catch (InterruptedException e) {
				e.printStackTrace();
				log.error("同步超时", e);
			}

		} finally {
			// 同步标记
			try {
				redisTemplate.execute(new RedisCallback<Boolean>() {

					@Override
					public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
						connection.set("sync".getBytes(), "1".getBytes());
						log.info("sync:" + 1);
						return true;
					}
				});

			} finally {
				lock.unlock();
			}
			if ("true".equals(jobConfig.getEndautogc())) {
				System.gc();
			}
		}

	}

	@Override
	public void run() {
		syncRedisJob();
	}

	// IOC初始化时调用一次 见IOCInit.java
	public void init() {
		this.start();
	}

	// 状态日志
	public void printSysStatus() {
		log.info(this);
	}

	@Override
	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
		this.applicationContext = applicationContext;
	}

	private ApplicationContext applicationContext;

	@Override
	public String toString() {
		return "TimerTask [jobConfig=" + jobConfig + ", redisTemplate=" + redisTemplate + ", workThreadPool="
				+ workThreadPool + ", applicationContext=" + applicationContext + "]";
	}
}

  • 允许并发无疑是意见好事,是允许而不是必须,我们当然可以使用一个大小为1的固定线程池来实现.
  • 总要谨慎潜在的危险. 合理是用finally 块无疑是一种保障. ,让等待付出代价是必要的,有限的超时.
  • 避免潜在的危险,真正属于自己的东西用起来才更放心.遍历删除一定要小心. 输出一个看的明白的的怪物总是有必要的.
  • 意外是有发生,也许就在明天,你只能启动一个.

最后多写几行代码,浏览器中可以调度一个作业那是在好不过了.

@RestController
public class RestHandler {
	@Autowired
	private TimerTask timerTask;
	@RequestMapping("/execute")
	public String immediatelyExecute() {
		new Thread() {
			public void run() {
				timerTask.run();
			};
		}.start();
		return timerTask.toString();
	}
}





  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值