提交 0aa9bf9f 编写于 作者: 武汉红喜's avatar 武汉红喜

earth-web的辅助工程

上级 b383dfca
......@@ -10,7 +10,7 @@
| :- | :- |
whatsmars-common | mail,HttpUtils,AES,DES加解密
whatsmars-earth-web | springmvc+velocity实战
whatsmars-earth-support-web | 全局唯一ID生成简单实现
whatsmars-earth-support-web | earth-web的辅助工程
whatmars-fs-web | 用mongodb存储图片和文件
whatsmars-javase-example | Java基础学习
whatsmars-spring | spring深入研究
......
earth-web的辅助工程,提供任务调度、消息等功能
\ No newline at end of file
package com.whatsmars.earth.support.web.service.uuid;
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.whatsmars.earth.support.web.service.uuid;
/**
* 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.whatsmars.earth.support.web.service.uuid;
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.whatsmars.earth.support.web.service.uuid;
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.whatsmars.earth.support.web.service.uuid;
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.whatsmars.earth.support.web.service.uuid;
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.whatsmars.earth.support.web.service.uuid;
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.whatsmars.earth.support.web.service.uuid;
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.whatsmars.earth.support.web.service.uuid;
/**
* Created by shenhongxi on 2016/8/12.
*/
public interface UuidService {
/**
* 获取自增id,从1开始
* @param name
* @return
*/
String nextUuid(String name);
}
package com.whatsmars.earth.support.web.service.uuid;
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();
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册