首页 > 代码库 > [编织消息框架]数值与逻辑分离
[编织消息框架]数值与逻辑分离
为什么要分离?
业务需求是不停地变,如果把条件写进代码里,当用户需求变时要改代码发版本更新才能生效,这过程无疑是漫长的
就算是在开发期,不停的变开发者精力耗光在沟通,小修改上,无法专注逻辑部分
分离的根本目的是让开发者专注写引擎部分,无需关注太多业务上的边界,条件等
需要分离什么类型数值?
如活动开启时间,购买满足条件,购买上限等 这些不确定用户具体需求,全都可以弄成动态获取
分离技术实现有很多
如使用数据库mysql等
linux 常用的配置文本config
表格csv,json文件等
本项目用的是 java Properties 跟单例
1 import java.io.FileInputStream; 2 import java.io.InputStream; 3 import java.lang.reflect.Field; 4 import java.lang.reflect.Method; 5 import java.lang.reflect.Type; 6 import java.util.Collection; 7 import java.util.Collections; 8 import java.util.HashSet; 9 import java.util.Map; 10 import java.util.Properties; 11 import java.util.Set; 12 13 import javax.script.ScriptEngine; 14 import javax.script.ScriptEngineManager; 15 16 import org.apache.commons.lang3.reflect.TypeUtils; 17 18 import com.eyu.onequeue.reflect.anno.FieldValue; 19 import com.eyu.onequeue.util.SerialUtil; 20 21 /** 22 * @author solq 23 */ 24 public class PropertiesFactory { 25 static final ScriptEngine se = new ScriptEngineManager().getEngineByName("JavaScript"); 26 27 public static <T> T initField(Class<T> clz, String file) { 28 T ret = null; 29 try { 30 Properties pro = getProperties(file); 31 ret = clz.newInstance(); 32 Field[] fields = clz.getDeclaredFields(); 33 Set<Method> methods = new HashSet<>(); 34 Collections.addAll(methods, clz.getDeclaredMethods()); 35 // Field modifiersField = Field.class.getDeclaredField("modifiers"); 36 // modifiersField.setAccessible(true); 37 for (Field f : fields) { 38 FieldValue anno = f.getAnnotation(FieldValue.class); 39 if (anno == null) { 40 continue; 41 } 42 43 String fileName = anno.value(); 44 String tmp = (String) pro.get(fileName); 45 if (tmp == null) { 46 continue; 47 } 48 Object value =http://www.mamicode.com/ tmp; 49 Type type = f.getGenericType(); 50 if (type.equals(Integer.TYPE)) { 51 value =http://www.mamicode.com/ se.eval(tmp); 52 } else if (type.equals(Double.TYPE)) { 53 value =http://www.mamicode.com/ se.eval(tmp); 54 } else if (type.equals(Float.TYPE)) { 55 value =http://www.mamicode.com/ se.eval(tmp); 56 } else if (type.equals(Long.TYPE)) { 57 value =http://www.mamicode.com/ se.eval(tmp); 58 } else if (type.equals(Short.TYPE)) { 59 value =http://www.mamicode.com/ ((Integer) se.eval(tmp)).shortValue(); 60 } else if (type.equals(Byte.TYPE)) { 61 value =http://www.mamicode.com/ ((Integer) se.eval(tmp)).byteValue(); 62 } else if (type.equals(Boolean.TYPE)) { 63 value =http://www.mamicode.com/ se.eval(tmp); 64 } else if (TypeUtils.isAssignable(type, Map.class)) { 65 value =http://www.mamicode.com/ SerialUtil.readValue(tmp, type); 66 }else if (TypeUtils.isAssignable(type, Collection.class)) { 67 value =http://www.mamicode.com/ SerialUtil.readValue(tmp, type); 68 }else if (TypeUtils.isAssignable(type, Class.class)) { 69 value =http://www.mamicode.com/ Class.forName(tmp); 70 }else if (TypeUtils.isArrayType(type)) { 71 value =http://www.mamicode.com/ SerialUtil.readArray(tmp, type); 72 } 73 74 String callMethodName = "set" + f.getName(); 75 boolean flag = false; 76 try { 77 for (Method m : methods) { 78 if (m.getName().equals(callMethodName)) { 79 m.setAccessible(true); 80 m.invoke(ret, value); 81 flag = true; 82 break; 83 } 84 } 85 } catch (Exception e) { 86 87 } 88 if (flag) { 89 continue; 90 } 91 f.setAccessible(true); 92 // modifiersField.setInt(f, f.getModifiers() & ~Modifier.FINAL); 93 94 try { 95 f.set(ret, value); 96 } catch (Exception e1) { 97 e1.printStackTrace(); 98 } 99 }100 } catch (Exception e1) {101 e1.printStackTrace();102 }103 return ret;104 }105 106 public static Properties getProperties(String file) {107 Properties pro = new Properties();108 String path = ClassLoader.getSystemResource(file).getPath();109 try (InputStream fs = new FileInputStream(path);) {110 pro.load(fs);111 } catch (Exception e) {112 e.printStackTrace();113 }114 return pro;115 }116 }
为什么解释字符串部分用到 ScriptEngine ?
有些配置 如 QM.COMPRESS_SIZE = 1024*2 是个公式运算,要用引擎才能执行
1 /*** 2 * qm config 所有配置 属性不能加 final 否则 jvm 会优化 3 * 4 * @author solq 5 */ 6 public class QMConfig { 7 private static QMConfig instance = null; 8 9 public static QMConfig getInstance() {10 if (instance != null) {11 return instance;12 }13 synchronized (QMConfig.class) {14 if (instance != null) {15 return instance;16 }17 instance = PropertiesFactory.initField(QMConfig.class, "qm.properties");18 }19 return instance;20 }21 22 // other23 24 /** 启动服务模式 影响 记录存储目录 **/25 public boolean SERVER_MODEL = true;26 /** 集群服务器 <address> client端不能为NULL **/27 @FieldValue("QM.CLUSTER_LIST")28 /** 本地名称,多应用不能相同,注册时用到 client端不能为NULL **/29 public String LOCALNAME;30 /** 集群服务器 <address> client端不能为NULL **/31 @FieldValue("QM.CLUSTER_LIST")32 public Set<String> CLUSTER_LIST;33 /** 订阅信息 topic : groupId 填写开启 **/34 @FieldValue("QM.TOPIC_INFO")35 public Set<String> TOPIC_INFO;36 /** 日志保存路径 <订阅,路径> consume端不能为NULL **/37 @FieldValue("QM.CONSUME_LOG_SAVE_DIRS")38 public Map<String, String> CONSUME_LOG_SAVE_DIRS = new HashMap<>(1);39 40 public Collection<QSubscribe> getTopics() {41 Collection<QSubscribe> ret = new HashSet<>();42 if (TOPIC_INFO == null) {43 return ret;44 }45 for (String str : TOPIC_INFO) {46 String[] s = str.split(":");47 ret.add(QSubscribe.of(s[0], s[1]));48 }49 return ret;50 }51 52 /** rpc param compress **/53 @FieldValue("QM.COMPRESS_SIZE")54 public int COMPRESS_SIZE = 1024;55 56 // NETTY57 /** server port **/58 @FieldValue("QM.NETTY_SERVER_PORT")59 public int NETTY_SERVER_PORT = 8080;60 /** server bossgroup **/61 @FieldValue("QM.NETTY_SERVER_BOSSGROUP")62 public int NETTY_SERVER_BOSSGROUP = 1;63 /** server workergroup **/64 @FieldValue("QM.NETTY_SERVER_WORKERGROUP")65 public int NETTY_SERVER_WORKERGROUP = 4;66 /** server socket option **/67 @FieldValue("QM.NETTY_SERVER_SESSION_OPTION")68 public Map<String, ?> NETTY_SERVER_SESSION_OPTION;69 /** child socket option **/70 @FieldValue("QM.NETTY_SERVER_CHILD_SESSION_OPTION")71 public Map<String, ?> NETTY_SERVER_CHILD_SESSION_OPTION;72 /** 处理模型实现 **/73 @FieldValue("QM.NETTY_SERVER_ACCEPTOR")74 public Class<? extends ServerSocketChannel> NETTY_SERVER_ACCEPTOR = NioServerSocketChannel.class;75 76 ..............................77 78 }
QMConfig 是个单例使用时必须初始化配置文件 qm.properties 才能正常使用
使用properties 跟单例可以做出很好的效果,看了大多数框架花大多精力在配置上,有时复杂的不一定是最优
重复一下观点 出自UNIX编程艺术
分离的根本目的是让开发者专注写引擎部分,无需关注太多业务上的边界,条件等
[编织消息框架]数值与逻辑分离
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。