提交 2eb96829 编写于 作者: S shenhongxi

uuid,dbrouter,worker

上级 89759be7
......@@ -25,6 +25,7 @@
<module>whatsmars-grpc-interface</module>
<module>whatsmars-grpc-service</module>
<module>whatsmars-grpc-client</module>
<module>whatsmars-uuid-web</module>
</modules>
<properties>
......
......@@ -126,6 +126,17 @@
<version>1.2.12</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.6</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjtools</artifactId>
<version>1.8.6</version>
</dependency>
</dependencies>
<build>
<finalName>${project.artifactId}</finalName>
......
package com.itlong.whatsmars.earth.support.web.job.base;
import com.itlong.whatsmars.earth.support.web.service.SimpleTaskService;
import com.itlong.whatsmars.earth.support.web.service.StandardTaskService;
import com.itlong.whatsmars.earth.support.web.service.TaskBaseService;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.List;
/**
* Created by shenhongxi on 2016/7/11.
*/
public abstract class AbstractJobExecutor implements JobExecutor {
protected TaskBaseService taskBaseService;
protected int batchSize;
protected String dbKey; // db1, db2
protected String tableIndex; // _0000, _0001
protected void execute(ThreadPoolTaskExecutor threadPoolTaskExecutor, StandardTaskService standardTaskService, List<Task> tasks) {
JobRunnable jobRunnable = new JobRunnable();
jobRunnable.setTasks(tasks);
jobRunnable.setStandardTaskService(standardTaskService);
jobRunnable.setTableIndex(tableIndex);
jobRunnable.setDbKey(dbKey);
threadPoolTaskExecutor.execute(jobRunnable);
}
protected void execute(ThreadPoolTaskExecutor threadPoolTaskExecutor, SimpleTaskService simpleTaskService, List<Task> tasks) {
SimpleJobRunnable jobRunnable = new SimpleJobRunnable();
jobRunnable.setTasks(tasks);
jobRunnable.setSimpleTaskService(simpleTaskService);
jobRunnable.setTableIndex(tableIndex);
jobRunnable.setDbKey(dbKey);
threadPoolTaskExecutor.execute(jobRunnable);
}
/**
* 计算批处理执行次数
* @param taskSize
* @param batchSize
* @return
*/
protected int computeBatchTimes(int taskSize, int batchSize){
int times = 0;
if (taskSize % batchSize > 0) {
times = taskSize / batchSize + 1;
}else{
times = taskSize / batchSize;
}
return times;
}
/**
* 计算批处开始
* @param taskSize
* @param batchSize
* @return
*/
protected int computeBatchFromIndex(int taskSize, int batchSize, int i){
int from = i * batchSize;
if(from > taskSize){
from = taskSize;
}
return from;
}
/**
* 计算批处理结束
* @param taskSize
* @param batchSize
* @return
*/
protected int computeBatchToIndex(int taskSize, int batchSize, int i){
int to = (i + 1) * batchSize;
if (to > taskSize){
to = taskSize;
}
return to;
}
public int getBatchSize() {
return batchSize;
}
public void setBatchSize(int batchSize) {
this.batchSize = batchSize;
}
public String getDbKey() {
return dbKey;
}
public void setDbKey(String dbKey) {
this.dbKey = dbKey;
DbContext.setDbKey(dbKey);
}
public String getTableIndex() {
return tableIndex;
}
public void setTableIndex(String tableIndex) {
this.tableIndex = tableIndex;
DbContext.setTableIndex(tableIndex);
}
public TaskBaseService getTaskBaseService() {
return taskBaseService;
}
public void setTaskBaseService(TaskBaseService taskBaseService) {
this.taskBaseService = taskBaseService;
}
}
package com.itlong.whatsmars.earth.support.web.job.base;
/**
* Created by shenhongxi on 2016/7/11.
*/
public class BaseDO {
private String phone; // 手机号码
private String tableIndex;
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getTableIndex() {
tableIndex = DbContext.getTableIndex();
return tableIndex;
}
public void setTableIndex(String tableIndex) {
this.tableIndex = tableIndex;
}
}
package com.itlong.whatsmars.earth.support.web.job.base;
/**
* Created by shenhongxi on 2016/7/12.
*/
public interface CacheService {
void set(String key, String value, long seconds);
String get(String key);
}
package com.itlong.whatsmars.earth.support.web.job.base;
/**
* Created by shenhongxi on 2016/7/11.
*/
public class DbContext {
private static final ThreadLocal<String> dbHolder = new ThreadLocal<String>();
private static final ThreadLocal<String> tableHolder = new ThreadLocal<String>();
public static void setDbKey(String dbKey) {
dbHolder.set(dbKey);
}
public static String getDbKey() {
return dbHolder.get();
}
public static void removeDbKey() {
dbHolder.remove();
}
public static void setTableIndex(String tableIndex) {
tableHolder.set(tableIndex);
}
public static String getTableIndex() {
return tableHolder.get();
}
public static void removeTableIndex() {
tableHolder.remove();
}
}
package com.itlong.whatsmars.earth.support.web.job.base;
/**
* Created by shenhongxi on 2016/7/11.
* 1. 一个job的多个实例,谁先成功锁定任务,谁先处理任务,若处理失败则解锁任务
* 2. 对于1中解锁失败的,要利用另外的job来专门进行解锁
* 3. 将任务分成几批,并行处理
* 4. 这些任务的子任务分批串行处理,同样有锁定-处理-失败解锁
* 5. 对于4中解锁失败的,同样要利用另外的job来专门进行解锁
*/
public interface JobExecutor {
void execute() throws Exception;
}
package com.itlong.whatsmars.earth.support.web.job.base;
import net.sf.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* Created by shenhongxi on 2016/7/12.
*/
public class JobGenerateExecutor extends AbstractJobExecutor {
private static final Logger log = LoggerFactory.getLogger(JobGenerateExecutor.class);
private int dbs;
private int tables;
private String tableFormat = "0000";
@Autowired
private CacheService cacheService;
private static final int cacheTime = 60*60*24-60*20; // 缓存时间23小时40分
@Override
public void execute() throws Exception {
log.info("shard job start!");
String taskType = new Integer(tableIndex).toString();
String today = new SimpleDateFormat("yyyyMMdd").format(new Date());
String _tableIndex; // 0000
String taskId = "";
String successFlag = "y";
String shardAllCacheKey = "shardAllJob_" + today;
if (successFlag.equals(cacheService.get(shardAllCacheKey))) {
log.info("任务已经全部生成,date:" + today);
} else {
boolean allSuccess = true;
DbContext.setTableIndex(tableIndex);
for (int i = 1; i <= dbs; i++) {
String dbKey = "db" + i;
DbContext.setDbKey(dbKey);
for (int j = 0; j < tables; j++) {
try {
_tableIndex = format(j, tableFormat);
taskId = today + _tableIndex;
String shardSingleCacheKey = "shardSingleJob_" + dbKey + "_" + taskId;
if (successFlag.equals(cacheService.get(shardSingleCacheKey))) {
log.info("此任务已经生成,dbKey:" + dbKey + ",taskId:" + taskId);
} else {
Task task = new Task();
task.setTaskId(taskId);
task.setType(taskType);
JSONObject json = new JSONObject();
json.put("lastId", 0L);
task.setData(json.toString());
taskBaseService.add(task);
log.info("生成任务成功。dbKey:" + dbKey + ",tableIndex:" + tableIndex + ",taskId:" + taskId);
}
} catch (Exception e) {
if (e.getMessage() != null && (e.getMessage().indexOf("Duplicate") >= 0 || e.getMessage().indexOf("UNIQUE KEY") >= 0
|| e.getMessage().indexOf("PRIMARY KEY") >= 0)) { // 任务重复,视为成功
log.info("生成任务重复。taskType:" + taskType + ",taskId:" + taskId);
}else{
log.error("生成任务异常。taskType:" + taskType + ",taskId:" + taskId, e);
allSuccess = false;
}
}
}
}
if (allSuccess) {
cacheService.set(shardAllCacheKey, successFlag, cacheTime);
}
}
}
private String format(int num, String format){
DecimalFormat df = new DecimalFormat();
df.applyPattern(format);
return df.format(num);
}
public int getDbs() {
return dbs;
}
public void setDbs(int dbs) {
this.dbs = dbs;
}
public int getTables() {
return tables;
}
public void setTables(int tables) {
this.tables = tables;
}
public String getTableFormat() {
return tableFormat;
}
public void setTableFormat(String tableFormat) {
this.tableFormat = tableFormat;
}
}
package com.itlong.whatsmars.earth.support.web.job.base;
import com.itlong.whatsmars.earth.support.web.service.StandardTaskService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
/**
* Created by shenhongxi on 2016/7/12.
*/
public class JobRunnable implements Runnable {
private static final Logger log = LoggerFactory.getLogger(JobRunnable.class);
private StandardTaskService standardTaskService;
private List<Task> tasks;
private String dbKey;
private String tableIndex;
@Override
public void run() {
if (tasks != null) {
if (log.isDebugEnabled()) {
log.debug("Current thread: " + Thread.currentThread().getName());
}
try {
DbContext.setDbKey(dbKey);
DbContext.setTableIndex(tableIndex);
for (Task task : tasks) {
task.setTableIndex(tableIndex);
// 1. 一个job的多个实例,谁先成功锁定任务,谁先处理任务,若处理失败则解锁任务
// 2. 对于1中解锁失败的,要利用另外的job来专门进行解锁
// 3. 将任务分成几批,并行处理
// 4. 这些任务的子任务分批串行处理,同样有锁定-处理-失败解锁
// 5. 对于4中解锁失败的,同样要利用另外的job来专门进行解锁
boolean locked = standardTaskService.lock(task);
if (!locked) continue;
boolean result = standardTaskService.process(task);
standardTaskService.finished(result, task);
}
} catch (Exception e) {
log.error("Do task error", e);
throw new RuntimeException("Do task error");
}
}
}
public List<Task> getTasks() {
return tasks;
}
public void setTasks(List<Task> tasks) {
this.tasks = tasks;
}
public StandardTaskService getStandardTaskService() {
return standardTaskService;
}
public void setStandardTaskService(StandardTaskService standardTaskService) {
this.standardTaskService = standardTaskService;
}
public String getTableIndex() {
return tableIndex;
}
public void setTableIndex(String tableIndex) {
this.tableIndex = tableIndex;
}
public String getDbKey() {
return dbKey;
}
public void setDbKey(String dbKey) {
this.dbKey = dbKey;
}
}
package com.itlong.whatsmars.earth.support.web.job.base;
import com.itlong.whatsmars.earth.support.web.service.SimpleTaskService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import javax.annotation.Resource;
import java.util.List;
/**
* Created by shenhongxi on 2016/7/12.
*/
public class JobUnlockExecutor extends AbstractJobExecutor {
private Logger log = LoggerFactory.getLogger(JobUnlockExecutor.class);
/** 配置任务最大锁定时间(秒)*/
private int splitSeconds = 60 * 5;
/** 配置失败重试次数 */
private int retries = 6;
/** 配置每次批处理个数 */
private int batchSize = 100;
/** 配置数据库个数 */
private int dbs;
@Autowired
private ThreadPoolTaskExecutor taskUnlockThreadPool;
@Resource(name="taskUnlockService")
private SimpleTaskService taskUnlockService;
@Override
public void execute() throws Exception {
try {
DbContext.setTableIndex(tableIndex);
for (int i = 1; i <= dbs; i++) {
String dbKey = "db" + i;
DbContext.setDbKey(dbKey);
List<Task> tasks = taskBaseService.findLocked(splitSeconds, retries);
if (tasks != null && tasks.size() > 0) {
int size = tasks.size();
log.info("取到被锁定任务条数:" + size + ",dbKey:" + dbKey);
int batchTimes = computeBatchTimes(size, batchSize);
for (int j = 0; j < batchTimes; j++) {
int from = computeBatchFromIndex(size, batchSize, j);
int to = computeBatchToIndex(size, batchSize, j);
this.execute(taskUnlockThreadPool, taskUnlockService, tasks.subList(from, to));
}
} else {
log.info("任务调度--没有被锁定的任务,dbkey:" + dbKey);
}
}
} catch (Exception e) {
log.error("任务调度--定期重置被锁定的任务异常", e);
}
}
public Integer getDbs() {
return dbs;
}
public void setDbs(Integer dbs) {
this.dbs = dbs;
}
public Integer getSplitSeconds() {
return splitSeconds;
}
public void setSplitSeconds(Integer splitSeconds) {
this.splitSeconds = splitSeconds;
}
public Integer getRetries() {
return retries;
}
public void setRetries(Integer retries) {
this.retries = retries;
}
public void setBatchSize(Integer batchSize) {
this.batchSize = batchSize;
}
}
package com.itlong.whatsmars.earth.support.web.job.base;
import java.util.HashMap;
import java.util.Map;
/**
* Created by shenhongxi on 2016/7/13.
*/
public class ParamHashMap<K,V> extends HashMap<K,V> {
private static final String TABLE_SUFFIX = "tableIndex";
@SuppressWarnings( "unchecked" )
public ParamHashMap(){
super();
this.put((K) TABLE_SUFFIX, (V) DbContext.getTableIndex());
}
@SuppressWarnings( "unchecked" )
public ParamHashMap(Map<? extends K, ? extends V> m){
super(m);
this.put((K)TABLE_SUFFIX, (V)DbContext.getTableIndex());
}
@SuppressWarnings( "unchecked" )
public ParamHashMap(int initialCapacity) {
super(initialCapacity);
this.put((K)TABLE_SUFFIX, (V)DbContext.getTableIndex());
}
@SuppressWarnings( "unchecked" )
public ParamHashMap(int initialCapacity, float loadFactor) {
super(initialCapacity,loadFactor);
this.put((K)TABLE_SUFFIX, (V) DbContext.getTableIndex());
}
private static final long serialVersionUID = 5541751367713832209L;
}
package com.itlong.whatsmars.earth.support.web.job.base;
import com.itlong.whatsmars.earth.support.web.service.SimpleTaskService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
/**
* Created by shenhongxi on 2016/7/12.
*/
public class SimpleJobRunnable implements Runnable {
private static final Logger log = LoggerFactory.getLogger(SimpleJobRunnable.class);
private SimpleTaskService simpleTaskService;
private List<Task> tasks;
private String dbKey;
private String tableIndex;
@Override
public void run() {
if (tasks != null) {
if (log.isDebugEnabled()) {
log.debug("Current simple thread: " + Thread.currentThread().getName());
}
try {
DbContext.setDbKey(dbKey);
DbContext.setTableIndex(tableIndex);
for (Task task : tasks) {
task.setTableIndex(tableIndex);
simpleTaskService.process(task);
}
} catch (Exception e) {
log.error("Do simple task error", e);
throw new RuntimeException("Do simple task error");
}
}
}
public List<Task> getTasks() {
return tasks;
}
public void setTasks(List<Task> tasks) {
this.tasks = tasks;
}
public String getTableIndex() {
return tableIndex;
}
public void setTableIndex(String tableIndex) {
this.tableIndex = tableIndex;
}
public String getDbKey() {
return dbKey;
}
public void setDbKey(String dbKey) {
this.dbKey = dbKey;
}
public SimpleTaskService getSimpleTaskService() {
return simpleTaskService;
}
public void setSimpleTaskService(SimpleTaskService simpleTaskService) {
this.simpleTaskService = simpleTaskService;
}
}
package com.itlong.whatsmars.earth.support.web.job.base;
import java.util.Date;
/**
* Created by shenhongxi on 2016/7/11.
*/
public class Task extends BaseDO {
private Long id;
private String taskId;
private String type;
private int status;
private String data; // json
private int retries;
private Date createDate;
private Date updateDate;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getTaskId() {
return taskId;
}
public void setTaskId(String taskId) {
this.taskId = taskId;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public int getStatus() {
return status;
}
public void setStatus(int status) {
this.status = status;
}
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
public int getRetries() {
return retries;
}
public void setRetries(int retries) {
this.retries = retries;
}
public Date getCreateDate() {
return createDate;
}
public void setCreateDate(Date createDate) {
this.createDate = createDate;
}
public Date getUpdateDate() {
return updateDate;
}
public void setUpdateDate(Date updateDate) {
this.updateDate = updateDate;
}
}
package com.itlong.whatsmars.earth.support.web.job.base;
import java.util.List;
/**
* Created by shenhongxi on 2016/7/12.
*/
public interface TaskDao {
void insert(Task task);
int updateSuccess(Task task);
int updateFailed(Task task);
int lock(Task task);
int unlock(Task task);
List<Task> findLocked(int splitSeconds, int retries);
List<Task> findByType(String type);
}
package com.itlong.whatsmars.earth.support.web.job.base;
import com.itlong.whatsmars.earth.dao.impl.BaseDao;
import java.util.List;
/**
* Created by shenhongxi on 2016/7/13.
*/
public class TaskDaoImpl extends BaseDao implements TaskDao {
@Override
public void insert(Task task) {
this.sqlSession.insert("Task.insert", task);
}
@Override
public int updateSuccess(Task task) {
return this.sqlSession.update("Task.updateSuccess", task);
}
@Override
public int updateFailed(Task task) {
return this.sqlSession.update("Task.updateFailed", task);
}
@Override
public int lock(Task task) {
return this.sqlSession.update("Task.lock", task);
}
@Override
public int unlock(Task task) {
return this.sqlSession.update("Task.unlock", task);
}
@Override
public List<Task> findLocked(int splitSeconds, int retries) {
ParamHashMap<String, Object> params = new ParamHashMap<String, Object>();
params.put("splitSeconds", splitSeconds);
params.put("retries", retries);
return this.sqlSession.selectList("Task.findLocked", params);
}
@Override
public List<Task> findByType(String type) {
ParamHashMap<String, Object> params = new ParamHashMap<String, Object>();
params.put("type", type);
return this.sqlSession.selectList("Task.findByType", params);
}
}
package com.itlong.whatsmars.earth.support.web.job.biz;
import com.itlong.whatsmars.earth.support.web.job.base.AbstractJobExecutor;
import com.itlong.whatsmars.earth.support.web.job.base.DbContext;
import com.itlong.whatsmars.earth.support.web.job.base.Task;
import com.itlong.whatsmars.earth.support.web.service.StandardTaskService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.List;
/**
* Created by shenhongxi on 2016/7/14.
*/
public class BizJobProcessExecutor extends AbstractJobExecutor {
private static final Logger log = LoggerFactory.getLogger(BizJobProcessExecutor.class);
private ThreadPoolTaskExecutor commonThreadPool;
private StandardTaskService standardTaskService;
@Override
public void execute() throws Exception {
DbContext.setDbKey(dbKey);
DbContext.setTableIndex(tableIndex);
String taskType = new Integer(tableIndex).toString();
try {
List<Task> tasks = taskBaseService.findByType(taskType);
if (tasks != null && tasks.size() > 0) {
int taskSize = tasks.size();
int batchTimes = computeBatchTimes(taskSize, batchSize);
for (int i = 0; i < batchTimes; i++) {
int from = computeBatchFromIndex(taskSize, batchSize, i);
int to = computeBatchToIndex(taskSize, batchSize, i);
this.execute(commonThreadPool, standardTaskService, tasks.subList(from, to));
}
} else {
log.info("没有未处理的任务");
}
} catch (Exception e) {
}
}
public ThreadPoolTaskExecutor getCommonThreadPool() {
return commonThreadPool;
}
public void setCommonThreadPool(ThreadPoolTaskExecutor commonThreadPool) {
this.commonThreadPool = commonThreadPool;
}
public StandardTaskService getStandardTaskService() {
return standardTaskService;
}
public void setStandardTaskService(StandardTaskService standardTaskService) {
this.standardTaskService = standardTaskService;
}
}
package com.itlong.whatsmars.earth.support.web.job.biz;
import com.itlong.whatsmars.earth.support.web.job.base.AbstractJobExecutor;
import com.itlong.whatsmars.earth.support.web.job.base.DbContext;
import com.itlong.whatsmars.earth.support.web.service.SimpleTaskService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import javax.annotation.Resource;
import java.text.DecimalFormat;
import java.util.List;
/**
* Created by shenhongxi on 16/7/16.
* 参考TaskUnlockJobExecutor
*/
public class BizJobUnlockExecutor extends AbstractJobExecutor {
private Logger log = LoggerFactory.getLogger(BizJobUnlockExecutor.class);
private int tables;
private String tableFormat = "0000";
@Resource(name = "bizUnlockThreadPool")
private ThreadPoolTaskExecutor bizUnlockThreadPool;
@Resource(name = "bizUnlockService")
private SimpleTaskService bizUnlockService;
@Override
public void execute() throws Exception {
// 循环各表查询锁定任务
for (int i = 0; i < tables; i++) {
try {
tableIndex = format(i, tableFormat);
DbContext.setTableIndex(tableIndex);
List list = null;
if (list != null && list.size() > 0) {
int taskSize = list.size();
int batchTimes = computeBatchTimes(taskSize, batchSize);
for (int j = 0; j < batchTimes; j++) {
int from = computeBatchFromIndex(taskSize, batchSize, i);
int to = computeBatchToIndex(taskSize, batchSize, i);
this.execute(bizUnlockThreadPool, bizUnlockService, list.subList(from, to));
}
} else {
log.info("没有被锁定的任务");
}
} catch (Exception e) {
log.error("unlock error",e);
}
}
}
private String format(int num, String format){
DecimalFormat df = new DecimalFormat();
df.applyPattern(format);
String ret=df.format(num);
return ret;
}
public int getTables() {
return tables;
}
public void setTables(int tables) {
this.tables = tables;
}
}
package com.itlong.whatsmars.earth.support.web.service.listener;
package com.itlong.whatsmars.earth.support.web.listener;
import net.sf.json.JSONObject;
import org.apache.activemq.ActiveMQConnectionFactory;
......
package com.itlong.whatsmars.earth.support.web.service;
import com.itlong.whatsmars.earth.support.web.job.base.Task;
/**
* Created by shenhongxi on 2016/7/11.
*/
public interface SimpleTaskService {
boolean process(Task task);
}
package com.itlong.whatsmars.earth.support.web.service;
import com.itlong.whatsmars.earth.support.web.job.base.Task;
/**
* Created by shenhongxi on 2016/7/11.
*/
public interface StandardTaskService {
boolean lock(Task task);
boolean process(Task task);
boolean finished(boolean processResult, Task task);
}
package com.itlong.whatsmars.earth.support.web.service;
import com.itlong.whatsmars.earth.support.web.job.base.Task;
import java.util.List;
/**
* Created by shenhongxi on 2016/7/12.
*/
public interface TaskBaseService {
void add(Task task);
boolean updateSuccess(Task task);
boolean lock(Task task);
boolean unlock(Task task);
List<Task> findLocked(int splitSeconds, int retries);
List<Task> findByType(String type);
}
package com.itlong.whatsmars.earth.support.web.service.biz;
import com.itlong.whatsmars.earth.support.web.job.base.DbContext;
import com.itlong.whatsmars.earth.support.web.job.base.Task;
import com.itlong.whatsmars.earth.support.web.service.impl.AbstractStandardTaskService;
import net.sf.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.MessageCreator;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import javax.annotation.Resource;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.Session;
import java.util.List;
/**
* Created by shenhongxi on 16/7/16.
*/
public class BizServiceImpl extends AbstractStandardTaskService {
private static final Logger log = LoggerFactory.getLogger(BizServiceImpl.class);
@Resource(name = "smsSender")
private JmsTemplate jmsTemplate;
@Resource(name = "taskMqExecutor")
private ThreadPoolTaskExecutor taskMqExecutor;
@Override
public boolean process(Task task) {
String taskTableIndex = DbContext.getTableIndex();
try {
String bizTableIndex = task.getTaskId().substring(6, task.getTaskId().length());
DbContext.setTableIndex(bizTableIndex);
JSONObject data = JSONObject.fromObject(task.getData());
final long lastId = data.getInt("lastId");
while (true) {
List list = null;
if (list == null || list.isEmpty()) {
log.info("任务全部处理完成,table:" + bizTableIndex);
return true;
}
for (final Object e : list) {
// 锁定
boolean lockResult = lock(e);
if (lockResult) {
taskMqExecutor.execute(new Runnable() {
@Override
public void run() {
jmsTemplate.send(new MessageCreator() {
@Override
public Message createMessage(Session session) throws JMSException {
JSONObject json = new JSONObject();
json.put("bizId", "");
return session.createTextMessage(json.toString());
}
});
}
});
}
}
}
} catch (Exception e) {
log.error("biz process error, taskId:" + task.getTaskId());
return false;
} finally {
DbContext.setTableIndex(taskTableIndex);
}
}
private boolean lock(Object e) {
// ...
return true;
}
}
package com.itlong.whatsmars.earth.support.web.service.biz;
import com.itlong.whatsmars.earth.support.web.job.base.Task;
import com.itlong.whatsmars.earth.support.web.service.SimpleTaskService;
/**
* Created by shenhongxi on 16/7/17.
*/
public class BizUnlockServiceImpl implements SimpleTaskService {
@Override
public boolean process(Task task) {
return false;
}
}
package com.itlong.whatsmars.earth.support.web.service.dbrouter;
import java.math.BigDecimal;
/**
* Created by shenhongxi on 16/7/16.
*/
public class AddOrderReq extends BaseReq {
private BigDecimal amount;
public BigDecimal getAmount() {
return amount;
}
public void setAmount(BigDecimal amount) {
this.amount = amount;
}
}
package com.itlong.whatsmars.earth.support.web.service.dbrouter;
/**
* Created by shenhongxi on 16/7/16.
*/
public class BaseDO {
private String userId;
private String tableIndex;
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getTableIndex() {
return tableIndex;
}
public void setTableIndex(String tableIndex) {
this.tableIndex = tableIndex;
}
}
package com.itlong.whatsmars.earth.support.web.service.dbrouter;
/**
* Created by shenhongxi on 16/7/16.
*/
public class BaseReq {
private String userId;
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
}
package com.itlong.whatsmars.earth.support.web.service.dbrouter;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface DbRoute {
String field() default "userId";
String tableStyle() default "0000";
}
\ No newline at end of file
package com.itlong.whatsmars.earth.support.web.service.dbrouter;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
@Aspect
@Component
public class DbRouteInterceptor {
private static final Logger log = LoggerFactory.getLogger(DbRouteInterceptor.class);
private DbRouter dbRouter;
public DbRouteInterceptor() {
}
@Pointcut("@annotation(com.itlong.bjxizhan.support.web.service.dbrouter.DbRoute)")
public void aopPoint() {
}
@Before("aopPoint()")
public Object doRoute(JoinPoint jp) throws Throwable {
boolean result = true;
Method method = this.getMethod(jp);
DbRoute dbRoute = (DbRoute)method.getAnnotation(DbRoute.class);
String routeField = dbRoute.field(); // userId
Object[] args = jp.getArgs();
if(args != null && args.length > 0) {
for(int i = 0; i < args.length; ++i) {
String routeFieldValue = BeanUtils.getProperty(args[i], routeField);
if(StringUtils.isNotEmpty(routeFieldValue)) {
if("userId".equals(routeField)) {
this.dbRouter.route(routeField);
}
break;
}
}
}
return Boolean.valueOf(result);
}
private Method getMethod(JoinPoint jp) throws NoSuchMethodException {
Signature sig = jp.getSignature();
MethodSignature msig = (MethodSignature)sig;
return this.getClass(jp).getMethod(msig.getName(), msig.getParameterTypes());
}
private Class<? extends Object> getClass(JoinPoint jp) throws NoSuchMethodException {
return jp.getTarget().getClass();
}
public DbRouter getDbRouter() {
return dbRouter;
}
public void setDbRouter(DbRouter dbRouter) {
this.dbRouter = dbRouter;
}
}
\ No newline at end of file
package com.itlong.whatsmars.earth.support.web.service.dbrouter;
import com.itlong.whatsmars.earth.support.web.job.base.DbContext;
import org.apache.commons.lang.StringUtils;
/**
* Created by shenhongxi on 16/7/16.
*/
public class DbRouter {
public void route(String fieldId) {
if(StringUtils.isEmpty(fieldId)) {
throw new IllegalArgumentException("dbsCount and tablesCount must be both positive!");
} else {
// base64编码得到的字符串取hashcode
int routeFieldInt = RouteUtils.getResourceCode(fieldId);
// 分库又分表
int dbs = 6;
int tbs = 200;
int mode = dbs * tbs;
Integer dbIndex = routeFieldInt % mode / tbs;
Integer tableIndex = routeFieldInt % tbs;
// tableIndex格式化
// dbIndex -> dbKey;
DbContext.setTableIndex(tableIndex.toString());
DbContext.setDbKey(dbIndex.toString());
}
}
}
package com.itlong.whatsmars.earth.support.web.service.dbrouter;
import com.itlong.whatsmars.earth.support.web.job.base.DbContext;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
/**
* Created by shenhongxi on 16/7/16.
*/
public class DynamicDataSource extends AbstractRoutingDataSource {
public DynamicDataSource() {
}
protected Object determineCurrentLookupKey() {
return DbContext.getDbKey(); // ThreadLocal
}
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="Order">
<sql id="all">
id,userId,orderId,amount
</sql>
<select id="insert" resultType="Order">
insert into xhd_order_$tableIndex$(userId,orderId,amount) values(#userId#,#orderId#,#amount#)
</select>
</mapper>
package com.itlong.whatsmars.earth.support.web.service.dbrouter;
import java.math.BigDecimal;
/**
* Created by shenhongxi on 16/7/16.
*/
public class OrderDO extends BaseDO {
private String orderId;
private BigDecimal amount;
public String getOrderId() {
return orderId;
}
public void setOrderId(String orderId) {
this.orderId = orderId;
}
public BigDecimal getAmount() {
return amount;
}
public void setAmount(BigDecimal amount) {
this.amount = amount;
}
}
package com.itlong.whatsmars.earth.support.web.service.dbrouter;
/**
* Created by shenhongxi on 16/7/16.
*/
public interface OrderDao {
void insert(OrderDO order);
}
package com.itlong.whatsmars.earth.support.web.service.dbrouter;
import com.itlong.whatsmars.earth.dao.impl.BaseDao;
/**
* Created by shenhongxi on 16/7/16.
*/
public class OrderDaoImpl extends BaseDao implements OrderDao {
@Override
public void insert(OrderDO order) {
this.sqlSession.insert("Order.insert", order);
}
}
package com.itlong.whatsmars.earth.support.web.service.dbrouter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* Created by shenhongxi on 16/7/16.
*/
@Service("orderService")
public class OrderServiceImpl {
@Autowired
private OrderDao orderDao;
@DbRoute(field = "userId", tableStyle = "0000")
public void addOrder(AddOrderReq req) {
OrderDO order = new OrderDO();
order.setUserId(req.getUserId());
order.setOrderId(order.getUserId() + System.currentTimeMillis());
order.setAmount(req.getAmount());
orderDao.insert(order);
}
}
package com.itlong.whatsmars.earth.support.web.service.dbrouter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class RouteUtils {
private static final Logger log = LoggerFactory.getLogger(RouteUtils.class);
private static final String encode = "utf-8";
private static final int resourceMax = 10000;
public RouteUtils() {
}
public static int getHashCodeBase64(String routeValue) {
int hashCode = 0;
try {
//String e = Base64Binrary.encodeBase64Binrary(routeValue.getBytes("utf-8"));
//hashCode = Math.abs(e.hashCode());
} catch (Exception var3) {
log.error("hashCode 失败", var3);
}
return hashCode;
}
public static int getResourceCode(String routeValue) {
int hashCode = getHashCodeBase64(routeValue);
int resourceCode = hashCode % 10000;
return resourceCode;
}
public static void main(String[] args) {
String payid = "140331160123935469773";
String resource = payid.substring(payid.length() - 4);
int routeFieldInt = Integer.valueOf(resource).intValue();
short mode = 1200;
int dbIndex = routeFieldInt % mode / 200;
int tbIndex = routeFieldInt % 200;
System.out.println(dbIndex + "-->" + tbIndex);
}
}
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd"
default-autowire="byName">
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:dbcp-config.properties" />
</bean>
<bean id="dataSource1" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="${bjxizhan.jdbc.mysql.url}?useUnicode=true&amp;characterEncoding=UTF-8&amp;autoReconnect=true"></property>
<property name="username" value="${bjxizhan.jdbc.mysql.username}"></property>
<property name="password" value="${bjxizhan.jdbc.mysql.password}"></property>
<property name="maxActive" value="${dbcp.maxActive}"></property>
<property name="maxIdle" value="${dbcp.maxIdle}"></property>
<property name="minIdle" value="${dbcp.minIdle}"></property>
<property name="maxWait" value="${dbcp.maxWait}"></property>
<property name="defaultAutoCommit" value="${dbcp.defaultAutoCommit}"></property>
<property name="timeBetweenEvictionRunsMillis" value="${dbcp.timeBetweenEvictionRunsMillis}"></property>
<property name="minEvictableIdleTimeMillis" value="${dbcp.minEvictableIdleTimeMillis}"></property>
</bean>
<bean id="dataSource2" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="${bjxizhan.jdbc.mysql.url}?useUnicode=true&amp;characterEncoding=UTF-8&amp;autoReconnect=true"></property>
<property name="username" value="${bjxizhan.jdbc.mysql.username}"></property>
<property name="password" value="${bjxizhan.jdbc.mysql.password}"></property>
<property name="maxActive" value="${dbcp.maxActive}"></property>
<property name="maxIdle" value="${dbcp.maxIdle}"></property>
<property name="minIdle" value="${dbcp.minIdle}"></property>
<property name="maxWait" value="${dbcp.maxWait}"></property>
<property name="defaultAutoCommit" value="${dbcp.defaultAutoCommit}"></property>
<property name="timeBetweenEvictionRunsMillis" value="${dbcp.timeBetweenEvictionRunsMillis}"></property>
<property name="minEvictableIdleTimeMillis" value="${dbcp.minEvictableIdleTimeMillis}"></property>
</bean>
<bean id="dynamicDataSource" class="com.itlong.bjxizhan.support.web.service.dbrouter.DynamicDataSource">
<property name="targetDataSources">
<map key-type="java.lang.String">
<entry key="db1" value-ref="dataSource1"/>
<entry key="db2" value-ref="dataSource2"/>
</map>
</property>
</bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dynamicDataSource" />
<property name="configLocation" value="classpath:sqlmap-config.xml"></property>
<!-- <property name="dataSource" ref="dataSource" /> -->
</bean>
<bean name="jdbcTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dynamicDataSource"/>
</bean>
<bean name="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
<property name="transactionManager" ref="jdbcTransactionManager" />
<property name="isolationLevelName" value="ISOLATION_READ_COMMITTED"/>
<property name="timeout" value="30"/>
</bean>
<!-- core api -->
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg index="0" ref="sqlSessionFactory" />
</bean>
</beans>
\ No newline at end of file
package com.itlong.whatsmars.earth.support.web.service.impl;
import com.itlong.whatsmars.earth.support.web.job.base.Task;
import com.itlong.whatsmars.earth.support.web.service.StandardTaskService;
import com.itlong.whatsmars.earth.support.web.service.TaskBaseService;
import org.springframework.beans.factory.annotation.Autowired;
/**
* Created by shenhongxi on 2016/7/12.
*/
public abstract class AbstractStandardTaskService implements StandardTaskService {
@Autowired
private TaskBaseService taskBaseService;
@Override
public boolean finished(boolean processResult, Task task) {
if(processResult){
return taskBaseService.updateSuccess(task);
} else {
taskBaseService.unlock(task);
}
return true;
}
@Override
public boolean lock(Task task) {
return taskBaseService.lock(task);
}
}
package com.itlong.whatsmars.earth.support.web.service.impl;
import com.itlong.whatsmars.earth.support.web.job.base.Task;
import com.itlong.whatsmars.earth.support.web.job.base.TaskDao;
import com.itlong.whatsmars.earth.support.web.service.TaskBaseService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* Created by shenhongxi on 2016/7/12.
*/
@Service("taskBaseService")
public class TaskBaseServiceImpl implements TaskBaseService {
@Autowired
private TaskDao taskDao;
@Override
public void add(Task task) {
taskDao.insert(task);
}
@Override
public boolean updateSuccess(Task task) {
try {
return taskDao.updateSuccess(task) > 0;
} catch (Exception e) {
return false;
}
}
@Override
public boolean lock(Task task) {
try {
return taskDao.lock(task) > 0;
} catch (Exception e) {
return false;
}
}
@Override
public boolean unlock(Task task) {
try {
return taskDao.unlock(task) > 0;
} catch (Exception e) {
return false;
}
}
@Override
public List<Task> findLocked(int splitSeconds, int retries) {
return taskDao.findLocked(splitSeconds, retries);
}
@Override
public List<Task> findByType(String type) {
return taskDao.findByType(type);
}
}
package com.itlong.whatsmars.earth.support.web.service.impl;
import com.itlong.whatsmars.earth.support.web.job.base.Task;
import com.itlong.whatsmars.earth.support.web.job.base.TaskDao;
import com.itlong.whatsmars.earth.support.web.service.SimpleTaskService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* Created by shenhongxi on 2016/7/12.
*/
@Service("taskFailedService")
public class TaskFailedServiceImpl implements SimpleTaskService {
@Autowired
private TaskDao taskDao;
@Override
public boolean process(Task task) {
try {
return taskDao.updateFailed(task) > 0;
} catch (Exception e) {
return false;
}
}
}
package com.itlong.whatsmars.earth.support.web.service.impl;
import com.itlong.whatsmars.earth.support.web.job.base.Task;
import com.itlong.whatsmars.earth.support.web.job.base.TaskDao;
import com.itlong.whatsmars.earth.support.web.service.SimpleTaskService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* Created by shenhongxi on 2016/7/12.
*/
@Service("taskUnlockService")
public class TaskUnlockServiceImpl implements SimpleTaskService {
@Autowired
private TaskDao taskDao;
@Override
public boolean process(Task task) {
try {
return taskDao.unlock(task) > 0;
} catch (Exception e) {
return false;
}
}
}
package com.itlong.whatsmars.earth.support.web.service.job;
/**
* Created by shenhongxi on 2016/4/6.
*/
public class TestJob {
public void execute() {
// send mq
}
}
package com.itlong.whatsmars.earth.support.web.service.monitor;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Created by shenhongxi on 2016/8/10.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
public @interface Monitor {
String DEFAULT_TAG_NAME = "@@USE_METHOD_NAME";
String tag() default "@@USE_METHOD_NAME";
String message() default "";
boolean heart() default false;
}
package com.itlong.whatsmars.earth.support.web.service.monitor;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
/**
* Created by shenhongxi on 2016/8/10.
*/
@Aspect
public class MonitorAspect {
private String tagPrefix;
@Around(
value = "execution(* *(..)) && @annotation(monitor)",
argNames = "pjp,monitor"
)
public Object doUmpLogging(ProceedingJoinPoint pjp, Monitor monitor) throws Throwable {
// String tag = monitor.tag();
// boolean heart = monitor.heart();
long start = System.currentTimeMillis();
// record invocation (times)
Object obj = null;
try {
obj = pjp.proceed();
} catch (Exception e) {
// record error
throw e;
} finally {
long end = System.currentTimeMillis();
// record time -> end - start
}
return obj;
}
public String getTagPrefix() {
return tagPrefix;
}
public void setTagPrefix(String tagPrefix) {
this.tagPrefix = tagPrefix;
}
}
......@@ -14,7 +14,7 @@
<constructor-arg index="0" value="${whatsmars.activemq.queue.withdraw}"></constructor-arg>
</bean>
<bean id="withdrawQueueListener" class="com.itlong.whatsmars.earth.support.web.service.listener.TestListener"/>
<bean id="withdrawQueueListener" class="com.itlong.whatsmars.earth.support.web.listener.TestListener"/>
<bean class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="connectionFactory"></property>
<property name="destination" ref="withdrawQueueDestination"></property>
......
package com.itlong.whatsmars.fs.web;
package com.itlong.whatsmars.uuid.web;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;
......
package com.itlong.whatsmars.fs.web.controller;
package com.itlong.whatsmars.uuid.web.controller;
import com.itlong.whatsmars.common.CommonConstants;
import com.itlong.whatsmars.common.pojo.Result;
import com.itlong.whatsmars.common.pojo.ResultCode;
import com.itlong.whatsmars.common.util.DESUtils;
import com.itlong.whatsmars.common.util.ResultHelper;
import com.itlong.whatsmars.fs.web.service.FileService;
import com.itlong.whatsmars.uuid.web.service.FileService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
......
package com.itlong.whatsmars.fs.web.controller;
package com.itlong.whatsmars.uuid.web.controller;
import com.itlong.whatsmars.common.pojo.ResultCode;
import com.itlong.whatsmars.common.util.ResultHelper;
......
package com.itlong.whatsmars.fs.web.filter;
package com.itlong.whatsmars.uuid.web.filter;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
......
package com.itlong.whatsmars.fs.web.service;
package com.itlong.whatsmars.uuid.web.service;
import com.itlong.whatsmars.common.pojo.Result;
......
package com.itlong.whatsmars.fs.web.service.impl;
package com.itlong.whatsmars.uuid.web.service.impl;
import com.itlong.whatsmars.common.ImageSizeEnum;
import com.itlong.whatsmars.common.mongo.GridFSClient;
import com.itlong.whatsmars.common.pojo.Result;
import com.itlong.whatsmars.common.pojo.ResultCode;
import com.itlong.whatsmars.fs.web.service.FileService;
import com.itlong.whatsmars.uuid.web.service.FileService;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
......
......@@ -29,6 +29,6 @@
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>
<bean id="exceptionResolver" class="com.itlong.whatsmars.fs.web.ExceptionHandler"/>
<bean id="exceptionResolver" class="ExceptionHandler"/>
</beans>
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>whatsmars-parent</artifactId>
<groupId>com.itlong</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>whatsmars-uuid-web</artifactId>
<packaging>war</packaging>
<name>${project.artifactId}</name>
<url>http://maven.apache.org</url>
<properties>
<spring.version>3.2.11.RELEASE</spring.version>
<slf4j.version>1.7.5</slf4j.version>
</properties>
<!-- 依赖包 -->
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.4</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${slf4j.version}</version>
</dependency>
</dependencies>
<build>
<finalName>${project.artifactId}</finalName>
<outputDirectory>src/main/webapp/WEB-INF/classes</outputDirectory>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>2.6</version>
<configuration>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-release-plugin</artifactId>
<version>2.1</version>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>development</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<build>
<filters>
<filter>../profile/development.properties</filter>
</filters>
</build>
</profile>
<profile>
<id>test</id>
<build>
<filters>
<filter>../profile/test.properties</filter>
</filters>
</build>
</profile>
<profile>
<id>production</id>
<build>
<filters>
<filter>../profile/production.properties</filter>
</filters>
</build>
</profile>
</profiles>
</project>
\ No newline at end of file
package com.itlong.whatsmars.uuid.web;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
public class AppConfig {
static final Properties p = new Properties();
static{
try{
File fp = new File(AppConfig.class.getResource("/props/config.properties").toURI());
p.load(new FileInputStream(fp));
}catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("找不到config属性文件");
}
}
public static int getInt(String key){
return Integer.parseInt(p.getProperty(key));
}
public static String getValue(String key) throws Exception{
return p.getProperty(key);
}
public static String trim(String s){
return s == null ? "" : s.trim();
}
public static void loadProperty(InputStream in) throws IOException{
p.load(in);
}
}
package com.itlong.whatsmars.uuid.web;
/**
* Created by shenhongxi on 2016/8/12.
*/
public class Config {
/**
* 业务名称
*/
private String name;
/**
* 内存运算个数
*/
private int cacheSize;
/**
* 生成自增数长度
*/
private int length;
/**
* 填充字符
*/
private String fillChar;
/**
* 前缀
*/
private String prefix;
/**
* 后缀
*/
private String suffix;
/**
* 自增预警数
*/
private long warnNum;
/**
* 重置数
*/
private long resetNum;
/**
* 1 uuid=前缀+自增数+后缀
*/
private int strategy;
public int getCacheSize() {
return cacheSize;
}
public void setCacheSize(int cacheSize) {
this.cacheSize = cacheSize;
}
public int getLength() {
return length;
}
public void setLength(int length) {
this.length = length;
}
public String getFillChar() {
return fillChar;
}
public void setFillChar(String fillChar) {
this.fillChar = fillChar;
}
public String getPrefix() {
return prefix;
}
public void setPrefix(String prefix) {
this.prefix = prefix;
}
public String getSuffix() {
return suffix;
}
public void setSuffix(String suffix) {
this.suffix = suffix;
}
public long getWarnNum() {
return warnNum;
}
public void setWarnNum(long warnNum) {
this.warnNum = warnNum;
}
public long getResetNum() {
return resetNum;
}
public void setResetNum(long resetNum) {
this.resetNum = resetNum;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getStrategy() {
return strategy;
}
public void setStrategy(int strategy) {
this.strategy = strategy;
}
}
package com.itlong.whatsmars.uuid.web;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* Created by shenhongxi on 2016/8/12.
*/
public class Main {
static ApplicationContext context;
public static void init() {
context = new ClassPathXmlApplicationContext("classpath*:spring-config.xml");
}
public static void main(String[] args) {
init();
UuidContext.init();
UuidServiceImpl uuidService = (UuidServiceImpl) context.getBean("uuidService");
Thread t = new TestThread("TESTPSBC", uuidService);
Thread t1 = new TestThread("TESTPSBC", uuidService);
Thread t2 = new TestThread("TESTPSBC", uuidService);
Thread t3 = new TestThread("TESTPSBC", uuidService);
Thread t4 = new TestThread("TEST5CMB", uuidService);
Thread t5 = new TestThread("TEST5CMB", uuidService);
Thread t6 = new TestThread("TEST5CMB", uuidService);
Thread t7 = new TestThread("TEST5CMB", uuidService);
t.start();
t1.start();
t2.start();
t3.start();
t4.start();
t5.start();
t6.start();
t7.start();
}
}
package com.itlong.whatsmars.uuid.web;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
public class SpringHelper implements ServletContextListener {
private static ServletContext servletContext = null;
private static final String SPRING_XML_CLASS_PATH_STR = "classpath*:spring*.xml";
private static ApplicationContext noContainerCtxt = null;
public static ApplicationContext getContext(){
if(servletContext != null)
return WebApplicationContextUtils.getWebApplicationContext(servletContext);
if(noContainerCtxt != null)
return noContainerCtxt;
synchronized (SPRING_XML_CLASS_PATH_STR) {
if(noContainerCtxt == null){
noContainerCtxt = new ClassPathXmlApplicationContext(new String[]{SPRING_XML_CLASS_PATH_STR});
}
}
return noContainerCtxt;
}
@SuppressWarnings("unchecked")
public static <T> T getBean(String name, Class<T> clazz) {
return (T)getContext().getBean(name, clazz);
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
;
}
@Override
public void contextInitialized(ServletContextEvent sce) {
try {
UuidContext.init();
} catch (Exception e) {
e.printStackTrace();
}
}
}
package com.itlong.whatsmars.uuid.web;
public class TestThread extends Thread{
String name;
UuidServiceImpl us;
public TestThread(String name, UuidServiceImpl us) {
this.name = name;
this.us = us;
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println(Thread.currentThread().getName() + ":" + us.nextUuid(name));
}
}
}
package com.itlong.whatsmars.uuid.web;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
/**
* Created by shenhongxi on 2016/8/12.
*/
public class UuidContext {
private static final Logger log = LoggerFactory.getLogger(UuidContext.class);
// 缓存DB中的截止数
public static ConcurrentMap<String, Long> endCache = new ConcurrentHashMap<String,Long>();
// 缓存当前增加到的数值
public static ConcurrentMap<String, Long> nowCache = new ConcurrentHashMap<String,Long>();
// 缓存共享对象
public static ConcurrentMap<String, UuidModel> uuidCache = new ConcurrentHashMap<String, UuidModel>();
// 缓存配置
public static ConcurrentMap<String, Config> configCache = new ConcurrentHashMap<String, Config>();
static UuidDao uuidDao;
public static void init(){
loadConfig();
uuidDao = SpringHelper.getBean("uuidDao", UuidDao.class);
List<UuidModel> list = uuidDao.getAll();
for (UuidModel um : list) {
Config cm = getConfig(um.getName());
updateUuid(um, cm.getLength());
loadMemory(um);
}
}
/**
* 根据名称更新号段 直至成功
* @param um
* @return
*/
public static UuidModel updateUuid(UuidModel um, int length){
boolean updated = false;
do{
UuidModel _um = uuidDao.findByName(um.getName());
int cacheSize = 1000;
Config config = getConfig(um.getName());
if (config != null) {
cacheSize = config.getCacheSize();
}
// 判断是否需要重置 条件为:1.配置的重置数<新段的截止数 则需要重置
// 2.新段的截止数大于需要获取的位数 则需要重置
long resetNum = config.getResetNum();
// 取得新段的截止数
long newEnd = _um.getEnd() + cacheSize;
um.setOldEnd(_um.getEnd());
um.setOldStart(_um.getStart());
if ((resetNum < newEnd) || (String.valueOf(newEnd).length() > length)) {
// 需要重置为0开始段
um.setStart(0);
um.setEnd(cacheSize);
} else {
// 取新段
um.setStart(_um.getEnd());
um.setEnd(_um.getEnd() + cacheSize);
}
// 最终的更新成功保证了多实例部署时,各实例持有的号段不同
updated = uuidDao.update(um);
} while (!updated);
return um;
}
/**
* 载入内存
* @param um
*/
public static void loadMemory(UuidModel um){
endCache.put(um.getName(), um.getEnd());
nowCache.put(um.getName(), um.getStart());
uuidCache.put(um.getName(), um);
}
public static Config getConfig(String name) {
Config config = configCache.get(name);
if (config == null) {
config = configCache.get("default");
}
return config;
}
private static void loadConfig(){
try {
String businesses = AppConfig.getValue("businesses");
for(String biz : businesses.split(",")){
String bizConfig = AppConfig.getValue(biz);
String[] configs = bizConfig.split(",");
int cacheSize = Integer.valueOf(configs[0]);
int length = Integer.valueOf(configs[1]);
String fillChar = configs[2];
long warnNum = Long.valueOf(configs[3]);
long resetNum = Long.valueOf(configs[4]);
int tactics = Integer.valueOf(configs[5]);
Config config = new Config();
config.setCacheSize(cacheSize);
config.setFillChar(fillChar);
config.setLength(length);
config.setPrefix("");
config.setSuffix("");
config.setStrategy(tactics);
config.setResetNum(resetNum);
config.setWarnNum(warnNum);
config.setName(biz);
configCache.put(biz, config);
}
log.info("load config success");
} catch (Exception e) {
log.error("load config error", e);
}
}
}
package com.itlong.whatsmars.uuid.web;
import java.util.List;
/**
* Created by shenhongxi on 2016/8/12.
*/
public interface UuidDao {
boolean insert(UuidModel uuidModel);
boolean update(UuidModel uuidModel);
List<UuidModel> getAll();
UuidModel findByName(String name);
}
package com.itlong.whatsmars.uuid.web;
import java.io.Serializable;
/**
* Created by shenhongxi on 2016/8/12.
*/
public class UuidModel implements Serializable {
private static final long serialVersionUID = 972714740313784893L;
private String name;
private long start;
private long end;
// above is DB column
private long oldStart;
private long oldEnd;
private long now;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public long getStart() {
return start;
}
public void setStart(long start) {
this.start = start;
}
public long getEnd() {
return end;
}
public void setEnd(long end) {
this.end = end;
}
public long getOldStart() {
return oldStart;
}
public void setOldStart(long oldStart) {
this.oldStart = oldStart;
}
public long getOldEnd() {
return oldEnd;
}
public void setOldEnd(long oldEnd) {
this.oldEnd = oldEnd;
}
public long getNow() {
return now;
}
public void setNow(long now) {
this.now = now;
}
}
package com.itlong.whatsmars.uuid.web;
/**
* Created by shenhongxi on 2016/8/12.
*/
public interface UuidService {
/**
* 获取自增id,从1开始
* @param name
* @return
*/
String nextUuid(String name);
}
package com.itlong.whatsmars.uuid.web;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* Created by shenhongxi on 2016/8/12.
*/
public class UuidServiceImpl implements UuidService {
private static final Logger log = LoggerFactory.getLogger(UuidServiceImpl.class);
private UuidDao uuidDao;
@Override
public String nextUuid(String name) {
Config config = UuidContext.getConfig(name);
String format = config.getPrefix() + "#" + config.getSuffix();
if (config.getStrategy() == 0) {
// 使用策略0 日期+自增
String formatDate = format(new Date(), "yyMMdd");
format = formatDate + config.getPrefix() + "#" + config.getSuffix();
} else { // 其他策略
}
long nextUuid = nextUuid(name, config.getCacheSize(), config.getLength());
String value = formatUuid(nextUuid, config.getLength(), config.getFillChar());
return format.replace("#", value);
}
private synchronized long nextUuid(String name, int cacheSize, int length) {
UuidModel um = UuidContext.uuidCache.get(name);
Long nowUuid = null;
try {
if (um != null) {
synchronized (um) {
nowUuid = UuidContext.nowCache.get(name);
Config cm = UuidContext.getConfig(name);
// 判断是否到达预警值
if (UuidContext.nowCache.get(name).intValue() == cm.getWarnNum()) {
log.warn("警告:" + name + "号段已达到预警值.");
}
log.info("dbNum:" + UuidContext.endCache.get(name)
+ ",nowNum:" + UuidContext.nowCache.get(name));
// 判断内存中号段是否用完
if (UuidContext.nowCache.get(name).compareTo(UuidContext.endCache.get(name)) >= 0) {
// 更新号段
UuidContext.updateUuid(um, length);
nowUuid = um.getStart() + 1;
UuidContext.endCache.put(name, um.getEnd());
UuidContext.nowCache.put(name, nowUuid);
} else {
nowUuid += 1;
// 是否需要重置 判断自增号位数是否大于length参数
if (String.valueOf(nowUuid).length() > length) {
// 更新号段,需要重置
nowUuid = 1l;
UuidContext.updateUuid(um, 0);
UuidContext.endCache.put(name, um.getEnd());
UuidContext.nowCache.put(name, nowUuid);
UuidContext.uuidCache.put(name, um);
} else {
// 直接修改缓存的值就可以了
UuidContext.nowCache.put(name, nowUuid);
}
}
}
} else {
synchronized (this) {
um = UuidContext.uuidCache.get(name);
if (um != null) {
return nextUuid(name, cacheSize, length);
}
nowUuid = 1l;
// 如果缓存不存在,那么就新增到数据库
UuidModel um2 = new UuidModel();
um2.setName(name);
um2.setStart(0);
um2.setEnd(cacheSize);
uuidDao.insert(um2);
// 还要同时在缓存的map中加入
UuidContext.endCache.put(name, um2.getEnd());
UuidContext.nowCache.put(name, nowUuid);
UuidContext.uuidCache.put(name, um2);
}
}
} catch (Exception e) {
log.error("生成uuid error", e);
if (e.getMessage() != null && (e.getMessage().indexOf("UNIQUE KEY") >= 0 ||
e.getMessage().indexOf("PRIMARY KEY") >= 0)) {
UuidModel _um = new UuidModel();
_um.setName(name);
// 更新号段
UuidContext.updateUuid(_um, length);
// 载入缓存
UuidContext.loadMemory(_um);
// 继续获取
return nextUuid(name, cacheSize, length);
}
throw new RuntimeException("生成uuid error");
}
return nowUuid;
}
private static String format(Date time, String fmt) {
SimpleDateFormat sdf = new SimpleDateFormat(fmt);
return sdf.format(time);
}
private String formatUuid(long nextUuid, int length, String fillChar) {
StringBuffer buffer = new StringBuffer("");
int len = length - ("" + nextUuid).length();
for (int i = 0; i < len; i++) {
buffer.append(fillChar);
}
buffer.append("" + nextUuid);
return buffer.toString();
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"
default-autowire="byName">
<!-- 属性文件读入 -->
<context:component-scan base-package="com.itlong.bjxizhan.uuid" />
<aop:aspectj-autoproxy/>
<bean
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:*.properties</value>
</list>
</property>
</bean>
<!-- Spring配置文件读入 -->
<import resource="classpath:spring-*.xml" />
</beans>
\ No newline at end of file
<?xml version="1.0" encoding="GBK"?>
<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-config.xml</param-value>
</context-param>
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<listener>
<listener-class>org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap</listener-class>
</listener>
<listener>
<listener-class>org.jboss.resteasy.plugins.spring.SpringContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>Resteasy</servlet-name>
<servlet-class>
org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Resteasy</servlet-name>
<url-pattern>/service/*</url-pattern>
</servlet-mapping>
<!-- spring context helper -->
<listener>
<listener-class>com.itlong.bjxizhan.uuid.SpringHelper</listener-class>
</listener>
</web-app>
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册