1.diamond-server工程里 使用了我们常用的一些技术 比如spring springmvc jsbctamplate 等等这些技术
jar包如下
2.首先我们先从启动tomcat的时候 加载bean的时候 会有三个bean进行初始化数据的bean开始分析
2.1加载diamond-server其他实例的ip地址和端口号
com.taobao.diamond.server.service.NotifyService
[java] view plaincopy
- @PostConstruct
- public void loadNodes() {
- InputStream in = null;
- try {
- in = ResourceUtils.getResourceAsStream("node.properties");
- nodeProperties.load(in);
- }
- catch (IOException e) {
- log.error("加载节点配置文件失败");
- }
- finally {
- try {
- if (in != null)
- in.close();
- }
- catch (IOException e) {
- log.error("关闭node.properties失败", e);
- }
- }
- log.info("节点列表:" + nodeProperties);
- }
node配置文件里面的内容(在本地部署两个tomcat实例)
[html] view plaincopy
- A=http://10.144.35.250:8080/diamond-server/notify.do
- B=http://10.144.35.250:9090/diamond-server1/notify.do
2.2加载数据库信息,创建BasicDataSource,JdbcTemplate对象
com.taobao.diamond.server.service.PersistService
[java] view plaincopy
- @PostConstruct
- public void initDataSource() throws Exception {
- // 读取jdbc.properties配置, 加载数据源
- Properties props = ResourceUtils.getResourceAsProperties("jdbc.properties");
- BasicDataSource ds = new BasicDataSource();
- ds.setDriverClassName(JDBC_DRIVER_NAME);
- ds.setUrl(ensurePropValueNotNull(props.getProperty("db.url")));
- ds.setUsername(ensurePropValueNotNull(props.getProperty("db.user")));
- ds.setPassword(ensurePropValueNotNull(props.getProperty("db.password")));
- ds.setInitialSize(Integer.parseInt(ensurePropValueNotNull(props.getProperty("db.initialSize"))));
- ds.setMaxActive(Integer.parseInt(ensurePropValueNotNull(props.getProperty("db.maxActive"))));
- ds.setMaxIdle(Integer.parseInt(ensurePropValueNotNull(props.getProperty("db.maxIdle"))));
- ds.setMaxWait(Long.parseLong(ensurePropValueNotNull(props.getProperty("db.maxWait"))));
- ds.setPoolPreparedStatements(Boolean.parseBoolean(ensurePropValueNotNull(props
- .getProperty("db.poolPreparedStatements"))));
- this.jt = new JdbcTemplate();
- this.jt.setDataSource(ds);
- // 设置最大记录数,防止内存膨胀
- this.jt.setMaxRows(MAX_ROWS);
- // 设置JDBC执行超时时间
- this.jt.setQueryTimeout(QUERY_TIMEOUT);
- }
2.3 定时任务服务(每600s 从数据库拉取数据到本地磁盘和本地缓存)
com.taobao.diamond.server.service.TimerTaskService
[java] view plaincopy
- @PostConstruct
- public void init() {
- this.scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(new ThreadFactory() {
- public Thread newThread(Runnable r) {
- Thread t = new Thread(r);
- t.setName(THREAD_NAME);
- t.setDaemon(true);
- return t;
- }
- });
- DumpConfigInfoTask dumpTask = new DumpConfigInfoTask(this);
- dumpTask.run();
- this.scheduledExecutorService.scheduleWithFixedDelay(dumpTask, SystemConfig.getDumpConfigInterval(),
- SystemConfig.getDumpConfigInterval(), TimeUnit.SECONDS);
- }
3.以添加一条数据走一遍diamond-server的流程
3.1 添加数据的页面
3.2提交数据进入controller
com.taobao.diamond.server.controller.AdminController
[java] view plaincopy
- @RequestMapping(params = "method=postConfig", method = RequestMethod.POST)
- public String postConfig(HttpServletRequest request, HttpServletResponse response,
- @RequestParam("dataId") String dataId, @RequestParam("group") String group,
- @RequestParam("content") String content, ModelMap modelMap) {
- response.setCharacterEncoding("GBK");
- boolean checkSuccess = true;
- String errorMessage = "参数错误";
- if (StringUtils.isBlank(dataId) || DiamondUtils.hasInvalidChar(dataId.trim())) {
- checkSuccess = false;
- errorMessage = "无效的DataId";
- }
- if (StringUtils.isBlank(group) || DiamondUtils.hasInvalidChar(group.trim())) {
- checkSuccess = false;
- errorMessage = "无效的分组";
- }
- if (StringUtils.isBlank(content)) {
- checkSuccess = false;
- errorMessage = "无效的内容";
- }
- if (!checkSuccess) {
- modelMap.addAttribute("message", errorMessage);
- return "/admin/config/new";
- }
- dataId = dataId.trim();
- group = group.trim();
- <span style="color:#FF0000;">this.configService.addConfigInfo(dataId, group, content);</span>
- modelMap.addAttribute("message", "提交成功!");
- return listConfig(request, response, dataId, group, 1, 20, modelMap);
- }
3.3进入添加数据的service层
com.taobao.diamond.server.service.ConfigService
[java] view plaincopy
- public void addConfigInfo(String dataId, String group, String content) {
- checkParameter(dataId, group, content);
- ConfigInfo configInfo = new ConfigInfo(dataId, group, content);
- // 保存顺序:先数据库,再磁盘
- try {
- persistService.addConfigInfo(configInfo);
- // 切记更新缓存
- this.contentMD5Cache.put(generateMD5CacheKey(dataId, group), configInfo.getMd5());
- diskService.saveToDisk(configInfo);
- // 通知其他节点
- this.notifyOtherNodes(dataId, group);
- }
- catch (Exception e) {
- log.error("保存ConfigInfo失败", e);
- throw new ConfigServiceException(e);
- }
- }
到此为止,已经把数据添加到数据里,并且其他diamond-server实例也已经更新到最新的数据。
4.我们现在看看diamond是如何通知到其他的diamond实例的,如果通知不到其他diamond实例的话,该如何同步
4.1 通知其他的diamond实例
我们是通过node配置文件进行配置的
现在我们看一下代码
com.taobao.diamond.server.service.NotifyService
[java] view plaincopy
- public void notifyConfigInfoChange(String dataId, String group) {
- Enumeration<?> enu = nodeProperties.propertyNames();
- while (enu.hasMoreElements()) {
- String address = (String) enu.nextElement();
- if (address.contains(SystemConfig.LOCAL_IP)) {
- continue;
- }
- String urlString = generateNotifyConfigInfoPath(dataId, group, address);
- final String result = invokeURL(urlString);
- log.info("通知节点" + address + "分组信息改变:" + result);
- }
- }
- String generateNotifyConfigInfoPath(String dataId, String group, String address) {
- String specialUrl = this.nodeProperties.getProperty(address);
- String urlString = PROTOCOL + address + URL_PREFIX;
- // 如果有指定url,使用指定的url
- if (specialUrl != null && StringUtils.hasLength(specialUrl.trim())) {
- urlString = specialUrl;
- }
- urlString += "?method=notifyConfigInfo&dataId=" + dataId + "&group=" + group;
- return urlString;
- }
- /**
- * http get调用
- *
- * @param urlString
- * @return
- */
- private String invokeURL(String urlString) {
- HttpURLConnection conn = null;
- URL url = null;
- try {
- url = new URL(urlString);
- conn = (HttpURLConnection) url.openConnection();
- conn.setConnectTimeout(TIMEOUT);
- conn.setReadTimeout(TIMEOUT);
- conn.setRequestMethod("GET");
- conn.connect();
- InputStream urlStream = conn.getInputStream();
- StringBuilder sb = new StringBuilder();
- BufferedReader reader = null;
- try {
- reader = new BufferedReader(new InputStreamReader(urlStream));
- String line = null;
- while ((line = reader.readLine()) != null) {
- sb.append(line);
- }
- }
- finally {
- if (reader != null)
- reader.close();
- }
- return sb.toString();
- }
- catch (Exception e) {
- e.printStackTrace();
- log.error("http调用失败,url=" + urlString, e);
- }
- finally {
- if (conn != null) {
- conn.disconnect();
- }
- }
- return "error";
- }
4.2 如果通过http请求并没有通知到其他实例,那该如何同步数据。
diamond本身有个定时任务进行查询数据库
现在我们看一下代码
com.taobao.diamond.server.service.TimerTaskService
[java] view plaincopy
- @PostConstruct
- public void init() {
- this.scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(new ThreadFactory() {
- public Thread newThread(Runnable r) {
- Thread t = new Thread(r);
- t.setName(THREAD_NAME);
- t.setDaemon(true);
- return t;
- }
- });
- DumpConfigInfoTask dumpTask = new DumpConfigInfoTask(this);
- dumpTask.run();
- this.scheduledExecutorService.scheduleWithFixedDelay(dumpTask, SystemConfig.getDumpConfigInterval(),
- SystemConfig.getDumpConfigInterval(), TimeUnit.SECONDS);
- }
到这diamond-server基本的业务就差不多了,对于更改数据和删除数据这些跟添加数据也是一样业务,必须得同步数据。
存储到磁盘的业务是一个组一个文件夹,组文件夹相应下面是存储的不同的dataId,一个dataId是一个文件。
希望关于diamond-server的内容 对大家有所帮助。