├── Zebra.jpg ├── zebra-design.png ├── zebra4js ├── src │ ├── common │ │ ├── config │ │ │ ├── locale │ │ │ │ └── en.js │ │ │ ├── env │ │ │ │ ├── development.js │ │ │ │ ├── testing.js │ │ │ │ └── production.js │ │ │ ├── config.js │ │ │ ├── hook.js │ │ │ ├── error.js │ │ │ ├── zk.js │ │ │ ├── view.js │ │ │ ├── db.js │ │ │ └── session.js │ │ ├── bootstrap │ │ │ ├── middleware.js │ │ │ └── global.js │ │ └── controller │ │ │ └── error.js │ └── home │ │ ├── model │ │ └── index.js │ │ ├── controller │ │ ├── base.js │ │ └── index.js │ │ ├── config │ │ └── config.js │ │ └── logic │ │ └── index.js ├── .thinkjsrc ├── pm2.json ├── www │ ├── production.js │ ├── testing.js │ ├── development.js │ └── README.md ├── .gitignore ├── README.md ├── package.json ├── view │ ├── home │ │ └── index_index.html │ └── common │ │ ├── error_404.html │ │ └── error_400.html └── nginx.conf ├── .gitattributes ├── zebra4j ├── zebra-boot │ ├── src │ │ ├── test │ │ │ └── java │ │ │ │ ├── suanfa │ │ │ │ ├── SortList.java │ │ │ │ ├── BinaryTreePrint.java │ │ │ │ └── PrintList.java │ │ │ │ ├── designs │ │ │ │ └── Singleton.java │ │ │ │ ├── connection │ │ │ │ ├── Counter.java │ │ │ │ └── CopyOnwriteTest.java │ │ │ │ ├── com58 │ │ │ │ └── zhl │ │ │ │ │ ├── util │ │ │ │ │ ├── Convert.java │ │ │ │ │ ├── DatabaseConnection.java │ │ │ │ │ └── Operator.java │ │ │ │ │ └── concurrent │ │ │ │ │ ├── Cpt2_CollectionsUtil.java │ │ │ │ │ ├── Cptt13_DBNonblock.java │ │ │ │ │ ├── Cpt7_Executor.java │ │ │ │ │ ├── Cpt3_ConcurrentUtilClass.java │ │ │ │ │ ├── Cpt4_Queue.java │ │ │ │ │ ├── Cpt9_LockInterface.java │ │ │ │ │ ├── Cptt14_MyCountDownLatch.java │ │ │ │ │ ├── Cpt6_CyclicBarrierAndExchanger.java │ │ │ │ │ ├── Cptt12_LogWriter.java │ │ │ │ │ ├── Cptt10_CustomBlocking.java │ │ │ │ │ ├── Cpt1_StringLockManager.java │ │ │ │ │ ├── Cptt11_Nonblocking.java │ │ │ │ │ ├── Cpt5_LoadTest.java │ │ │ │ │ └── Cpt8_TimeoutManager.java │ │ │ │ └── datatype │ │ │ │ └── StackList.java │ │ └── main │ │ │ ├── resources │ │ │ ├── application.properties │ │ │ └── banner.txt │ │ │ └── java │ │ │ └── com │ │ │ └── zebra │ │ │ └── boot │ │ │ ├── registry │ │ │ ├── IRegistry.java │ │ │ ├── RegistryConfig.java │ │ │ └── impl │ │ │ │ └── ZebraRegistry.java │ │ │ ├── App.java │ │ │ ├── api │ │ │ └── bean │ │ │ │ └── ApiResponse.java │ │ │ └── listener │ │ │ └── ZebraListener.java │ └── pom.xml ├── projectdemo │ └── pom.xml ├── zebra-core │ ├── src │ │ └── main │ │ │ └── java │ │ │ └── com │ │ │ └── zebra │ │ │ └── core │ │ │ ├── helper │ │ │ └── ConfigHelper.java │ │ │ ├── ConfigConstant.java │ │ │ └── util │ │ │ ├── ReflectUtil.java │ │ │ ├── PropsUtil.java │ │ │ ├── CastUtil.java │ │ │ └── ClassUtil.java │ └── pom.xml ├── zebra-doc │ └── zebra-boot │ │ └── Zebra-微服务.md └── zebra-zookeeper │ └── zoo.cfg ├── LICENSE ├── .gitignore ├── Zebra-index.html ├── README.md └── maven-repo-settings-ali.xml /Zebra.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ae6623/Zebra/HEAD/Zebra.jpg -------------------------------------------------------------------------------- /zebra-design.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ae6623/Zebra/HEAD/zebra-design.png -------------------------------------------------------------------------------- /zebra4js/src/common/config/locale/en.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | export default { 4 | 5 | }; -------------------------------------------------------------------------------- /zebra4js/src/common/config/env/development.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | export default { 4 | 5 | }; -------------------------------------------------------------------------------- /zebra4js/src/common/config/env/testing.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | export default { 4 | 5 | }; -------------------------------------------------------------------------------- /zebra4js/.thinkjsrc: -------------------------------------------------------------------------------- 1 | { 2 | "createAt": "2016-11-25 00:22:46", 3 | "mode": "module", 4 | "es": true 5 | } -------------------------------------------------------------------------------- /zebra4js/src/common/config/env/production.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | export default { 4 | resource_on: false 5 | }; -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.js linguist-language=java 2 | *.css linguist-language=java 3 | *.html linguist-language=java 4 | -------------------------------------------------------------------------------- /zebra4js/src/common/config/config.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /** 3 | * config 4 | */ 5 | export default { 6 | //key: value 7 | }; -------------------------------------------------------------------------------- /zebra4js/src/home/model/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /** 3 | * model 4 | */ 5 | export default class extends think.model.base { 6 | 7 | } -------------------------------------------------------------------------------- /zebra4js/src/home/controller/base.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | export default class extends think.controller.base { 4 | /** 5 | * some base method in here 6 | */ 7 | } -------------------------------------------------------------------------------- /zebra4js/src/common/config/hook.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * hook config 5 | * https://thinkjs.org/doc/middleware.html#toc-df6 6 | */ 7 | export default { 8 | 9 | } -------------------------------------------------------------------------------- /zebra4j/zebra-boot/src/test/java/suanfa/SortList.java: -------------------------------------------------------------------------------- 1 | package suanfa; 2 | 3 | /** 4 | * Created by lzy@js-dev.cn on 2017/1/15 0015. 5 | */ 6 | public class SortList { 7 | 8 | } 9 | -------------------------------------------------------------------------------- /zebra4js/src/common/config/error.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /** 3 | * err config 4 | */ 5 | export default { 6 | //key: value 7 | key: "errno", //error number 8 | msg: "errmsg" //error message 9 | }; -------------------------------------------------------------------------------- /zebra4js/src/home/config/config.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /** 3 | * config 4 | */ 5 | export default { 6 | //key: value 7 | HOST_PORT: 1234, 8 | ZK_SERVER: '127.0.0.1:2181,127.0.0.1:2182,127.0.0.1:2183', 9 | REGISTRY_ROOT: '/registry' 10 | }; -------------------------------------------------------------------------------- /zebra4js/src/common/config/zk.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /** 3 | * config zk 4 | */ 5 | export default { 6 | //key: value 7 | HOST_PORT: 1234, 8 | ZK_SERVER: '127.0.0.1:2181,127.0.0.1:2182,127.0.0.1:2183', 9 | REGISTRY_ROOT: '/registry' 10 | }; -------------------------------------------------------------------------------- /zebra4js/src/home/logic/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /** 3 | * logic 4 | * @param {} [] 5 | * @return {} [] 6 | */ 7 | export default class extends think.logic.base { 8 | /** 9 | * index action logic 10 | * @return {} [] 11 | */ 12 | indexAction(){ 13 | 14 | } 15 | } -------------------------------------------------------------------------------- /zebra4js/src/common/bootstrap/middleware.js: -------------------------------------------------------------------------------- 1 | /** 2 | * this file will be loaded before server started 3 | * you can register middleware 4 | * https://thinkjs.org/doc/middleware.html 5 | */ 6 | 7 | /** 8 | * 9 | * think.middleware('xxx', http => { 10 | * 11 | * }) 12 | * 13 | */ 14 | -------------------------------------------------------------------------------- /zebra4js/src/common/config/view.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /** 3 | * template config 4 | */ 5 | export default { 6 | type: 'ejs', 7 | content_type: 'text/html', 8 | file_ext: '.html', 9 | file_depr: '_', 10 | root_path: think.ROOT_PATH + '/view', 11 | adapter: { 12 | ejs: {} 13 | } 14 | }; -------------------------------------------------------------------------------- /zebra4j/zebra-boot/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | #dev 2 | spring.profiles.active=dev 3 | 4 | #address 5 | server.address=127.0.0.1 6 | 7 | #port 8 | server.port=8888 9 | 10 | #log 11 | logging.level.org.springframework.web=INFO 12 | 13 | #zookeeper services 14 | registry.servers=localhost:2181 15 | -------------------------------------------------------------------------------- /zebra4js/src/common/bootstrap/global.js: -------------------------------------------------------------------------------- 1 | /** 2 | * this file will be loaded before server started 3 | * you can define global functions used in controllers, models, templates 4 | */ 5 | 6 | /** 7 | * use global.xxx to define global functions 8 | * 9 | * global.fn1 = function(){ 10 | * 11 | * } 12 | */ -------------------------------------------------------------------------------- /zebra4js/src/home/controller/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import Base from './base.js'; 4 | 5 | export default class extends Base { 6 | /** 7 | * index action 8 | * @return {Promise} [] 9 | */ 10 | indexAction(){ 11 | //auto render template file index_index.html 12 | return this.display(); 13 | } 14 | } -------------------------------------------------------------------------------- /zebra4js/pm2.json: -------------------------------------------------------------------------------- 1 | { 2 | "apps": [{ 3 | "name": "zebra4js", 4 | "script": "www/production.js", 5 | "cwd": "/Users/ae6623/IdeaProjects/thinkjs/zebra4js", 6 | "exec_mode": "cluster", 7 | "instances": 0, 8 | "max_memory_restart": "1G", 9 | "autorestart": true, 10 | "node_args": [], 11 | "args": [], 12 | "env": { 13 | 14 | } 15 | }] 16 | } -------------------------------------------------------------------------------- /zebra4js/www/production.js: -------------------------------------------------------------------------------- 1 | var thinkjs = require('thinkjs'); 2 | var path = require('path'); 3 | 4 | var rootPath = path.dirname(__dirname); 5 | 6 | var instance = new thinkjs({ 7 | APP_PATH: rootPath + path.sep + 'app', 8 | RUNTIME_PATH: rootPath + path.sep + 'runtime', 9 | ROOT_PATH: rootPath, 10 | RESOURCE_PATH: __dirname, 11 | env: 'production' 12 | }); 13 | 14 | instance.run(true); 15 | -------------------------------------------------------------------------------- /zebra4js/src/common/config/db.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /** 3 | * db config 4 | * @type {Object} 5 | */ 6 | export default { 7 | type: 'mysql', 8 | adapter: { 9 | mysql: { 10 | host: '127.0.0.1', 11 | port: '', 12 | database: '', 13 | user: '', 14 | password: '', 15 | prefix: '', 16 | encoding: 'utf8' 17 | }, 18 | mongo: { 19 | 20 | } 21 | } 22 | }; -------------------------------------------------------------------------------- /zebra4js/src/common/config/session.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * session configs 5 | */ 6 | export default { 7 | name: 'thinkjs', 8 | type: 'file', 9 | secret: '7Y&HQ6(K', 10 | timeout: 24 * 3600, 11 | cookie: { // cookie options 12 | length: 32, 13 | httponly: true 14 | }, 15 | adapter: { 16 | file: { 17 | path: think.RUNTIME_PATH + '/session', 18 | } 19 | } 20 | }; -------------------------------------------------------------------------------- /zebra4js/www/testing.js: -------------------------------------------------------------------------------- 1 | var thinkjs = require('thinkjs'); 2 | var path = require('path'); 3 | 4 | var rootPath = path.dirname(__dirname); 5 | 6 | var instance = new thinkjs({ 7 | APP_PATH: rootPath + path.sep + 'app', 8 | RUNTIME_PATH: rootPath + path.sep + 'runtime', 9 | ROOT_PATH: rootPath, 10 | RESOURCE_PATH: __dirname, 11 | env: 'testing' 12 | }); 13 | //自动编译 14 | instance.compile(); 15 | instance.run(); -------------------------------------------------------------------------------- /zebra4j/zebra-boot/src/test/java/designs/Singleton.java: -------------------------------------------------------------------------------- 1 | package designs; 2 | 3 | /** 4 | * Created by lzy@js-dev.cn on 2017/1/15 0015. 5 | */ 6 | public class Singleton { 7 | private static class SingletonInstace { 8 | public static Singleton instance = new Singleton(); 9 | } 10 | 11 | private Singleton(){ 12 | 13 | } 14 | 15 | public Singleton getInstance() { 16 | return SingletonInstace.instance; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /zebra4j/projectdemo/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.liu 8 | com.liu 9 | 1.0-SNAPSHOT 10 | 11 | 12 | -------------------------------------------------------------------------------- /zebra4j/zebra-core/src/main/java/com/zebra/core/helper/ConfigHelper.java: -------------------------------------------------------------------------------- 1 | package com.zebra.core.helper; 2 | 3 | import com.zebra.core.ConfigConstant; 4 | import com.zebra.core.util.PropsUtil; 5 | 6 | import java.util.Properties; 7 | 8 | /** 9 | * 属性读取工具类,用于工程加载时读取约定的配置文件 10 | * Created by lzy@js-dev.cn on 2016/10/26. 11 | */ 12 | public class ConfigHelper { 13 | /** 14 | * 配置文件 app.properties 15 | */ 16 | private static final Properties CONFIG_PROS = PropsUtil.loadProps(ConfigConstant.CONFIG_FILE); 17 | } 18 | -------------------------------------------------------------------------------- /zebra4js/www/development.js: -------------------------------------------------------------------------------- 1 | var thinkjs = require('thinkjs'); 2 | var path = require('path'); 3 | 4 | var rootPath = path.dirname(__dirname); 5 | 6 | var instance = new thinkjs({ 7 | APP_PATH: rootPath + path.sep + 'app', 8 | RUNTIME_PATH: rootPath + path.sep + 'runtime', 9 | ROOT_PATH: rootPath, 10 | RESOURCE_PATH: __dirname, 11 | env: 'development' 12 | }); 13 | 14 | // Build code from src to app directory. 15 | instance.compile({ 16 | log: true 17 | }); 18 | 19 | instance.run(); 20 | var zks = think.config('zk'); 21 | console.log(zks); 22 | -------------------------------------------------------------------------------- /zebra4j/zebra-boot/src/main/java/com/zebra/boot/registry/IRegistry.java: -------------------------------------------------------------------------------- 1 | package com.zebra.boot.registry; 2 | 3 | /** 4 | * Created by ae6623 on 2016/11/22. 5 | * ervice 注册中心接口 6 | * 负责响应网关的服务注册,只要实现此接口,就可以担任整个框架的服务中心的角色 7 | * 可以参考实现类实现自己的注册中心 8 | */ 9 | public interface IRegistry { 10 | 11 | /** 12 | * 服务注册信息 13 | * 14 | * @param serviceName 服务名称 比如 zebra/service 15 | * @param address 服务真实地址 比如 ip:port 16 | */ 17 | void register(String serviceName, String address); 18 | 19 | /** 20 | * 服务卸载 21 | * @param serviceName 22 | * @param address 23 | */ 24 | void unRegister(String serviceName, String address); 25 | } 26 | -------------------------------------------------------------------------------- /zebra4js/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | 5 | # Runtime data 6 | pids 7 | *.pid 8 | *.seed 9 | 10 | # Directory for instrumented libs generated by jscoverage/JSCover 11 | lib-cov 12 | 13 | # Coverage directory used by tools like istanbul 14 | coverage/ 15 | 16 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 17 | .grunt 18 | 19 | # node-waf configuration 20 | .lock-wscript 21 | 22 | # Dependency directory 23 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git 24 | node_modules/ 25 | 26 | # IDE config 27 | .idea 28 | 29 | # output 30 | output/ 31 | output.tar.gz 32 | 33 | app/ 34 | 35 | runtime/ -------------------------------------------------------------------------------- /zebra4j/zebra-boot/src/main/java/com/zebra/boot/App.java: -------------------------------------------------------------------------------- 1 | package com.zebra.boot; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.web.bind.annotation.RequestMapping; 6 | import org.springframework.web.bind.annotation.RestController; 7 | 8 | /** 9 | * Created by lzy@js-dev.cn on 2016/11/15 0015. 10 | */ 11 | @RestController 12 | @SpringBootApplication 13 | public class App { 14 | 15 | @RequestMapping("/") 16 | String boot(){ 17 | return " Zebra is booting ...... "; 18 | } 19 | 20 | public static void main(String[] args) { 21 | SpringApplication.run(App.class, args); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /zebra4j/zebra-boot/src/test/java/connection/Counter.java: -------------------------------------------------------------------------------- 1 | package connection; 2 | 3 | /** 4 | * Created by lzy@js-dev.cn on 2017/1/15 0015. 5 | */ 6 | public class Counter { 7 | public volatile static int count = 0; 8 | 9 | public static void inc() { 10 | 11 | //这里延迟1毫秒,使得结果明显 12 | try { 13 | Thread.sleep(1); 14 | } catch (InterruptedException e) { 15 | } 16 | 17 | count++; 18 | } 19 | 20 | public static void main(String[] args) { 21 | 22 | //同时启动1000个线程,去进行i++计算,看看实际结果 23 | for (int i = 0; i < 1000; i++) { 24 | new Thread(new Runnable() { 25 | // @Override 26 | public void run() { 27 | Counter.inc(); 28 | } 29 | }).start(); 30 | } 31 | 32 | //这里每次运行的值都有可能不同,可能为1000 33 | System.out.println("运行结果:Counter.count=" + Counter.count); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /zebra4js/www/README.md: -------------------------------------------------------------------------------- 1 | ## application 2 | 3 | ### start server 4 | 5 | *development* 6 | 7 | ```js 8 | node www/development.js 9 | ``` 10 | 11 | *testing* 12 | 13 | ```js 14 | node www/testing.js 15 | ``` 16 | 17 | *production* 18 | 19 | ```js 20 | node www/production.js 21 | ``` 22 | 23 | or use pm2 to manage node: 24 | 25 | ``` 26 | pm2 start www/production.js 27 | ``` 28 | 29 | ### compile es6 code 30 | 31 | ``` 32 | npm run compile 33 | ``` 34 | 35 | ### how to link resource 36 | 37 | *in template file* 38 | 39 | ```html 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | ``` 48 | 49 | *link image in css* 50 | 51 | ```css 52 | .a{ 53 | background: url(../img/a.png) no-repeat; 54 | } 55 | ``` 56 | -------------------------------------------------------------------------------- /zebra4j/zebra-boot/src/test/java/com58/zhl/util/Convert.java: -------------------------------------------------------------------------------- 1 | package com58.zhl.util; 2 | 3 | public class Convert { 4 | 5 | public static String toHexString(byte b){ 6 | StringBuilder sb=new StringBuilder(); 7 | int n=b<<24>>>24; //因为位运算时都会转换为int型,因此需按照int型的去除符号位的方式来判断 8 | if(n<16){ 9 | sb.append("0"); 10 | sb.append(getHexChar((byte)(n%16))); 11 | }else{ 12 | sb.append(getHexChar((byte)(n/16))).append(getHexChar((byte)(n%16))); 13 | } 14 | return sb.toString(); 15 | } 16 | 17 | private static char getHexChar(byte b){ 18 | switch(b){ 19 | case 10:return 'A'; 20 | case 11:return 'B'; 21 | case 12:return 'C'; 22 | case 13:return 'D'; 23 | case 14:return 'E'; 24 | case 15:return 'F'; 25 | default:return ((char)(b%10+48)); 26 | } 27 | } 28 | 29 | public static void main(String args[]){ 30 | byte b=-66; 31 | int n=b<<24>>>24; 32 | System.out.println(Integer.toBinaryString(n)+"==="+n+"==="+(byte)b); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /zebra4j/zebra-core/src/main/java/com/zebra/core/ConfigConstant.java: -------------------------------------------------------------------------------- 1 | package com.zebra.core; 2 | 3 | /** 4 | * Created by lzy@js-dev.cn on 2016/11/2 0002. 5 | */ 6 | public class ConfigConstant { 7 | private static final String SMART_PREFIX = "zebra.core"; 8 | 9 | /** 10 | * 默认配置文件名称 11 | */ 12 | public static final String CONFIG_FILE = "app.properties"; 13 | 14 | /** 15 | * JDBC 16 | */ 17 | public static final String JDBC_DRIVER = SMART_PREFIX + ".jdbc.driver"; 18 | public static final String JDBC_USERNAME = SMART_PREFIX + ".jdbc.username"; 19 | public static final String JDBC_PASSWORD = SMART_PREFIX + ".jdbc.password"; 20 | 21 | public static final String APP_ABASE_PACKAGE = SMART_PREFIX + ".app.base_package"; 22 | public static final String APP_PATH_JSP = SMART_PREFIX + ".app.path_jsp"; 23 | public static final String APP_PATH_ASSET= SMART_PREFIX + ".app.path_asset"; 24 | public static final String APP_UPLOAD_LIMIT = SMART_PREFIX + ".app.upload_limit"; 25 | } 26 | -------------------------------------------------------------------------------- /zebra4j/zebra-boot/src/test/java/com58/zhl/util/DatabaseConnection.java: -------------------------------------------------------------------------------- 1 | package com58.zhl.util; 2 | 3 | import java.sql.Connection; 4 | import java.sql.DriverManager; 5 | import java.sql.SQLException; 6 | 7 | public class DatabaseConnection { 8 | 9 | private static final String DRIVER="oracle.jdbc.driver.OracleDriver"; 10 | 11 | private static final String URL="jdbc:oracle:thin:@localhost:1521:orcl"; 12 | 13 | private static final String pwd="scott"; 14 | 15 | private static final String name="scott"; 16 | 17 | public static Connection getConnection(){ 18 | try { 19 | Class.forName(DRIVER); 20 | Connection conn=DriverManager.getConnection(URL, name, pwd); 21 | return conn; 22 | } catch (ClassNotFoundException e) { 23 | e.printStackTrace(); 24 | } catch (SQLException e) { 25 | e.printStackTrace(); 26 | } 27 | return null; 28 | } 29 | 30 | public static void closeConnection(Connection conn){ 31 | try { 32 | conn.close(); 33 | } catch (SQLException e) { 34 | e.printStackTrace(); 35 | } 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /zebra4j/zebra-boot/src/main/java/com/zebra/boot/registry/RegistryConfig.java: -------------------------------------------------------------------------------- 1 | package com.zebra.boot.registry; 2 | 3 | import com.zebra.boot.registry.impl.ZebraRegistry; 4 | import org.springframework.boot.context.properties.ConfigurationProperties; 5 | import org.springframework.context.annotation.Bean; 6 | import org.springframework.context.annotation.Configuration; 7 | 8 | 9 | /** 10 | * Created by ae6623 on 2016/11/23. 11 | * 通过该类配置注册中心,prefix注解是为了读取application.properties中的配置的前缀变量,比如registry.servers 12 | */ 13 | @Configuration 14 | @ConfigurationProperties(prefix = "registry") 15 | public class RegistryConfig { 16 | 17 | /** 18 | * 会被Spring boot 自动塞入进来 19 | */ 20 | private String servers; 21 | 22 | /** 23 | * 返回注册中心实例 24 | * @return 25 | */ 26 | @Bean 27 | public IRegistry serviceRegistry() { 28 | return new ZebraRegistry(servers); 29 | } 30 | 31 | /** 32 | * 供Spring boot 自动注入 33 | * @param servers 34 | * @return 35 | */ 36 | public void setServers(String servers) { 37 | this.servers = servers; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /zebra4j/zebra-boot/src/test/java/datatype/StackList.java: -------------------------------------------------------------------------------- 1 | package datatype; 2 | 3 | import java.util.Stack; 4 | 5 | /** 6 | * Created by lzy@js-dev.cn on 2017/1/15 0015. 7 | */ 8 | public class StackList { 9 | 10 | private Stack stack1 = new Stack(); 11 | private Stack stack2 = new Stack(); 12 | 13 | /** 14 | * 添加元素到队尾 15 | * @param t 16 | */ 17 | public void appendTail(T t) { 18 | stack1.push(t); 19 | } 20 | 21 | public void printList(){ 22 | System.out.println("当前栈:" + stack1); 23 | } 24 | 25 | public T deleteHead() throws Exception{ 26 | if (stack2.isEmpty()) { 27 | while (!stack1.isEmpty()) { 28 | stack2.push(stack1.pop()); 29 | } 30 | if(stack2.isEmpty()){ 31 | System.out.println("队列为空,不可删除"); 32 | } 33 | } 34 | //stack2存放了所有的stack的倒序,弹出的第一个就是队列头,也就是栈尾 35 | return stack2.pop(); 36 | } 37 | 38 | public static void main(String[] args) throws Exception { 39 | StackList slist = new StackList<>(); 40 | slist.appendTail("1"); 41 | slist.appendTail("2"); 42 | slist.appendTail("3"); 43 | slist.deleteHead(); 44 | System.out.println(slist); 45 | } 46 | 47 | 48 | } 49 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013-2016 lzy [http://js-dev.cn](http://js-dev.cn) (ae6623@gmail.com) and contributors 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. -------------------------------------------------------------------------------- /zebra4j/zebra-boot/src/test/java/suanfa/BinaryTreePrint.java: -------------------------------------------------------------------------------- 1 | package suanfa; 2 | 3 | import java.util.Arrays; 4 | 5 | /** 6 | * Created by lzy@js-dev.cn on 2017/1/14 0014. 7 | */ 8 | public class BinaryTreePrint { 9 | 10 | public static Node buildTree(int[] pre, int[] middle) { 11 | 12 | if (pre != null && middle != null) { 13 | if( pre.length != middle.length) { 14 | System.out.println("参数非法"); 15 | } 16 | 17 | Node root = new Node(); 18 | for (int i = 0; i < middle.length; i++) { 19 | if (middle[i] == pre[0]) { 20 | root.data = middle[i]; 21 | root.left = buildTree( Arrays.copyOfRange(pre, i, i+1), Arrays.copyOfRange(middle, 0, i)); 22 | root.right = buildTree( Arrays.copyOfRange(pre, i+1, pre.length), Arrays.copyOfRange( middle, i+1, middle.length) ); 23 | } 24 | } 25 | 26 | return root; 27 | 28 | } 29 | return null; 30 | } 31 | 32 | 33 | public static void main(String[] args) { 34 | int[] pre = {1, 2, 4, 7, 3, 5, 6, 8}; 35 | int[] middle = {4, 7, 2, 1, 5, 3, 8, 6}; 36 | Node root = buildTree(pre, middle); 37 | } 38 | 39 | 40 | } 41 | 42 | class Node { 43 | T data; 44 | Node left; 45 | Node right; 46 | } -------------------------------------------------------------------------------- /zebra4j/zebra-doc/zebra-boot/Zebra-微服务.md: -------------------------------------------------------------------------------- 1 | ###1.什么是微服务 2 | 3 | 微服务是一种分布式的架构,它所有的组件(也就是服务)会被部署为单独的应用程序,并通过某种远程访问协议(`Rpc/Restful`)进行通讯。分布式应用的挑战之一就是如何管理远程服务的`可用性`和它们的`响应`。服务可用性是`服务消费者`连接服务并能够发送请求的能力,`服务响应`则关注服务的响应时间。 4 | 5 | ###2.微服务的局限 6 | 7 | 并不是所有的业务系统都适用于微服务,不能说现在流行这个,我就把公司上上下下几千个系统全部放入`Docker`,全部都架上微服务的袈裟,你应该静下心来,仔细分析你的商业需求、商业驱动、组织架构和团队技术环境,因为`微服务`并不适应所有的场景。而且基于`RESTful`的协议请求,很容易被多次重复调用,此时应考虑加入消息机制,利用消息进行事务的处理以及异步服务的调用,在此需要提醒各位在`数据一致性`和`高可用`方面做好取舍,准备好一致性的补偿机制。 8 | 9 | ###3.微服务的好处 10 | 11 | 打了这么多预防针,你还是跟到了这里,那么我们来谈谈微服务的好处, 12 | 13 | - 应用太大,我们上线一个小功能,并不想再所有程序都打包上线,这很烦,我们需要拆开,拆成单个的服务出来。每个服务都有一个`Rpc`或者`RESTful`的Api进行业务驱动,由类似于`Spring cloud`或者`Zookeeper`的服务管理者去发现和监听各个服务节点的状态。 14 | - 拆出来的微服务,就可以交给不同的团队进行开发,维护更加简单,不会因为一个模块上线失败,而整体回滚。 15 | - 部署方便,`Jekens + Docker`直接部署,对于前端而言,根本不知道后台什么时候突然部署了1w台服务,用户几乎0察觉,轻松应对秒杀等业务,流量下来之后,随时Stop服务。 16 | 17 | ###4.微服务的实现 18 | - 1.网关 19 | - 采用API的方式,制造一个所有的端都支持的网关,作为唯一的入口,可以提供授权、监控、负载、缓存、静态、返回相应等入口,建议使用`RESTful`的`http`接口。 20 | - 网关的作用 21 | - 提供统一服务入口,让微服务对前台透明 22 | - 聚合后台的服务,节省流量,提升性能 23 | - 提供安全,过滤,流控等API管理功能 24 | - 网关要考虑交互的方式 25 | - 客户端 1:1 服务端 26 | - 客户端 1:N 服务端 27 | - 2.服务发现 28 | - 3.服务调用 29 | - 同步调用 30 | - Rpc 31 | - Rest 32 | - 异步调用 33 | - MQ 34 | - 4.服务可用 35 | - 重试 36 | - 限流 37 | - 熔断 38 | - 负载 39 | - 降级 40 | - 缓存 41 | - 5.服务发布 42 | - Jekins Docker 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /zebra4js/README.md: -------------------------------------------------------------------------------- 1 | ## Introduction 介绍 2 | [![NPM version](https://img.shields.io/npm/v/thinkjs.svg?style=flat-square)](http://badge.fury.io/js/thinkjs) 3 | [![travis-ci](https://img.shields.io/travis/75team/thinkjs.svg?style=flat-square)](https://travis-ci.org/75team/thinkjs) 4 | [![Coverage Status](https://img.shields.io/coveralls/75team/thinkjs.svg?style=flat-square)](https://coveralls.io/github/75team/thinkjs) 5 | 6 | 7 | `Zebra4js`是`落雨`基于 [ThinkJS](http://www.thinkjs.org) 开发的一套Spring-Boot网关层,配合`Zebra4j`微服务框架[https://github.com/ae6623/Zebra](https://github.com/ae6623/Zebra),作为桥梁用来接收各个客户端的访问请求,并调用`Zookeeper`获取服务地址,提供高并发的各端`RESTful`服务调用。 8 | 9 | 本项目使用Es6 JavaScript语法,已经实现自动编译,推荐使用Webstom IDE进行项目调试。 10 | 11 | 线上生产环境,建议使用pm2作为守护进程。 12 | 13 | 使用方法:入口程序暂时放在www/testing.js中 14 | 15 | ## Frameworks and Tools 构建 16 | * JavaScript & IDE: ES6 / Webstorm 16 17 | * Backend: Thinkjs 2.x 18 | * Database: no 19 | * Cache:Redis 20 | * Web Server: Nginx proxy 80端口转发->8360 21 | * Build Tool: Webpack 22 | * Other: 23 | * Port-nginx:http://localhost:80 24 | * Port-node:http://localhost:8360 25 | 26 | --- 27 | ### Install dependencies 安装依赖 28 | 29 | * 30 | ``` 31 | npm install 32 | ``` 33 | 34 | #### Start server 开启服务 35 | 36 | * 37 | ``` 38 | npm start 39 | ``` 40 | 41 | ### Deploy with pm2 部署上线 42 | 43 | 44 | * Use pm2 to deploy app on production enviroment. 45 | 46 | * 47 | ``` 48 | pm2 startOrReload pm2.json 49 | ``` -------------------------------------------------------------------------------- /zebra4j/zebra-boot/src/test/java/com58/zhl/concurrent/Cpt2_CollectionsUtil.java: -------------------------------------------------------------------------------- 1 | package com58.zhl.concurrent; 2 | 3 | import java.util.Collections; 4 | import java.util.HashMap; 5 | import java.util.Map; 6 | 7 | /** 8 | * Collections.unmodifiableMap方法封装出来的不可修改map 9 | * @author 58_zhl 10 | * 11 | */ 12 | public class Cpt2_CollectionsUtil { 13 | 14 | private static String tkey="123"; 15 | /** 16 | * 17 | * @param map 18 | */ 19 | public static void testUnmodifiableMap(Map map){ 20 | UtilBean ub=map.get(tkey); 21 | ub.itg=12; 22 | Map unmodifiableMap=Collections.unmodifiableMap(map); 23 | ub=unmodifiableMap.get(tkey); 24 | try{ 25 | ub.itg=13; //这里不会引发异常,如需要限制,还得对UtilBean做限制,例如私有化变量,但不提供set方法 26 | unmodifiableMap.put(tkey, null); //这里可以引发异常 27 | unmodifiableMap.put("343333", new UtilBean("343333",22)); //也不能这么修改 28 | //注意:千万不要错误的使用这种工具,否则将会很危险 29 | //因为并发导致的异常大多数情况下都很难重现 30 | 31 | }catch(UnsupportedOperationException uoe){ 32 | System.out.println("异常发生,不能进行修改"); 33 | } 34 | } 35 | 36 | public static class UtilBean{ 37 | String str=null; 38 | int itg; 39 | UtilBean(String str,int itg){ 40 | this.str=str; 41 | this.itg=itg; 42 | } 43 | } 44 | 45 | public static void main(String args[]){ 46 | Map maps=new HashMap(); 47 | maps.put(tkey, new UtilBean("123",1)); //随便加了测试数据以后 48 | testUnmodifiableMap(maps); 49 | 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /zebra4js/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "zebra4js", 3 | "version": "1.0.0", 4 | "description": "Zebra4js for Zebra4J/Zebra-boot use Thinkjs", 5 | "scripts": { 6 | "test": "echo \"Error: no test specified\" && exit 1" 7 | }, 8 | "repository": { 9 | "type": "git", 10 | "url": "git+https://github.com/ae6623/Zebra.git" 11 | }, 12 | "keywords": [ 13 | "spring", 14 | "boot", 15 | "zebra" 16 | ], 17 | "author": "js-dev.cn 落雨", 18 | "license": "ISC", 19 | "bugs": { 20 | "url": "https://github.com/ae6623/Zebra/issues" 21 | }, 22 | "homepage": "https://github.com/ae6623/Zebra#readme", 23 | "scripts": { 24 | "start": "node www/development.js", 25 | "compile": "babel --presets es2015-loose,stage-1 --plugins transform-runtime src/ --out-dir app/ --source-maps", 26 | "watch-compile": "node -e \"console.log(' no longer need, use command direct.');console.log();\"", 27 | "watch": "npm run watch-compile" 28 | }, 29 | "dependencies": { 30 | "thinkjs": "2.2.x", 31 | "babel-runtime": "6.x.x", 32 | "source-map-support": "0.4.0" 33 | }, 34 | "devDependencies": { 35 | "http-proxy": "^1.15.2", 36 | "node-zookeeper-client": "^0.2.2", 37 | "babel-cli": "^6.7.7", 38 | "babel-preset-es2015": "^6.6.0", 39 | "babel-preset-es2015-loose": "^7.0.0", 40 | "babel-preset-stage-1": "^6.5.0", 41 | "babel-plugin-transform-runtime": "^6.7.5", 42 | "babel-core": "^6.7.7" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /zebra4j/zebra-boot/src/main/resources/banner.txt: -------------------------------------------------------------------------------- 1 | 2 | bbbbbbbb 3 | ZZZZZZZZZZZZZZZZZZZ b::::::b 4 | Z:::::::::::::::::Z b::::::b 5 | Z:::::::::::::::::Z b::::::b 6 | Z:::ZZZZZZZZ:::::Z b:::::b 7 | ZZZZZ Z:::::Z eeeeeeeeeeee b:::::bbbbbbbbb rrrrr rrrrrrrrr aaaaaaaaaaaaa 8 | Z:::::Z ee::::::::::::ee b::::::::::::::bb r::::rrr:::::::::r a::::::::::::a 9 | Z:::::Z e::::::eeeee:::::eeb::::::::::::::::b r:::::::::::::::::r aaaaaaaaa:::::a 10 | Z:::::Z e::::::e e:::::eb:::::bbbbb:::::::brr::::::rrrrr::::::r a::::a 11 | Z:::::Z e:::::::eeeee::::::eb:::::b b::::::b r:::::r r:::::r aaaaaaa:::::a 12 | Z:::::Z e:::::::::::::::::e b:::::b b:::::b r:::::r rrrrrrraa::::::::::::a 13 | Z:::::Z e::::::eeeeeeeeeee b:::::b b:::::b r:::::r a::::aaaa::::::a 14 | ZZZ:::::Z ZZZZZe:::::::e b:::::b b:::::b r:::::r a::::a a:::::a 15 | Z::::::ZZZZZZZZ:::Ze::::::::e b:::::bbbbbb::::::b r:::::r a::::a a:::::a 16 | Z:::::::::::::::::Z e::::::::eeeeeeee b::::::::::::::::b r:::::r a:::::aaaa::::::a 17 | Z:::::::::::::::::Z ee:::::::::::::e b:::::::::::::::b r:::::r a::::::::::aa:::a 18 | ZZZZZZZZZZZZZZZZZZZ eeeeeeeeeeeeee bbbbbbbbbbbbbbbb rrrrrrr aaaaaaaaaa aaaa 19 | 20 | by 落雨 1.0 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /zebra4j/zebra-zookeeper/zoo.cfg: -------------------------------------------------------------------------------- 1 | # The number of milliseconds of each tick 2 | # 1.最小时间长度,回话最小超时会依赖此参数 timeout = 2 * tickTime 3 | tickTime=2000 4 | 5 | # The number of ticks that the initial 6 | # synchronization phase can take 7 | # 2.Leader节点等待Follower节点并完成数据同步的最长时间单位 initLimit = 10 * tickTime 8 | initLimit=10 9 | 10 | # The number of ticks that can pass between 11 | # sending a request and getting an acknowledgement 12 | # 3.心跳检测延时时间 syncLimit = 5 * tickTime 13 | syncLimit=5 14 | 15 | # the directory where the snapshot is stored. 16 | # do not use /tmp for storage, /tmp here is just 17 | # example sakes. 18 | # 4.zookeeper存储mid的data路径 我这里配置的伪集群 19 | dataDir=/opt/soft/data/zookeeper/zookeeper1 20 | 21 | # the port at which the clients will connect 22 | # 5.向外提供调用接口的端口号,所有的客户端需要连接到这个端口,才可以拿到数据 23 | clientPort=2181 24 | # 6.配置集群 server. = :: port1是集群心跳,port2是选举端口 25 | server.1=127.0.0.1:2888:3881 26 | server.2=127.0.0.1:2882:3882 27 | server.3=127.0.0.1:2883:3883 28 | 29 | 30 | # the maximum number of client connections. 31 | # increase this if you need to handle more clients 32 | #maxClientCnxns=60 33 | # 34 | # Be sure to read the maintenance section of the 35 | # administrator guide before turning on autopurge. 36 | # 37 | # http://zookeeper.apache.org/doc/current/zookeeperAdmin.html#sc_maintenance 38 | # 39 | # The number of snapshots to retain in dataDir 40 | #autopurge.snapRetainCount=3 41 | # Purge task interval in hours 42 | # Set to "0" to disable auto purge feature 43 | #autopurge.purgeInterval=1 44 | 45 | 46 | -------------------------------------------------------------------------------- /zebra4j/zebra-boot/src/test/java/suanfa/PrintList.java: -------------------------------------------------------------------------------- 1 | package suanfa; 2 | 3 | 4 | import org.apache.commons.collections4.CollectionUtils; 5 | 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | import java.util.Stack; 9 | 10 | /** 11 | * Created by lzy@js-dev.cn on 2017/1/13 0013. 12 | */ 13 | public class PrintList { 14 | 15 | public static void printResers(ListNode head) { 16 | Stack stack = new Stack<>(); 17 | while (head != null) { 18 | stack.push(head); 19 | head = head.next; 20 | } 21 | while (!stack.isEmpty()) { 22 | System.out.println(stack.pop().data); 23 | } 24 | } 25 | 26 | public static void print(ListNode head) { 27 | List list = new ArrayList(); 28 | while (head != null) { 29 | list.add(head); 30 | head = head.next; 31 | } 32 | if (CollectionUtils.isNotEmpty(list)){ 33 | System.out.println(list); 34 | } 35 | } 36 | 37 | public static void main(String[] args) { 38 | ListNode node1 = new ListNode<>(); 39 | ListNode node2 = new ListNode<>(); 40 | ListNode node3 = new ListNode<>(); 41 | 42 | node1.data = 1; 43 | node2.data = 2; 44 | node3.data = 3; 45 | 46 | node1.next = node2; 47 | node2.next = node3; 48 | 49 | System.out.println("链表:"); 50 | print(node1); 51 | 52 | System.out.println("翻转链表:"); 53 | printResers(node1); 54 | } 55 | 56 | } 57 | 58 | class ListNode { 59 | T data; 60 | ListNode next; 61 | 62 | @Override 63 | public String toString() { 64 | return String.valueOf(data); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # node 2 | node_modules 3 | 4 | # nyc test coverage 5 | .nyc_output 6 | 7 | # Dependency directories 8 | node_modules 9 | jspm_packages 10 | 11 | # Optional npm cache directory 12 | .npm 13 | 14 | # Optional REPL history 15 | .node_repl_history 16 | 17 | # idea ide 18 | target/ 19 | *.class 20 | *.iml 21 | *.ipr 22 | *.iws 23 | .idea/ 24 | 25 | # Package Files 26 | *.jar 27 | *.war 28 | *.ear 29 | 30 | # virtual machine crash logs 31 | hs_err_pid* 32 | 33 | # Operating System Files 34 | # OSX 35 | .DS_Store 36 | .AppleDouble 37 | .LSOverride 38 | 39 | # Icon must end with two \r 40 | Icon 41 | 42 | # Thumbnails 43 | ._* 44 | 45 | # Files that might appear on external disk 46 | .Spotlight-V100 47 | .Trashes 48 | 49 | # Directories potentially created on remote AFP share 50 | .AppleDB 51 | .AppleDesktop 52 | Network Trash Folder 53 | Temporary Items 54 | .apdisk 55 | 56 | # Windows 57 | Thumbs.db 58 | ehthumbs.db 59 | 60 | # Folder config file 61 | Desktop.ini 62 | 63 | # Recycle Bin used on file shares 64 | $RECYCLE.BIN/ 65 | 66 | # Windows Installer files 67 | *.cab 68 | *.msi 69 | *.msm 70 | *.msp 71 | 72 | # Logs 73 | logs 74 | *.log 75 | npm-debug.log* 76 | 77 | # Runtime data 78 | pids 79 | *.pid 80 | *.seed 81 | 82 | # Directory for instrumented libs generated by jscoverage/JSCover 83 | lib-cov 84 | 85 | # Coverage directory used by tools like istanbul 86 | coverage 87 | 88 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 89 | .grunt 90 | 91 | # node-waf configuration 92 | .lock-wscript 93 | 94 | # Compiled binary addons (http://nodejs.org/api/addons.html) 95 | build/Release 96 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /zebra4j/zebra-boot/src/main/java/com/zebra/boot/api/bean/ApiResponse.java: -------------------------------------------------------------------------------- 1 | package com.zebra.boot.api.bean; 2 | 3 | /** 4 | * 封装Api Restfull 返回Json 5 | * Created by lzy@js-dev.cn on 2016/11/17 0017. 6 | */ 7 | public class ApiResponse { 8 | 9 | /** 10 | * SUCCESS = 1 11 | */ 12 | public static final int SUCCESS = 1; 13 | 14 | /** 15 | * ERROR = 0 16 | */ 17 | public static final int ERROR = 0; 18 | 19 | /** 20 | * 错误编码 21 | */ 22 | private int code; 23 | 24 | /** 25 | * 提示信息 26 | */ 27 | private String msg; 28 | 29 | /** 30 | * 自带数据 31 | */ 32 | private T data; 33 | 34 | /** 35 | * 返回成功信息 36 | * @param data 37 | * @param 38 | * @return 39 | */ 40 | public static ApiResponse sucess(T data){ 41 | ApiResponse resp = new ApiResponse(); 42 | resp.setCode(SUCCESS); 43 | resp.setData(data); 44 | return resp; 45 | } 46 | 47 | /** 48 | * 返回错误信息 49 | * @param errorMsg 50 | * @param 51 | * @return 52 | */ 53 | public static ApiResponse error(String errorMsg){ 54 | return ApiResponse.error(errorMsg, ERROR); 55 | 56 | } 57 | 58 | /** 59 | * 返回含有错误码的响应 60 | * @param errorMsg 61 | * @param code 62 | * @param 63 | * @return 64 | */ 65 | private static ApiResponse error(String errorMsg, int code) { 66 | ApiResponse resp = new ApiResponse(); 67 | resp.setCode(code); 68 | resp.setMsg(errorMsg); 69 | return resp; 70 | } 71 | 72 | public int getCode() { 73 | return code; 74 | } 75 | 76 | public void setCode(int code) { 77 | this.code = code; 78 | } 79 | 80 | public String getMsg() { 81 | return msg; 82 | } 83 | 84 | public void setMsg(String msg) { 85 | this.msg = msg; 86 | } 87 | 88 | public T getData() { 89 | return data; 90 | } 91 | 92 | public void setData(T data) { 93 | this.data = data; 94 | } 95 | 96 | 97 | 98 | } 99 | -------------------------------------------------------------------------------- /zebra4j/zebra-core/src/main/java/com/zebra/core/util/ReflectUtil.java: -------------------------------------------------------------------------------- 1 | package com.zebra.core.util; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | 6 | import java.lang.reflect.Field; 7 | import java.lang.reflect.Method; 8 | 9 | /** 10 | * 反射工具类 11 | * Created by lzy@js-dev.cn on 2016/10/27. 12 | */ 13 | public class ReflectUtil { 14 | private static final Logger LOGGER = LoggerFactory.getLogger(ReflectUtil.class); 15 | 16 | /** 17 | * 根据类名创建实例 18 | * @param className 19 | * @return 20 | */ 21 | public static Object newInstance(String className){ 22 | Class cls = ClassUtil.loadClass(className); 23 | return newInstance(cls); 24 | } 25 | 26 | /** 27 | * 根据类创建实例 28 | * @param cls 29 | * @return 30 | */ 31 | public static Object newInstance(Class cls){ 32 | Object instance = null; 33 | try { 34 | instance = cls.newInstance(); 35 | } catch (Exception e) { 36 | LOGGER.error("new instance failure", e); 37 | e.printStackTrace(); 38 | } 39 | return instance; 40 | } 41 | 42 | /** 43 | * 调用方法 44 | * @param obj 45 | * @param method 46 | * @param args 47 | * @return 48 | */ 49 | public static Object invokeMethod(Object obj, Method method, Object... args){ 50 | Object result = null; 51 | method.setAccessible(true); 52 | try { 53 | result = method.invoke(obj, args); 54 | } catch (Exception e) { 55 | LOGGER.error("method invoke failure", e); 56 | } 57 | return result; 58 | } 59 | 60 | /** 61 | * 设置成员变量的值 62 | * @param obj 63 | * @param field 64 | * @param value 65 | * @return 66 | */ 67 | public static boolean setField(Object obj, Field field, Object value){ 68 | boolean result = false; 69 | field.setAccessible(true); 70 | try{ 71 | field.set(obj, value); 72 | result = true; 73 | }catch (Exception e){ 74 | LOGGER.error("field set failure",e); 75 | result = false; 76 | } 77 | return result; 78 | } 79 | 80 | } 81 | -------------------------------------------------------------------------------- /zebra4j/zebra-boot/src/test/java/com58/zhl/concurrent/Cptt13_DBNonblock.java: -------------------------------------------------------------------------------- 1 | package com58.zhl.concurrent; 2 | 3 | import java.sql.Connection; 4 | import java.sql.PreparedStatement; 5 | import java.sql.SQLException; 6 | import java.util.concurrent.CountDownLatch; 7 | 8 | import com58.zhl.util.DatabaseConnection; 9 | 10 | /** 11 | * 打造基于数据库操作的非阻塞算法 12 | * @author 58_zhl 13 | * 14 | */ 15 | public class Cptt13_DBNonblock { 16 | 17 | /** 18 | * 并发数量 19 | */ 20 | private static int count=10; 21 | 22 | private static CountDownLatch latch=new CountDownLatch(count); 23 | 24 | public static void testConcurrent() throws InterruptedException{ 25 | for(int i=0;i { 37 | content = content.replace('ERROR_MESSAGE', message); 38 | this.type(options.content_type); 39 | this.end(content); 40 | }); 41 | } 42 | /** 43 | * Bad Request 44 | * @return {Promise} [] 45 | */ 46 | _400Action(){ 47 | return this.displayError(400); 48 | } 49 | /** 50 | * Forbidden 51 | * @return {Promise} [] 52 | */ 53 | _403Action(){ 54 | return this.displayError(403); 55 | } 56 | /** 57 | * Not Found 58 | * @return {Promise} [] 59 | */ 60 | _404Action(){ 61 | return this.displayError(404); 62 | } 63 | /** 64 | * Internal Server Error 65 | * @return {Promise} [] 66 | */ 67 | _500Action(){ 68 | return this.displayError(500); 69 | } 70 | /** 71 | * Service Unavailable 72 | * @return {Promise} [] 73 | */ 74 | _503Action(){ 75 | return this.displayError(503); 76 | } 77 | } -------------------------------------------------------------------------------- /zebra4js/view/home/index_index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Zebra4js 6 | 21 | 22 | 23 |
24 |
25 |

Zebra4js | 落雨 微服务WEB中间件

26 |
27 |
28 |
29 |
30 |
31 |
1
32 |

Zebra

33 |

Fork Zebra-boot visit https://github.com/ae6623/Zebra to view more infomation.

34 | 35 |
36 |
37 |
2
38 |

Zebra4js

39 |

Zebra4js use Zookeeper to connect the Zebra4j micro services

40 |
41 |
42 |
3
43 |

doc

44 |

Zebra-微服务 Zebra-doc and Spring boot visit https://github.com/ae6623/Zebra

45 |
46 |
47 |
48 | 49 | 50 | -------------------------------------------------------------------------------- /zebra4j/zebra-boot/src/test/java/com58/zhl/util/Operator.java: -------------------------------------------------------------------------------- 1 | package com58.zhl.util; 2 | 3 | import java.util.Random; 4 | 5 | public class Operator { 6 | private static Random random=new Random(47); //因子为47是为了保证每次运行的结果都是一致的,方便展示用 7 | private static int failFactor=50; //失败因子,不要太大,否则全是成功了 8 | private static int valueScope=200; //随机数的取值范围,因为取值大小决定着睡眠时间,因此不宜太大 9 | /** 10 | * 模拟请求访问 11 | * @return 12 | */ 13 | @Deprecated 14 | public static boolean request(){ 15 | int n=random.nextInt(valueScope); //注意:该方法没有使用任何同步机制,但为什么能确保是线程安全? 16 | try { 17 | Thread.sleep(n); //随机的睡眠时间,模拟请求处理过程所需要的时间 18 | } catch (InterruptedException e) { System.out.println(" request 请求中断..."); } 19 | return (n%failFactor!=0); // 20 | } 21 | 22 | public static boolean request2() throws InterruptedException{ 23 | int n=random.nextInt(valueScope); //注意:该方法没有使用任何同步机制,但为什么能确保是线程安全? 24 | Thread.sleep(n); //随机的睡眠时间,模拟请求处理过程所需要的时间 25 | return (n%failFactor!=0); // 26 | } 27 | 28 | /** 29 | * 随机等待 30 | */ 31 | @Deprecated 32 | public static void randomSleep(){ 33 | int n=random.nextInt(100); 34 | try { 35 | Thread.sleep(n); 36 | } catch (InterruptedException e) { 37 | System.out.println("randomSleep 请求中断..."); 38 | } 39 | } 40 | 41 | /** 42 | * 随机等待 43 | * @throws InterruptedException 44 | */ 45 | public static void randomSleep2() throws InterruptedException{ 46 | int n=random.nextInt(100); 47 | Thread.sleep(n); 48 | } 49 | 50 | /** 51 | * 模拟处理过程 52 | */ 53 | @Deprecated 54 | public static void process(){ 55 | int n=random.nextInt(valueScope); 56 | try{ 57 | Thread.sleep(n); 58 | }catch(InterruptedException e){ System.out.println(" process 请求中断..."); } 59 | } 60 | 61 | /** 62 | * 模拟处理过程 63 | * @throws InterruptedException 64 | */ 65 | public static void process2() throws InterruptedException{ 66 | int n=random.nextInt(valueScope); 67 | Thread.sleep(n); 68 | } 69 | 70 | public static byte getByte() throws InterruptedException{ 71 | int n=random.nextInt(255); 72 | Thread.sleep(n); 73 | return (byte)n; 74 | } 75 | 76 | } 77 | -------------------------------------------------------------------------------- /Zebra-index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Zebra 6 | 21 | 22 | 23 |
24 |
25 |

Zebra | 落雨 微服务WEB中间件

26 |
27 |
28 |
29 |
30 |
31 |
1
32 |

Zebra4j

33 |

Based on Spring-Boot visit or fork https://github.com/ae6623/Zebra to view more infomation.

34 |

Zebra是基于Spring-Boot 开发的一款JavaWeb/Nodejs新企业级应用框架。

35 |
36 |
37 |
2
38 |

Zebra4js

39 |

Zebra4js use Zookeeper client to connect the Zebra4j Micro Services

40 |
41 |
42 |
3
43 |

doc

44 |

Zebra-微服务文档 Zebra-doc and Spring boot can visit https://github.com/ae6623/Zebra

45 |
46 |
47 |
48 | 49 | 50 | -------------------------------------------------------------------------------- /zebra4j/zebra-boot/src/test/java/connection/CopyOnwriteTest.java: -------------------------------------------------------------------------------- 1 | package connection; 2 | 3 | import java.util.Iterator; 4 | import java.util.List; 5 | import java.util.Random; 6 | import java.util.concurrent.CopyOnWriteArrayList; 7 | import java.util.concurrent.CountDownLatch; 8 | 9 | /** 10 | * Created by lzy@js-dev.cn on 2017/1/15 0015. 11 | * 频繁遍历,又要更新 12 | */ 13 | public class CopyOnwriteTest { 14 | 15 | /** 16 | * 等待线程 17 | */ 18 | private static CountDownLatch countDownLatch = new CountDownLatch(2); 19 | 20 | /** 21 | * 循环次数 22 | */ 23 | private static int forNum = 1000; 24 | 25 | /** 26 | * 初始化数组 27 | */ 28 | private static void initList(List list) { 29 | for (int i=0; i<100; i++){ 30 | list.add(i); 31 | } 32 | } 33 | 34 | /** 35 | * 测试 36 | * @param list 37 | * @throws InterruptedException 38 | */ 39 | public static void test(final List list) throws InterruptedException { 40 | Thread worker = new Thread() { 41 | public void run() { 42 | Random random = new Random(); 43 | for(int i=0; i it = list.iterator(); 66 | while(it.hasNext()) { 67 | it.next(); 68 | } 69 | } 70 | CopyOnwriteTest.countDownLatch.countDown(); 71 | } 72 | }; 73 | worker.start(); 74 | System.out.println("遍历list的线程启动"); 75 | } 76 | 77 | public static void main(String[] args) throws InterruptedException { 78 | long start = System.currentTimeMillis(); 79 | List list = new CopyOnWriteArrayList<>(); 80 | initList(list); 81 | test(list); 82 | countDownLatch.await(); 83 | System.out.println("执行完成"); 84 | long end=System.currentTimeMillis(); 85 | System.out.println((end-start)); 86 | } 87 | 88 | } 89 | -------------------------------------------------------------------------------- /zebra4j/zebra-core/src/main/java/com/zebra/core/util/PropsUtil.java: -------------------------------------------------------------------------------- 1 | package com.zebra.core.util; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | 6 | import java.io.IOException; 7 | import java.io.InputStream; 8 | import java.nio.file.FileSystemNotFoundException; 9 | import java.util.Properties; 10 | 11 | /** 12 | * 读取配置文件工具类 13 | * Created by lzy@js-dev.cn on 2016/10/26. 14 | */ 15 | public class PropsUtil { 16 | 17 | /** 18 | * logger 19 | */ 20 | private static final Logger LOGGER = LoggerFactory.getLogger(PropsUtil.class); 21 | 22 | public static Properties loadProps(String fileName){ 23 | Properties props = null; 24 | InputStream is = null; 25 | try{ 26 | is = ClassUtil.getClassLoader().getResourceAsStream(fileName); 27 | if( is == null){ 28 | throw new FileSystemNotFoundException("file :[" + fileName + "] not found !"); 29 | } 30 | props = new Properties(); 31 | props.load(is); 32 | }catch (IOException e){ 33 | 34 | }finally { 35 | if( is != null){ 36 | try { 37 | is.close(); 38 | } catch (IOException e) { 39 | e.printStackTrace(); 40 | } 41 | } 42 | } 43 | 44 | return props; 45 | 46 | } 47 | 48 | public static String getString(Properties props, String key){ 49 | return getString(props, key, ""); 50 | } 51 | 52 | public static String getString(Properties props, String key, String defaultValue){ 53 | String value = defaultValue; 54 | if( props.contains(key)){ 55 | value = props.getProperty(key); 56 | } 57 | return value; 58 | } 59 | 60 | public static int getInt(Properties props, String key){ 61 | return getInt(props, key, 0); 62 | } 63 | 64 | public static int getInt(Properties props, String key, int defaultValue){ 65 | int value = defaultValue; 66 | if(props.contains(key)){ 67 | value = Integer.valueOf(props.getProperty(key)); 68 | } 69 | return value; 70 | } 71 | 72 | public static boolean getBoolean(Properties props, String key){ 73 | return getBoolean(props,key,false); 74 | } 75 | 76 | public static boolean getBoolean(Properties props, String key, boolean defaultValue){ 77 | boolean value = defaultValue; 78 | if(props.contains(key)){ 79 | value = Boolean.valueOf(props.getProperty(key)); 80 | } 81 | return value; 82 | } 83 | 84 | 85 | 86 | 87 | 88 | } 89 | -------------------------------------------------------------------------------- /zebra4j/zebra-boot/src/test/java/com58/zhl/concurrent/Cpt7_Executor.java: -------------------------------------------------------------------------------- 1 | package com58.zhl.concurrent; 2 | 3 | import java.util.concurrent.ArrayBlockingQueue; 4 | import java.util.concurrent.BlockingQueue; 5 | import java.util.concurrent.RejectedExecutionHandler; 6 | import java.util.concurrent.ThreadFactory; 7 | import java.util.concurrent.ThreadPoolExecutor; 8 | import java.util.concurrent.TimeUnit; 9 | 10 | public class Cpt7_Executor { 11 | 12 | public static void testThreadPoolExecutor(){ 13 | BlockingQueue bq=new ArrayBlockingQueue(10); 14 | //在调用shutdown方法后,抛出RejectedExecutionException的异常 15 | //handler仅影响在执行shutdown后提交任务的响应情况 16 | RejectedExecutionHandler handler=new ThreadPoolExecutor.AbortPolicy(); //默认就是使用该机制 17 | //尽量不要自己创建线程工厂,除非有特殊的需求并且非常的了解线程池的工作机制,或者需要自己的管理机制 18 | //如果不传递默认线程工厂参数,则使用Executors.DefaultThreadFactory 19 | //了解Executors.DefaultThreadFactory的实现 20 | ThreadFactory tf=new MyThreadFactory(); 21 | 22 | //线程池中存在10个线程,最大允许20个线程,比10个多的线程在2秒钟内,没接到任务,就会自动消除 23 | //使用DelayQueue作为任务队列,超出线程范围时,采用拒绝处理的政策 24 | ThreadPoolExecutor tpe=new ThreadPoolExecutor(10, 20, 2, TimeUnit.SECONDS, bq, tf,handler); 25 | // int count=0; 26 | for(int i=0;i<23;i++){ 27 | tpe.execute(new RunEntity()); 28 | System.out.println("add"+i+"========"); 29 | } 30 | tpe.shutdown(); 31 | } 32 | 33 | static class RunEntity extends Thread{ 34 | @Override 35 | public void run() { 36 | System.out.println(Thread.currentThread().getName()+"-------------------------"); 37 | try { 38 | Thread.sleep(1000); 39 | } catch (InterruptedException e) { System.out.println("中断");} 40 | } 41 | 42 | } 43 | 44 | static class MyThreadFactory implements ThreadFactory{ 45 | @Override 46 | public Thread newThread(final Runnable r) { 47 | //该方法的实现一定要处理参数r,否则将无法在线程池中正确的工作 48 | //可参照Executors.DefaultThreadFactory()的实现 49 | return new Thread(){ 50 | public void run(){ 51 | r.run(); 52 | } 53 | }; 54 | } 55 | 56 | } 57 | 58 | public static void main(String args[]){ 59 | /* 60 | * 线程池的存在,本身就是为了给应用程序提供便捷的多线程管理机制,包括线程监控、绑定和管理 61 | * 线程资源。因此ThreadPoolExecutor类可以通过调整参数和可扩展的钩子方法,实现用户自定义的 62 | * 线程池管理。但大多数情况下,都可以通过Executors的new_XXX_ThreadPool()方法,来创建大多数 63 | * 使用场景的线程池。 64 | */ 65 | testThreadPoolExecutor(); 66 | // System.out.println(TimeUnit.NANOSECONDS.name()); 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Introduction 介绍 2 | [![Gitter][badge-gitter-img]][badge-gitter] [![Build Status][badge-travis-img]][badge-travis] ![][zebra] ![][maven] 3 | 4 | GitHub地址:[https://github.com/ae6623/Zebra](https://github.com/ae6623/Zebra) 5 | 6 | OSCGit地址:[http://git.oschina.net/ae6623/Zebra](http://git.oschina.net/ae6623/Zebra) 7 | 8 | ![image](Zebra.jpg) 9 | 10 | zebra-design 11 | 12 | ![image](zebra-design.png) 13 | `Zebra4J`是一款使用`Sping Boot`特性全新开发的微服务`WEB`框架,尝试封装一些常用框架比如`dubbo`等作为`spring-boot`组件,结合微服务的框架思想,利用`NodeJs`、[Zebra4Js](https://github.com/ae6623/Zebra/tree/master/zebra4js)作为应用网关,使得各个功能分层服务,持续迭代,解放团队生产力,快速构建`企业级`Web 应用。 14 | 15 | ## Frameworks and Tools 构建 16 | * Java&IDE: JDK8 Lamda/Intellij Idea 16 17 | * Backend: SpringBoot Docker Zookeeper (Configured by annotation/app) 18 | * Database: Mysql/MongoDB/Redis 19 | * Cache:Memcached/Redis 20 | * Web Server: Nginx/Tomcat 7 21 | * Build Tool: Maven 22 | * Other: Commons-Dbcp2(database connection pool) JUnit sl4j Jackson FastJson 23 | * Zebra4J Port:http://localhost:8888 24 | * Zebra4Js Port:http://localhost:8360 25 | 26 | ## 项目介绍 27 | * 1.如何启动 28 | * Zookeeper集群,3台即可,也可以搭建伪集群,一台机器,解压多个Zookeeper分别放在三个目录,端口号不同即可,核心配置文件在[zoo.cfg](https://github.com/ae6623/Zebra/blob/master/zebra4j/zebra-zookeeper/zoo.cfg)。 29 | * 服务端`Zebra4j`是基于SpringBoot的注册服务端的一个Demo,当多个提供Api的微服务启动,将自动寻找Zookeeper并注册所有的Controller请求映射。 30 | * 网关端`Zebra4js`是基于Nodejs的微服务服务发现,用来作为网关层,对前端请求进行接收,并调用Zookeeper,获取真实的微服务Api接口地址,进行请求,并返回到前端结果。 31 | 32 | ## Feature-list 33 | * 异步接口实现,基于 Spring-Reactor/Rxjava2 34 | * 限流熔断,基于 alibaba-sentinel https://github.com/alibaba/sentinel 35 | * 三方监控 36 | 37 | ## About 关于落雨 38 | * [Github-Me](https://github.com/ae6623) 39 | * [Linkedin-Me](http://www.linkedin.com/in/ae6623) 40 | * [QQ:43163707]() 41 | * [微信:ae6623]() 42 | * [Js-dev.cn](http://js-dev.cn) 43 | 44 | * 详细项目文档持续更新中,也欢迎各位达人提交PR,一起为China🇨🇳开源项目添砖增瓦,`Zebra4J`、`Zebra4Js`文档请参阅 [Zebra-doc/Zebra-微服务.md](https://github.com/ae6623/Zebra/blob/master/zebra4j/zebra-doc/zebra-boot/Zebra-%E5%BE%AE%E6%9C%8D%E5%8A%A1.md) 45 | 46 | [badge-gitter-img]: https://badges.gitter.im/hsz/idea-gitignore.svg 47 | [badge-gitter]: https://gitter.im/hsz/idea-gitignore 48 | [badge-travis-img]: https://travis-ci.org/hsz/idea-gitignore.svg 49 | [badge-travis]: https://travis-ci.org/hsz/idea-gitignore 50 | [zebra]: https://img.shields.io/badge/zebra-fast-orange.svg 51 | [maven]: https://img.shields.io/maven-central/v/org.apache.maven/apache-maven.svg 52 | 53 | 54 | ## License 许可协议 55 | 56 | * [MIT](https://github.com/ae6623/Zebra/blob/master/LICENSE) 57 | -------------------------------------------------------------------------------- /zebra4j/zebra-boot/src/test/java/com58/zhl/concurrent/Cpt3_ConcurrentUtilClass.java: -------------------------------------------------------------------------------- 1 | package com58.zhl.concurrent; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Collections; 5 | import java.util.Iterator; 6 | import java.util.List; 7 | import java.util.Random; 8 | import java.util.concurrent.CopyOnWriteArrayList; 9 | import java.util.concurrent.CountDownLatch; 10 | 11 | /** 12 | * CopyOnWriteArrayList类的应用场景,在需要频繁遍历的同时,又需要对列表有频率的 13 | * 更新时 14 | * @author 58_zhl 15 | * 16 | */ 17 | public class Cpt3_ConcurrentUtilClass { 18 | 19 | /** 20 | * 用于控制住线程暂停 21 | */ 22 | private static CountDownLatch countDownLatch=new CountDownLatch(2); //栅栏 23 | 24 | /** 25 | * 循环次数 26 | */ 27 | private static int forIndex=100000; 28 | 29 | /** 30 | * 测试各种数组的性能 31 | * @throws InterruptedException 32 | */ 33 | public static void testList(final List list) throws InterruptedException{ 34 | Thread run=new Thread(){ 35 | public void run(){ 36 | Random random=new Random(); 37 | for(int i=0;i it=list.iterator(); 57 | //如果CopyOnWriteArrayList,是因为迭代期是迭代时刻的一个快照,因此不需要阻塞写操作 58 | //但是如果普通的数组,因为迭代器会失效Iterator,那么仅能用线程安全的方式,阻塞写操作 59 | //才能进行安全迭代,这样可以有效的增加吞吐量 60 | while(it.hasNext()){ 61 | it.next(); 62 | } 63 | } 64 | Cpt3_ConcurrentUtilClass.countDownLatch.countDown(); //递减,让主线程可执行时间统计 65 | } 66 | }; 67 | run.start(); 68 | System.out.println("遍历list线程启动"); 69 | } 70 | 71 | public static void initList(List list){ 72 | for(int i=0;i<100;i++){ 73 | list.add(i); 74 | } 75 | } 76 | 77 | public static void main(String args[]) throws InterruptedException{ 78 | long start=System.currentTimeMillis(); 79 | // List list=Collections.synchronizedList(new ArrayList()); //线程安全的数组,但是迭代器却不能线程安全 80 | List list=new CopyOnWriteArrayList(); 81 | initList(list); //先让数组有一定的数据 82 | 83 | testList(list); 84 | countDownLatch.await(); 85 | System.out.println("执行完成"); 86 | long end=System.currentTimeMillis(); 87 | System.out.println((end-start)); 88 | 89 | /** 90 | * 思考:网游中,如何展示角色当前所在位置屏幕范围内的其他人物或怪物信息? 91 | */ 92 | } 93 | 94 | 95 | } 96 | -------------------------------------------------------------------------------- /zebra4j/zebra-core/src/main/java/com/zebra/core/util/CastUtil.java: -------------------------------------------------------------------------------- 1 | package com.zebra.core.util; 2 | 3 | import org.apache.commons.lang3.StringUtils; 4 | 5 | /** 6 | * 转换工具类 boolean string number 7 | * Created by lzy@js-dev.cn on 2016/10/26. 8 | */ 9 | public final class CastUtil { 10 | 11 | /** 12 | * 转换为String 13 | * @param obj 14 | * @return 15 | */ 16 | public static String castString(Object obj){ 17 | return CastUtil.castString(obj,""); 18 | } 19 | 20 | /** 21 | * 转换为String (提供默认值) 22 | * @param obj 23 | * @param defaultValue 24 | * @return 25 | */ 26 | public static String castString(Object obj,String defaultValue){ 27 | return obj !=null ? String.valueOf(obj.toString()) : defaultValue; 28 | } 29 | 30 | /** 31 | * 转换成int 32 | * @param obj 33 | * @return 34 | */ 35 | public static int castInt(Object obj){ 36 | return CastUtil.castInt(obj,0); 37 | } 38 | 39 | /** 40 | * 转换成int (提供默认值) 41 | * @param obj 42 | * @param defaultValue 43 | * @return 44 | */ 45 | private static int castInt(Object obj, int defaultValue) { 46 | int value = defaultValue; 47 | if(obj != null) { 48 | String strValue = castString(obj); 49 | if(StringUtils.isNotBlank(strValue)){ 50 | try{ 51 | value = Integer.parseInt(strValue); 52 | }catch(NumberFormatException e){ 53 | value = defaultValue; 54 | } 55 | } 56 | } 57 | return value; 58 | } 59 | 60 | /** 61 | * 转换成Long 62 | * @param obj 63 | * @return 64 | */ 65 | public static long castLong(Object obj){ 66 | return CastUtil.castLong(obj,0); 67 | } 68 | 69 | /** 70 | * 转换成Long (提供默认值) 71 | * @param obj 72 | * @param defaultValue 73 | * @return 74 | */ 75 | private static long castLong(Object obj, long defaultValue) { 76 | long value = defaultValue; 77 | if( obj != null) { 78 | String strValue = castString(obj); 79 | if(StringUtils.isNotBlank(strValue)){ 80 | try{ 81 | value = Long.parseLong(strValue); 82 | }catch (NumberFormatException e){ 83 | value = defaultValue; 84 | } 85 | } 86 | } 87 | return value; 88 | } 89 | 90 | /** 91 | * 转换为Double 92 | * @param obj 93 | * @return 94 | */ 95 | public static double castDouble(Object obj){ 96 | return CastUtil.castDouble(obj,0); 97 | } 98 | 99 | /** 100 | * 转换为Double (提供默认值) 101 | * @param obj 102 | * @param defaultValue 103 | * @return 104 | */ 105 | private static double castDouble(Object obj, double defaultValue) { 106 | double value = defaultValue; 107 | if( obj != null){ 108 | String strValue = castString(obj); 109 | if(StringUtils.isNotBlank(strValue)) { 110 | try { 111 | value = Double.parseDouble(strValue); 112 | }catch (NumberFormatException e){ 113 | value = defaultValue; 114 | } 115 | } 116 | } 117 | return value; 118 | } 119 | 120 | 121 | } 122 | -------------------------------------------------------------------------------- /zebra4j/zebra-boot/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 4.0.0 7 | com.zebra4j 8 | boot 9 | jar 10 | 1.0-SNAPSHOT 11 | 12 | 13 | zebra-boot 14 | zebra spirng-boot-web-module 15 | 16 | 17 | 18 | org.springframework.boot 19 | spring-boot-starter-parent 20 | 1.4.2.RELEASE 21 | 22 | 23 | 24 | 25 | UTF-8 26 | 1.8 27 | 28 | 29 | 30 | 31 | 32 | org.springframework.boot 33 | spring-boot-starter-web 34 | 1.4.2.RELEASE 35 | 36 | 37 | 38 | 39 | org.springframework.boot 40 | spring-boot-starter-logging 41 | 1.4.2.RELEASE 42 | 43 | 44 | 45 | 46 | org.springframework.boot 47 | spring-boot-starter-actuator 48 | 1.4.2.RELEASE 49 | 50 | 51 | 52 | 53 | org.springframework.boot 54 | spring-boot-starter-aop 55 | 1.4.2.RELEASE 56 | 57 | 58 | 59 | 60 | org.springframework.boot 61 | spring-boot-starter-jdbc 62 | 63 | 64 | 65 | 66 | com.alibaba 67 | fastjson 68 | 1.1.43 69 | 70 | 71 | 72 | 73 | org.apache.zookeeper 74 | zookeeper 75 | 3.4.9 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | org.springframework.boot 86 | spring-boot-maven-plugin 87 | 88 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /zebra4j/zebra-boot/src/test/java/com58/zhl/concurrent/Cpt4_Queue.java: -------------------------------------------------------------------------------- 1 | package com58.zhl.concurrent; 2 | 3 | import java.util.Queue; 4 | import java.util.concurrent.ArrayBlockingQueue; 5 | import java.util.concurrent.BlockingQueue; 6 | import java.util.concurrent.ConcurrentLinkedQueue; 7 | 8 | /** 9 | * 可阻塞队列的功能及行为 10 | * @author 58_zhl 11 | */ 12 | public class Cpt4_Queue { 13 | 14 | private static int n=100; 15 | 16 | private static int DIS_MODE=1; 17 | 18 | public static void testBlockingQueue(final Queue queue){ 19 | Thread run=new Thread(){ 20 | public void run(){ 21 | for(int i=0;i){ 23 | try { 24 | //注意:这里一定要用put方法,因为只有put方法才是有界队列的可阻塞方法。 25 | //如果是用add,那么当有界队列满了以后,就会抛出异常。 26 | ((BlockingQueue) queue).put(i); 27 | } catch (InterruptedException e) { } 28 | }else{ 29 | queue.add(i); //非阻塞方法 30 | } 31 | System.out.println("生产:"+i); 32 | try{ 33 | threadSleep(1); //当前模式的生产者睡觉 34 | }catch(InterruptedException e){} 35 | } 36 | } 37 | }; 38 | run.start(); 39 | run=new Thread(){ 40 | public void run(){ 41 | for(int i=0;i){ 44 | try { 45 | //只有BlockingQueue下的take方法才是阻塞的方法 46 | element=((BlockingQueue)queue).take(); 47 | } catch (InterruptedException e) { } 48 | }else{ 49 | element = queue.poll(); //该方法是不受阻塞的 50 | } 51 | System.out.println("消费:"+element); 52 | try { 53 | threadSleep(2); //当面模式的消费者睡眠时间 54 | } catch (InterruptedException e) { } 55 | } 56 | } 57 | }; 58 | run.start(); 59 | 60 | } 61 | 62 | /** 63 | * 线程睡眠 64 | * @param flag 1表示生产者,2表示消费者 65 | * @throws InterruptedException 66 | * @throws Exception 67 | */ 68 | private static void threadSleep(int flag) throws InterruptedException{ 69 | if(DIS_MODE==1){ 70 | switch(flag){ 71 | case 1: 72 | Thread.sleep(20);break; //生产慢 73 | case 2: 74 | Thread.sleep(1);break; //消费快 75 | default: 76 | break; 77 | } 78 | }else if(DIS_MODE==2){ 79 | switch(flag){ 80 | case 1: 81 | Thread.sleep(1);break; //生产快 82 | case 2: 83 | Thread.sleep(40);break; //消费慢 84 | default: 85 | break; 86 | } 87 | }else{ 88 | throw new RuntimeException("不支持..."); 89 | } 90 | } 91 | 92 | public static void main(String args[]){ 93 | 94 | //------------------------------------------------------------ 95 | //线程安全的队列 96 | // testBlockingQueue(new ConcurrentLinkedQueue()); //直接抛出异常,未能正确消费,除非自己编写管理机制,及线程唤醒机制 97 | 98 | 99 | //可阻塞队列,其它数据结构的实现请参照API,BlockingQueue接口 100 | //因为使用有界队列,因此基于数组的有界队列列更合适一点 101 | 102 | //模拟生产者速度慢,消费者速度快 103 | DIS_MODE=1;testBlockingQueue(new ArrayBlockingQueue(3)); //现象说明.... 104 | 105 | //模拟生产者快,消费者速度慢 106 | // DIS_MODE=2;testBlockingQueue(new ArrayBlockingQueue(10)); //现象说明.... 107 | 108 | //------------------------------------------------------------ 109 | 110 | } 111 | 112 | } 113 | -------------------------------------------------------------------------------- /zebra4j/zebra-boot/src/test/java/com58/zhl/concurrent/Cpt9_LockInterface.java: -------------------------------------------------------------------------------- 1 | package com58.zhl.concurrent; 2 | 3 | import java.util.concurrent.locks.Lock; 4 | import java.util.concurrent.locks.ReentrantLock; 5 | 6 | /** 7 | * 基于Lock接口的类 8 | * @author 58_zhl 9 | * 10 | */ 11 | public class Cpt9_LockInterface { 12 | 13 | /** 14 | * 基于Lock的锁分离管理器 15 | * @author 58_zhl 16 | */ 17 | static class LockManager { 18 | private static final int N=10; 19 | private static Lock[] locks=new Lock[N]; 20 | 21 | static { 22 | for(int i=0;i>>1)%N; //去除hasCode的符号位,并取模,得到锁数组的下标 34 | System.out.println("get lock_"+idx); 35 | return locks[idx]; 36 | } 37 | } 38 | 39 | /** 40 | * 测试Lock可以中断已进入排队中的请求 41 | * @param key 42 | */ 43 | public static void synchrMethod(String key){ 44 | Lock lock=LockManager.getLock(key); 45 | try { 46 | lock.lockInterruptibly(); 47 | try{ 48 | Thread.sleep(3000); //睡三秒 49 | String lockAddress=lock.toString(); 50 | int start=lockAddress.indexOf("@"); 51 | int end=lockAddress.indexOf("["); 52 | System.out.println("key:"+key+" lockAddress:"+lockAddress.substring(start+1,end)+"\t执行完成....."); 53 | } catch (InterruptedException e) { 54 | System.out.println("synchrMethod "+key+" 执行中,但已被中断...."); 55 | }finally{ 56 | lock.unlock(); //释放锁 57 | } 58 | } catch (InterruptedException e1) { 59 | System.out.println(key+" 正在排队中,并未获取到锁,已被中断..."); 60 | } 61 | } 62 | 63 | public static void testLock(){ 64 | Thread t1=new Thread(){ 65 | public void run(){ 66 | synchrMethod("1"); 67 | } 68 | }; 69 | t1.start(); 70 | Thread t2=new Thread(){ 71 | public void run(){ 72 | synchrMethod("2"); 73 | } 74 | }; 75 | t2.start(); 76 | //t1、t2并未有任何一个线程等待另一个执行完成,实现了锁分解 77 | } 78 | 79 | /** 80 | * 测试Lock可以中断已经进入排队中的请求 81 | * @throws InterruptedException 82 | */ 83 | public static void testInterruptLock() throws InterruptedException{ 84 | final String lockStr=new String("lockStr_1"); 85 | Thread t1=new Thread(){ 86 | public void run(){ 87 | synchrMethod(lockStr); 88 | System.out.println("线程t1结束...."); //注意:即使synchrMethod已经响应了interrupt信号,这里依然会执行 89 | } 90 | }; 91 | t1.start(); 92 | Thread.sleep(100); //让t1等待一段时间,防止t2先获取到锁 93 | Thread t2=new Thread(){ 94 | public void run(){ 95 | synchrMethod(lockStr); 96 | System.out.println("线程t2结束...."); 97 | } 98 | }; 99 | t2.start(); 100 | Thread.sleep(2000); 101 | t2.interrupt(); //t2未获取到锁应该打印: 排队中的Lock也已经中断 102 | Thread.sleep(100); //睡100毫秒,防止t1先执行结束,如果t1先执行结束,那么t2有一定概率瞬间执行 Thread.sleep(3000); 103 | t1.interrupt(); //t1先获取到锁应该打印: synchrMethod lockStr_1 已中断.... 104 | } 105 | 106 | public static void main(String args[]) throws Exception{ 107 | // testLock(); //Lock的典型用法 108 | 109 | testInterruptLock(); //测试Lock支持中断进入排队中的请求 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /zebra4j/zebra-boot/src/test/java/com58/zhl/concurrent/Cptt14_MyCountDownLatch.java: -------------------------------------------------------------------------------- 1 | package com58.zhl.concurrent; 2 | 3 | import java.util.concurrent.CountDownLatch; 4 | import java.util.concurrent.TimeUnit; 5 | import java.util.concurrent.locks.AbstractQueuedSynchronizer; 6 | 7 | /** 8 | * 基于AbstractQueuedSynchronizer框架的CountDownLatch 9 | * @author 58_zhl 10 | * 11 | */ 12 | public class Cptt14_MyCountDownLatch { 13 | 14 | /** 15 | * 自定义CountDownLatch 16 | * @author 58_zhl 17 | * 18 | */ 19 | static class MyCountDownLatch { 20 | 21 | private final Sync sync; 22 | 23 | public MyCountDownLatch(int count) { 24 | this.sync = new Sync(count); 25 | } 26 | 27 | public void await() throws InterruptedException { 28 | sync.acquireSharedInterruptibly(1); //内部会调用重载的tryAcquireShared(int acquires) 29 | } 30 | 31 | public boolean await(long timeout, TimeUnit unit) 32 | throws InterruptedException { 33 | return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout)); //内部会调用重载的tryAcquireShared(int acquires) 34 | } 35 | 36 | public void countDown() { 37 | sync.releaseShared(1); //内部会调用重载的tryReleaseShared(arg)方法 38 | } 39 | 40 | public long getCount() { 41 | return sync.getCount(); 42 | } 43 | 44 | private static final class Sync extends AbstractQueuedSynchronizer { 45 | 46 | private static final long serialVersionUID = -7364194632496799924L; 47 | 48 | Sync(int count) { 49 | setState(count); 50 | } 51 | 52 | int getCount() { 53 | return getState(); 54 | } 55 | 56 | public int tryAcquireShared(int acquires) { 57 | return getState() == 0 ? 1 : -1; //很显然,这句代码不是线程安全的。思考一下CountDownLatch的特性,做出解释 58 | } 59 | 60 | /** 61 | * 如果状态state为0,则返回true 62 | */ 63 | public boolean tryReleaseShared(int releases) { 64 | for (;;) { //非阻塞算法 65 | int c = getState(); 66 | if (c == 0) //先判断是否为0,如果为0,那么直接返回,这样就可以保证nextc一定不会小于0 67 | return false; 68 | int nextc = c - 1; 69 | System.out.println(nextc+"====="+c); 70 | if (compareAndSetState(c, nextc)) 71 | return nextc == 0; 72 | } 73 | } 74 | } 75 | } 76 | 77 | /** 78 | * 执行结果,可以看到 79 | * @throws InterruptedException 80 | */ 81 | public static void test1() throws InterruptedException{ 82 | int n1=2; //自定义线程的阻塞 83 | final MyCountDownLatch countDown=new MyCountDownLatch(n1); 84 | for(int i=0;i handlerMethods = mapping.getHandlerMethods(); 54 | for (RequestMappingInfo key : handlerMethods.keySet()) { 55 | String serviceName = key.getName(); 56 | if(!StringUtils.isEmpty(serviceName)){ 57 | //不等于空,则拿到了服务名称,则立即注册 58 | registry.register(serviceName,String.format("%s:%d",serverAddress,serverPort)); 59 | } 60 | } 61 | } 62 | 63 | @Override 64 | public void contextDestroyed(ServletContextEvent servletContextEvent) { 65 | //向注册中心销毁自己的服务信息 66 | 67 | //获取上下文 68 | ServletContext sc = servletContextEvent.getServletContext(); 69 | //获取ac 70 | ApplicationContext ac = WebApplicationContextUtils.getRequiredWebApplicationContext(sc); 71 | 72 | //获取Mapping(就是存放了所有的Controoler中@Path注解的Url映射) 73 | RequestMappingHandlerMapping mapping = ac.getBean(RequestMappingHandlerMapping.class); 74 | //遍历所有的handlerMethods(为了从mapping中取出Url,交给Zookeeper进行注册) 75 | Map handlerMethods = mapping.getHandlerMethods(); 76 | for (RequestMappingInfo key : handlerMethods.keySet()) { 77 | String serviceName = key.getName(); 78 | if (!StringUtils.isEmpty(serviceName)) { 79 | logger.info("卸载服务:" + serviceName); 80 | //不等于空,表示找到了配置中心的服务地址,则拿到了服务名称,要进行立即注册 81 | registry.unRegister(serviceName, String.format("%s:%d", serverAddress, serverPort)); 82 | } 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /zebra4j/zebra-boot/src/test/java/com58/zhl/concurrent/Cpt6_CyclicBarrierAndExchanger.java: -------------------------------------------------------------------------------- 1 | package com58.zhl.concurrent; 2 | 3 | import java.util.concurrent.BrokenBarrierException; 4 | import java.util.concurrent.CyclicBarrier; 5 | import java.util.concurrent.Exchanger; 6 | 7 | import com58.zhl.util.Convert; 8 | import com58.zhl.util.Operator; 9 | 10 | /** 11 | * CyclicBarrier 栅栏 12 | * Exchanger 线程交换 13 | * @author 58_zhl 14 | * 15 | */ 16 | public class Cpt6_CyclicBarrierAndExchanger { 17 | 18 | private static int TEST_COUNT=10; 19 | 20 | /** 21 | * 展示栅栏的应用方式 22 | */ 23 | public static void testCyclicBarrier(){ 24 | final CyclicBarrier cb=new CyclicBarrier(TEST_COUNT,new Runnable(){ 25 | private int count=0; 26 | @Override 27 | public void run() { 28 | count++; 29 | System.out.println("=========================第"+count+"次释放线程=========================="); 30 | } 31 | }); 32 | 33 | for(int i=0;i exchanger=new Exchanger(); 62 | final Byte[] b1=new Byte[100]; 63 | final Byte[] b2=new Byte[100]; 64 | final int n=10; 65 | Thread input=new Thread(){ 66 | public void run(){ 67 | Byte[] currentB=b1; 68 | for(int i=0;i logs=new ArrayBlockingQueue(30); 20 | 21 | 22 | /** 23 | * 日志输出线程.. 24 | * 25 | */ 26 | static class LogWriteThread extends Thread{ 27 | 28 | public void run(){ 29 | System.out.println("日志输出进程已启动...."); 30 | while(true){ //该线程会作为守护线程,因此不需要有退出的口,因为在主进程执行完毕后,会自动退出 31 | try { 32 | String str=logs.take(); 33 | System.out.println("logWrite:"+str); 34 | Thread.sleep(500); 35 | } catch (InterruptedException e) { 36 | System.out.println("弹出日志异常"); 37 | } 38 | } 39 | } 40 | 41 | } 42 | 43 | /** 44 | * 钩子进程输出所有未输出的日志信息 45 | * @author 58_zhl 46 | * 47 | */ 48 | static class HookLogWriteThread extends Thread{ 49 | public void run(){ //钩子线程的run主要针对java系统执行System.exit(n);内部程序请求退出JVM 50 | System.out.println("钩子进程启动...."); 51 | int n=0; 52 | while(!logs.isEmpty()){ 53 | try { 54 | System.out.println("睡眠 "+(++n)+" 次"); 55 | Thread.sleep(500); //因为这里睡眠,所以实时性不够好。。如果不睡眠则不停的循环浪费资源 56 | } catch (InterruptedException e) { 57 | System.out.println("钩子进程请求中断..."); 58 | } 59 | } 60 | System.out.println("钩子进程执行完毕..."); 61 | } 62 | 63 | } 64 | 65 | /** 66 | * 中断信号捕获 67 | * @author 58_zhl 68 | * 69 | */ 70 | static class TerminateThread implements SignalHandler{ 71 | @Override 72 | public void handle(Signal arg0) { 73 | System.out.println("系统中断...."); 74 | int n=0; 75 | while(!logs.isEmpty()){ 76 | try { 77 | System.out.println("睡眠 "+(++n)+" 次"); 78 | Thread.sleep(500); 79 | } catch (InterruptedException e) { 80 | System.out.println("钩子进程请求中断..."); 81 | } 82 | } 83 | System.out.println("系统中断完毕...."); 84 | System.exit(-1); 85 | } 86 | 87 | } 88 | 89 | /** 90 | * 生成日志线程 91 | * 92 | */ 93 | static class GeneratorLogThread extends Thread{ 94 | 95 | public void run(){ 96 | String baseStr=this.getName()+"==第"; 97 | for(int i=1;i<11;i++){ //模拟生成日志,到Logs队列中 98 | try { 99 | Cptt12_LogWriter.logs.put(baseStr+i+" 条日志"); 100 | } catch (InterruptedException e) { 101 | System.out.println(baseStr+"请求中断"); 102 | } 103 | } 104 | System.out.println(this.getName()+"生产日志完毕..."); 105 | } 106 | } 107 | 108 | /** 109 | * 测试普通钩子效果 110 | */ 111 | public static void testLogWriter_1(){ 112 | Thread logWriterThread=new LogWriteThread(); 113 | logWriterThread.setDaemon(true); //设置为守护进程 114 | logWriterThread.start(); 115 | new GeneratorLogThread().start(); // 116 | new GeneratorLogThread().start(); 117 | Runtime.getRuntime().addShutdownHook(new HookLogWriteThread()); //设置钩子线程 118 | } 119 | 120 | /** 121 | * 测试信号捕获 122 | * @throws InterruptedException 123 | */ 124 | public static void testLogWriter_2() throws InterruptedException{ 125 | Thread logWriterThread=new LogWriteThread(); 126 | logWriterThread.start(); 127 | new GeneratorLogThread().start(); // 128 | new GeneratorLogThread().start(); 129 | Thread.sleep(1000); 130 | Signal signal=new Signal("INT"); //程序结束信号,该信号可以被阻塞和处理 131 | Signal.handle(signal, new TerminateThread()); 132 | } 133 | 134 | public static void main(String args[]) throws InterruptedException{ 135 | /** 136 | * 该类型常用于本地程序的开发,主线程主要负责启动服务线程,在服务线程未结束时,JVM一直处于运行状态。 137 | * 而清理服务线程资源的线程,往往设置为守护进程,这样在主线程启动的所有服务线程结束时,这些守护线程 138 | * 会自动退出,不会影响进程的正常退出。但如想要在程序正常退出后,需清理守护进程的资源,则需要用钩子 139 | */ 140 | testLogWriter_1(); //钩子方式 141 | 142 | /** 143 | * 有时候,我们可能需要捕获系统的事件行为,来判断用户期望的请求操作。例如:执行ctrl+C不需要正常启动 144 | * 应用程序,而是异常退出,这样就不需要做资源保存工作等。这时,可以通过Signal注册一系列的系统信号来 145 | * 执行对应的操作。下面虽然用Signal来清理系统资源,但是在任何情况下,应该优先使用钩子来清理资源,而 146 | * 捕获系统信号,应该作为一种事件处理。 147 | */ 148 | //java com58.zhl.concurrent.Cptt12_LogWriter 149 | // testLogWriter_2(); //中断信号处理 150 | } 151 | 152 | } 153 | -------------------------------------------------------------------------------- /zebra4j/zebra-boot/src/main/java/com/zebra/boot/registry/impl/ZebraRegistry.java: -------------------------------------------------------------------------------- 1 | package com.zebra.boot.registry.impl; 2 | 3 | import com.zebra.boot.registry.IRegistry; 4 | import org.apache.zookeeper.*; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | import org.springframework.stereotype.Component; 8 | import org.springframework.util.StringUtils; 9 | 10 | import java.io.IOException; 11 | import java.util.HashMap; 12 | import java.util.Map; 13 | import java.util.concurrent.CountDownLatch; 14 | 15 | /** 16 | * Created by ae6623 on 2016/11/22. 17 | *

18 | * Zebra默认的注册中心实现类,供网关进行调用 19 | */ 20 | //@Component 21 | public class ZebraRegistry implements IRegistry, Watcher { 22 | 23 | /** 24 | * Time_out 心跳超时时间 25 | */ 26 | private static final int SESSION_TIMEOUT = 6000; 27 | 28 | /** 29 | * logger 30 | */ 31 | private static Logger logger = LoggerFactory.getLogger(ZebraRegistry.class); 32 | 33 | /** 34 | * 线程同步 35 | */ 36 | private static CountDownLatch latch = new CountDownLatch(1); 37 | 38 | /** 39 | * zk 根节点 40 | */ 41 | private static final String REGISTRY_PATH = "/registry"; 42 | 43 | /** 44 | * zk 地址前缀 45 | */ 46 | private static final String ADDRESS_PREFIX = "address-"; 47 | 48 | /** 49 | * zk service 映射 50 | */ 51 | private static Map zkServiceNodeMap = new HashMap(); 52 | 53 | /** 54 | * zoo 55 | */ 56 | private ZooKeeper zk; 57 | 58 | /** 59 | * constructor 60 | */ 61 | public ZebraRegistry() { 62 | 63 | } 64 | 65 | public ZebraRegistry(String zkServers) { 66 | try { 67 | zk = new ZooKeeper(zkServers, SESSION_TIMEOUT, this); 68 | //在zk创建之前,阻塞线程,让线程处于等待状态 69 | latch.await(); 70 | logger.info("Zebra is connecting to the zookeeper services : " + zkServers); 71 | } catch (IOException e) { 72 | e.printStackTrace(); 73 | } catch (InterruptedException e) { 74 | e.printStackTrace(); 75 | } 76 | 77 | } 78 | 79 | @Override 80 | public void register(String serviceName, String address) { 81 | 82 | //防止重复注册 83 | if (!StringUtils.isEmpty(zkServiceNodeMap.get(serviceName))) { 84 | logger.info(serviceName + "已经注册过,地址为:" + zkServiceNodeMap.get(serviceName)); 85 | return; 86 | } 87 | 88 | //根节点路径 89 | String registryPath = REGISTRY_PATH; 90 | 91 | try { 92 | if (zk.exists(registryPath, false) == null) { 93 | //如果木有根节点,则创建一个根节点 94 | zk.create(registryPath, null, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); 95 | logger.info("创建根节点 ok! ->" + registryPath); 96 | } 97 | 98 | //服务节点路径 99 | String servicePath = registryPath + serviceName; 100 | 101 | if (zk.exists(servicePath, false) == null) { 102 | //如果没有服务节点,则创建服务节点 103 | zk.create(servicePath, null, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); 104 | logger.info("创建服务节点 ok! ->" + servicePath); 105 | } 106 | 107 | //ip端口 108 | String addressPath = servicePath + "/" + ADDRESS_PREFIX; 109 | String addressNode = zk.create(addressPath, address.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, 110 | CreateMode.EPHEMERAL_SEQUENTIAL); 111 | 112 | //放入映射关系map,方便服务卸载 113 | zkServiceNodeMap.put(serviceName, addressPath + addressNode); 114 | logger.info("创建实际服务 ok! ->" + addressNode, zk.getData(addressNode, false, null)); 115 | 116 | } catch (KeeperException e) { 117 | e.printStackTrace(); 118 | } catch (InterruptedException e) { 119 | e.printStackTrace(); 120 | } 121 | } 122 | 123 | @Override 124 | public void unRegister(String serviceName, String address) { 125 | String addressPath = zkServiceNodeMap.get(serviceName); 126 | try { 127 | if (StringUtils.isEmpty(addressPath)) { 128 | return; 129 | } 130 | //删除zk服务需要注意,zk只允许删除叶子节点,所以一定要慢慢的删 131 | // TODO:当前版本还未删除根节点以及二级节点,后续实现 132 | if (zk.exists(addressPath, false) == null) { 133 | zk.delete(addressPath, -1); 134 | logger.info("删除服务节点" + addressPath + "ok"); 135 | } 136 | } catch (KeeperException e) { 137 | e.printStackTrace(); 138 | } catch (InterruptedException e) { 139 | e.printStackTrace(); 140 | } 141 | } 142 | 143 | @Override 144 | public void process(WatchedEvent watchedEvent) { 145 | if (watchedEvent.getState() == Event.KeeperState.SyncConnected) { 146 | //结束线程阻塞,结束等待 147 | latch.countDown(); 148 | } 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /zebra4js/nginx.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen 80; 3 | server_name example.com www.example.com; 4 | root /Users/ae6623/IdeaProjects/thinkjs/zebra4js/www; 5 | set $node_port 8360; 6 | 7 | index index.js index.html index.htm; 8 | if ( -f $request_filename/index.html ){ 9 | rewrite (.*) $1/index.html break; 10 | } 11 | if ( !-f $request_filename ){ 12 | rewrite (.*) /index.js; 13 | } 14 | location = /index.js { 15 | proxy_http_version 1.1; 16 | proxy_set_header X-Real-IP $remote_addr; 17 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 18 | proxy_set_header Host $http_host; 19 | proxy_set_header X-NginX-Proxy true; 20 | proxy_set_header Upgrade $http_upgrade; 21 | proxy_set_header Connection "upgrade"; 22 | proxy_pass http://127.0.0.1:$node_port$request_uri; 23 | proxy_redirect off; 24 | } 25 | 26 | location = /development.js { 27 | deny all; 28 | } 29 | 30 | location = /testing.js { 31 | deny all; 32 | } 33 | 34 | location = /production.js { 35 | deny all; 36 | } 37 | 38 | location ~ /static/ { 39 | etag on; 40 | expires max; 41 | } 42 | } 43 | 44 | 45 | 46 | 47 | ## http/2 nginx conf 48 | 49 | # server { 50 | # listen 80; 51 | # server_name example.com www.example.com; 52 | # rewrite ^(.*) https://example.com$1 permanent; 53 | # } 54 | # 55 | # server { 56 | # listen 443 ssl http2 fastopen=3 reuseport; 57 | # server_name www.thinkjs.org thinkjs.org; 58 | # set $node_port 8360; 59 | # 60 | # root /Users/ae6623/IdeaProjects/thinkjs/zebra4js/www; 61 | # 62 | # keepalive_timeout 70; 63 | # 64 | # ssl_certificate /path/to/certificate; 65 | # ssl_certificate_key /path/to/certificate.key; 66 | # ssl_protocols TLSv1 TLSv1.1 TLSv1.2; 67 | # ssl_ciphers "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA"; 68 | # ssl_prefer_server_ciphers on; 69 | 70 | # # openssl dhparam -out dhparams.pem 2048 71 | # ssl_dhparam /path/to/dhparams.pem; 72 | # 73 | # ssl_session_cache shared:SSL:10m; 74 | # ssl_session_timeout 10m; 75 | # 76 | # ssl_session_ticket_key /path/to/tls_session_ticket.key; 77 | # ssl_session_tickets on; 78 | # 79 | # ssl_stapling on; 80 | # ssl_stapling_verify on; 81 | # ssl_trusted_certificate /path/to/startssl_trust_chain.crt; 82 | # 83 | # 84 | # add_header x-Content-Type-Options nosniff; 85 | # add_header X-Frame-Options deny; 86 | # add_header Strict-Transport-Security "max-age=16070400"; 87 | # 88 | # index index.js index.html index.htm; 89 | # if ( -f $request_filename/index.html ){ 90 | # rewrite (.*) $1/index.html break; 91 | # } 92 | # if ( !-f $request_filename ){ 93 | # rewrite (.*) /index.js; 94 | # } 95 | # location = /index.js { 96 | # proxy_http_version 1.1; 97 | # proxy_set_header X-Real-IP $remote_addr; 98 | # proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 99 | # proxy_set_header Host $http_host; 100 | # proxy_set_header X-NginX-Proxy true; 101 | # proxy_set_header Upgrade $http_upgrade; 102 | # proxy_set_header Connection "upgrade"; 103 | # proxy_pass http://127.0.0.1:$node_port$request_uri; 104 | # proxy_redirect off; 105 | # } 106 | # 107 | # location = /production.js { 108 | # deny all; 109 | # } 110 | # 111 | # location = /testing.js { 112 | # deny all; 113 | # } 114 | # 115 | # location ~ /static/ { 116 | # etag on; 117 | # expires max; 118 | # } 119 | #} 120 | 121 | -------------------------------------------------------------------------------- /zebra4j/zebra-boot/src/test/java/com58/zhl/concurrent/Cptt10_CustomBlocking.java: -------------------------------------------------------------------------------- 1 | package com58.zhl.concurrent; 2 | 3 | import java.util.LinkedList; 4 | import java.util.concurrent.locks.Condition; 5 | import java.util.concurrent.locks.Lock; 6 | import java.util.concurrent.locks.ReentrantLock; 7 | 8 | /** 9 | * 阻塞行为的应用 10 | * @author 58_zhl 11 | * 12 | */ 13 | public class Cptt10_CustomBlocking { 14 | 15 | private static int LEN=3; 16 | 17 | static interface MyBlockingInterface{ 18 | /** 19 | * 添加操作 20 | * @param e 21 | * @throws InterruptedException 22 | */ 23 | public void put(T e) throws InterruptedException; 24 | 25 | /** 26 | * 弹出操作 27 | * @return 28 | * @throws InterruptedException 29 | */ 30 | public T take() throws InterruptedException; 31 | } 32 | 33 | /** 34 | * 自定义的阻塞队列,仅仅是介绍一种用法,因为现实应用中,很可能某个类的 35 | * 行为需要拥有阻塞的功能,这时可能用现有API不太容易实现 36 | * @author 58_zhl 37 | * @param 38 | */ 39 | static class MyBlokingLinked implements MyBlockingInterface{ 40 | 41 | private LinkedList list=new LinkedList(); 42 | 43 | public void put(T e) throws InterruptedException{ 44 | synchronized(this){ 45 | //可能上面还有一些与业务相关的代码..... 46 | while(list.size()==LEN) //这段操作时,需要暂时堵塞... 47 | wait(); 48 | list.addLast(e); 49 | notifyAll(); //注意这里一定要使用notifyAll 50 | } 51 | } 52 | 53 | public T take() throws InterruptedException{ 54 | synchronized(this){ 55 | T element=null; 56 | while(list.size()==0) 57 | wait(); 58 | element=list.removeFirst(); 59 | notifyAll(); //注意这里一定要使用notifyAll 60 | return element; 61 | } 62 | } 63 | } 64 | 65 | 66 | /** 67 | * 一个限定池 68 | * @author Administrator 69 | * 70 | */ 71 | static class MyBlockingQueue implements MyBlockingInterface{ 72 | 73 | private final Lock lock=new ReentrantLock(); 74 | 75 | /** 76 | * 用于堵塞元素数组已经处于饱和状态时,后续请求添加的线程 77 | */ 78 | private final Condition notFull=lock.newCondition(); 79 | 80 | /** 81 | * 用于堵塞元素数组为空时,后续请求获取元素的线程 82 | */ 83 | private final Condition notEmpty=lock.newCondition(); 84 | 85 | /** 86 | * 队列元素个数 87 | */ 88 | private int count=0; 89 | 90 | /** 91 | * 当前的队列头数组的索引 92 | */ 93 | private int head=0; 94 | 95 | /** 96 | * 当前的队列尾数组的索引 97 | */ 98 | private int last=0; 99 | 100 | private final T[] items=(T[])new Object[LEN]; 101 | 102 | public void put(T x) throws InterruptedException{ 103 | lock.lock(); 104 | try{ 105 | while(count==items.length) //如果已经达到了最大值,需要进入阻塞状态 106 | notFull.await(); 107 | items[last]=x; 108 | if(++last==items.length) //如果可用的索引已达到了数组末尾,则从0继续开始保存 109 | last=0; 110 | ++count; //添加元素计数器 111 | notEmpty.signal(); //唤醒那些因队列已空,但仍在等待弹出的线程 112 | }finally{ 113 | lock.unlock(); 114 | } 115 | } 116 | 117 | public T take() throws InterruptedException{ 118 | lock.lock(); 119 | try{ 120 | while(count==0) //如果当前数组中没有元素了,则处于等待状态 121 | notEmpty.await(); 122 | T x=items[head]; //取出队列头 123 | items[head]=null; 124 | if(++head==items.length) //如果队列头已经到了数组末尾,则从下标0继续取数据 125 | head=0; 126 | --count; 127 | notFull.signal(); //唤醒那些因队列已满,仍在等待添加的线程 128 | return x; 129 | }finally{ 130 | lock.unlock(); 131 | } 132 | } 133 | 134 | } 135 | 136 | /** 137 | * 测试自定义的阻塞队列 138 | */ 139 | public static void testMyBlockingQueue(final MyBlockingInterface list){ 140 | // final MyBlokingLinked list=new MyBlokingLinked(); 141 | final int count=10; //元素个数 142 | Thread t1=new Thread(){ //添加线程 143 | public void run(){ 144 | try { 145 | for(int i=0;i()); //wait+linked实现方式 171 | 172 | testMyBlockingQueue(new MyBlockingQueue()); //condition实现方式 173 | } 174 | 175 | } 176 | -------------------------------------------------------------------------------- /zebra4j/zebra-core/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.zebra4j 8 | core 9 | pom 10 | 1.0-SNAPSHOT 11 | 12 | 13 | 14 | 15 | 16 | UTF-8 17 | 18 | 19 | 20 | 21 | 22 | javax.servlet 23 | javax.servlet-api 24 | 3.1.0 25 | provided 26 | 27 | 28 | 29 | 30 | javax.servlet.jsp 31 | jsp-api 32 | 2.2 33 | provided 34 | 35 | 36 | 37 | 38 | javax.servlet 39 | jstl 40 | 1.2 41 | runtime 42 | 43 | 44 | 45 | 46 | org.slf4j 47 | slf4j-log4j12 48 | 1.7.7 49 | 50 | 51 | 52 | mysql 53 | mysql-connector-java 54 | 5.1.33 55 | runtime 56 | 57 | 58 | 59 | 60 | com.fasterxml.jackson.core 61 | jackson-databind 62 | 2.5.2 63 | 64 | 65 | 66 | 67 | cglib 68 | cglib 69 | 2.2.2 70 | 71 | 72 | 73 | 74 | commons-lang 75 | commons-lang 76 | 2.6 77 | 78 | 79 | 80 | 81 | org.apache.commons 82 | commons-collections4 83 | 4.0 84 | 85 | 86 | 87 | 88 | commons-dbutils 89 | commons-dbutils 90 | 1.6 91 | 92 | 93 | 94 | 95 | org.apache.commons 96 | commons-dbcp2 97 | 2.0.1 98 | 99 | 100 | 101 | 102 | commons-fileupload 103 | commons-fileupload 104 | 1.3.1 105 | 106 | 107 | 108 | 109 | commons-codec 110 | commons-codec 111 | 1.10 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | org.apache.maven.plugins 122 | maven-compiler-plugin 123 | 3.3 124 | 125 | 1.8 126 | 1.8 127 | 128 | 129 | 130 | 131 | 132 | org.apache.maven.plugins 133 | maven-surefire-plugin 134 | 2.18.1 135 | 136 | true 137 | 138 | 139 | 140 | 141 | -------------------------------------------------------------------------------- /zebra4j/zebra-boot/src/test/java/com58/zhl/concurrent/Cpt1_StringLockManager.java: -------------------------------------------------------------------------------- 1 | package com58.zhl.concurrent; 2 | 3 | import java.util.HashMap; 4 | 5 | /** 6 | * String锁管理 7 | * @author 58_zhl 8 | * 9 | */ 10 | public class Cpt1_StringLockManager { 11 | 12 | /** 13 | * 用于管理锁的map 14 | */ 15 | private static HashMap locks=new HashMap(); 16 | 17 | /** 18 | * 获取锁操作 19 | * @param keyStr 锁字符串 20 | * @return 21 | */ 22 | public static String getLock(String keyStr){ 23 | synchronized(Cpt1_StringLockManager.class){ //用全局锁来锁定获取锁操作的步骤 24 | LockBean bean=locks.get(keyStr); 25 | if(bean==null){ 26 | bean=new LockBean(keyStr); 27 | locks.put(keyStr, bean); //用锁字符串作为key,而bean是具体的锁信息。 28 | } 29 | bean.n++; //统计某把锁的个数,当锁个数为0时,可以清除对该锁的管理 30 | //bean.key保存了第一个放入该map中的锁对象,因为只有内存地址相等的情况下,才能认为是同一把锁。 31 | //其它任何情况,都不会认为是同一把锁 32 | return bean.key; 33 | } 34 | } 35 | 36 | /** 37 | * 当锁使用完毕时,必须在finally{}块中使用该函数来释放锁 38 | * @param keyStr 锁字符串 39 | */ 40 | public static void removeLock(String keyStr){ 41 | synchronized(Cpt1_StringLockManager.class){ //删除操作同样需要使用全局锁来确保getLock和removeLock是线程安全的 42 | LockBean bean=locks.get(keyStr); 43 | if(bean!=null){ 44 | if((--bean.n)==0){ //当锁计数为0的时候,在locks中删除该锁 45 | locks.remove(keyStr); 46 | // System.out.println("已删除锁"); 47 | }else{ //如果锁计数不为0,则仅仅是将计数器减一,不删除锁因为可能还有其它一个或多个线程持有锁 48 | System.out.println("未删除锁"); 49 | } 50 | } 51 | } 52 | } 53 | 54 | /** 55 | * 锁管理的工具bean 56 | * @author 58 57 | * 58 | */ 59 | private static class LockBean{ 60 | String key; //锁字符串 61 | int n; //锁计数器 62 | LockBean(String key){ 63 | this.key=key; 64 | this.n=0; 65 | } 66 | } 67 | 68 | public static void testLock(String lockStr, String threadName) { 69 | synchronized (lockStr) { 70 | //注意:synchronized(){ try{....}finally{....} }这种写法在同步块中是最常见的写法。 71 | //就像db访问时的try{}catch()finally{}的写法 72 | try { 73 | for (int i = 0; i < 10; i++) { 74 | try { 75 | System.out.println(lockStr + "===" + threadName); 76 | Thread.sleep(1000); //睡一秒,为了保证有足够的时间来观察执行过程 77 | } catch (InterruptedException e) { 78 | e.printStackTrace(); 79 | } 80 | } 81 | } finally { 82 | removeLock(lockStr); //必须要在这里removeLock,否则就会出现内存溢出的情况 83 | } 84 | } 85 | } 86 | 87 | 88 | public static void test22(String lockStr, String threadName) { 89 | synchronized (lockStr) { 90 | //注意:synchronized(){ try{....}finally{....} }这种写法在同步块中是最常见的写法。 91 | //就像db访问时的try{}catch()finally{}的写法 92 | try { 93 | for (int i = 0; i < 10; i++) { 94 | try { 95 | System.out.println(lockStr + "===" + threadName); 96 | Thread.sleep(1000); //睡一秒,为了保证有足够的时间来观察执行过程 97 | } catch (InterruptedException e) { 98 | e.printStackTrace(); 99 | } 100 | } 101 | } finally { 102 | removeLock(lockStr); //必须要在这里removeLock,否则就会出现内存溢出的情况 103 | } 104 | } 105 | } 106 | 107 | /** 108 | * 普通没有锁管理 109 | */ 110 | public static void test1(final String a1,final String a2){ 111 | Thread run=new Thread(){ 112 | @Override 113 | public void run() { 114 | Cpt1_StringLockManager.testLock(a1, this.getName()); //未对a1进行管理,直接使用 115 | } 116 | }; 117 | run.start(); 118 | run=new Thread(){ 119 | @Override 120 | public void run() { 121 | Cpt1_StringLockManager.test22(a2, this.getName()); //未对a2进行管理,直接使用 122 | } 123 | }; 124 | run.start(); 125 | } 126 | 127 | /** 128 | * 锁管理的情况下 129 | */ 130 | public static void test2(final String a1,final String a2){ 131 | Thread run=new Thread(){ 132 | @Override 133 | public void run() { 134 | String lockStr=getLock(a1); //通过锁管理器获取锁对象 135 | Cpt1_StringLockManager.testLock(lockStr, this.getName()); 136 | } 137 | }; 138 | run.start(); 139 | run=new Thread(){ 140 | @Override 141 | public void run() { 142 | String lockStr=getLock(a2); //通过锁管理器获取锁对象 143 | Cpt1_StringLockManager.test22(lockStr, this.getName()); 144 | } 145 | }; 146 | run.start(); 147 | } 148 | 149 | public static void test3(final String lockStr){ 150 | final String n="1234"; 151 | 152 | Thread run=new Thread(){ 153 | @Override 154 | public void run() { 155 | Cpt1_StringLockManager.testLock(lockStr, this.getName()); 156 | } 157 | }; 158 | run.start(); 159 | run=new Thread(){ 160 | @Override 161 | public void run() { 162 | Cpt1_StringLockManager.test22(n, this.getName()); 163 | } 164 | }; 165 | run.start(); 166 | } 167 | 168 | /** 169 | * 测试锁管理的性能 170 | */ 171 | public static void testLockManagerPerformance(){ 172 | long count=0; 173 | int n=500000; 174 | for(int i=0;i loadClass(String className) { 42 | return loadClass(className, true); 43 | } 44 | 45 | /** 46 | * 加载类 47 | * 48 | * @param className 49 | * @param isInitialized 50 | * @return 51 | */ 52 | public static Class loadClass(String className, boolean isInitialized) { 53 | Class cls = null; 54 | try { 55 | cls = Class.forName(className, isInitialized, getClassLoader()); 56 | } catch (ClassNotFoundException e) { 57 | LOGGER.error("load class failure", e); 58 | e.printStackTrace(); 59 | } 60 | return cls; 61 | } 62 | 63 | /** 64 | * 获取指定包名下的所有的类 65 | * 66 | * @param packageName 67 | * @return 68 | */ 69 | public static Set> getClassSet(String packageName) { 70 | Set> classSet = new HashSet>(); 71 | 72 | try { 73 | //获取包名的路径 74 | Enumeration urls = getClassLoader().getResources(packageName.replace(".", "/")); 75 | while (urls.hasMoreElements()) { 76 | //取出包下的类路径 77 | URL url = urls.nextElement(); 78 | if (url != null) { 79 | //获取url协议 80 | String protocol = url.getProtocol(); 81 | if ("file".equalsIgnoreCase(protocol)) { 82 | String packagePath = url.getPath().replaceAll("%20", " "); 83 | addClass(classSet, packagePath, packageName); 84 | } else if ("jar".equalsIgnoreCase(protocol)) { 85 | JarURLConnection jarUrlConnection = (JarURLConnection) url.openConnection(); 86 | if (jarUrlConnection != null) { 87 | JarFile jarFile = jarUrlConnection.getJarFile(); 88 | if (jarFile != null) { 89 | Enumeration jarEntries = jarFile.entries(); 90 | while (jarEntries.hasMoreElements()) { 91 | JarEntry jarEntry = jarEntries.nextElement(); 92 | String jarEntryName = jarEntry.getName(); 93 | if (jarEntryName.endsWith(".class")) { 94 | String className = jarEntryName.substring(0, jarEntryName.lastIndexOf(".")).replaceAll("/", "."); 95 | doAddClass(classSet, className); 96 | } 97 | } 98 | } 99 | } 100 | } 101 | } 102 | } 103 | } catch (IOException e) { 104 | e.printStackTrace(); 105 | } 106 | return classSet; 107 | } 108 | 109 | /** 110 | * 类加载器,添加.Class文件 111 | * 112 | * @param classSet 113 | * @param packagePath 114 | * @param packageName 115 | */ 116 | private static void addClass(Set> classSet, String packagePath, String packageName) { 117 | File[] files = new File(packagePath).listFiles( 118 | file -> (file.isFile() && file.getName().endsWith(".class")) || file.isDirectory() 119 | ); 120 | /* 121 | Arrays.asList(files).stream() 122 | .filter(file -> file.isFile()) 123 | .forEach(file -> { 124 | String fileName = file.getName(); 125 | String className = fileName.substring(0, fileName.lastIndexOf(".")); 126 | if (StringUtils.isNotBlank(className)) { 127 | className = packageName + "." + className; 128 | } 129 | //类加载 130 | doAddClass(classSet, className); 131 | }); 132 | 133 | Arrays.asList(files).stream() 134 | .filter(file -> !file.isFile()) 135 | .forEach(file -> { 136 | String fileName = file.getName(); 137 | String subPackagePath = fileName; 138 | if (StringUtils.isNotBlank(packagePath)) { 139 | //补全当前路径 140 | subPackagePath = packagePath + "/" + subPackagePath; 141 | } 142 | String subPackageName = fileName; 143 | if (StringUtils.isNotBlank(packageName)) { 144 | subPackageName = packageName + "." + subPackageName; 145 | } 146 | //递归遍历文件夹下的目录 147 | addClass(classSet, subPackagePath, subPackageName); 148 | }); 149 | */ 150 | 151 | Arrays.asList(files).forEach( 152 | file -> { 153 | String fileName = file.getName(); 154 | if (file.isFile()) { 155 | //取出.class之前的类名 156 | String className = fileName.substring(0, fileName.lastIndexOf(".")); 157 | if (StringUtils.isNotBlank(className)) { 158 | className = packageName + "." + className; 159 | } 160 | //类加载 161 | doAddClass(classSet, className); 162 | } else { 163 | //目录 164 | String subPackagePath = fileName; 165 | if (StringUtils.isNotBlank(packagePath)) { 166 | //补全当前路径 167 | subPackagePath = packagePath + "/" + subPackagePath; 168 | } 169 | String subPackageName = fileName; 170 | if (StringUtils.isNotBlank(packageName)) { 171 | subPackageName = packageName + "." + subPackageName; 172 | } 173 | //递归遍历文件夹下的目录 174 | addClass(classSet, subPackagePath, subPackageName); 175 | } 176 | } 177 | ); 178 | 179 | 180 | } 181 | 182 | /** 183 | * 添加类到类集合 184 | * 185 | * @param classSet 186 | * @param className 187 | */ 188 | private static void doAddClass(Set> classSet, String className) { 189 | Class cls = loadClass(className, false); 190 | classSet.add(cls); 191 | } 192 | 193 | 194 | } 195 | -------------------------------------------------------------------------------- /zebra4j/zebra-boot/src/test/java/com58/zhl/concurrent/Cptt11_Nonblocking.java: -------------------------------------------------------------------------------- 1 | package com58.zhl.concurrent; 2 | 3 | import java.util.ArrayList; 4 | import java.util.HashSet; 5 | import java.util.List; 6 | import java.util.Set; 7 | import java.util.concurrent.Callable; 8 | import java.util.concurrent.CountDownLatch; 9 | import java.util.concurrent.ExecutionException; 10 | import java.util.concurrent.ExecutorService; 11 | import java.util.concurrent.Executors; 12 | import java.util.concurrent.Future; 13 | import java.util.concurrent.atomic.AtomicReference; 14 | 15 | /** 16 | * 非阻塞算法实现 17 | * @author 58_zhl 18 | * 19 | */ 20 | public class Cptt11_Nonblocking { 21 | 22 | private static int concurrentCount=10; //准备并发的数量 23 | 24 | /** 25 | * 队列基础接口 26 | * @author 58_zhl 27 | * @param 28 | */ 29 | static interface MyLinkedInterface{ 30 | /** 31 | * 添加元素到列表中 32 | * @param element 33 | */ 34 | public void add(T element); 35 | /** 36 | * 显示所有元素 37 | */ 38 | public void displayElement(); 39 | } 40 | 41 | /** 42 | * 链表节点 43 | * @author 58_zhl 44 | * @param 45 | */ 46 | private static class Node{ 47 | T element; 48 | Node next=null; 49 | 50 | Node(T element,Node next){ 51 | this.element=element; 52 | this.next=next; 53 | } 54 | } 55 | 56 | /** 57 | * 非线程安全的链表 58 | * @author 58_zhl 59 | */ 60 | static class MyLinked_1 implements MyLinkedInterface{ 61 | private Node head=new Node(null,null); //链表头 62 | private Node last=head; //尾节点 63 | 64 | public void add(T element) { 65 | Node addNode=new Node(element,null); //新增节点 66 | last.next=addNode; //将addNode添加到尾节点 67 | // try { 68 | // Thread.sleep(20); //这句是为了增大并发冲突的概率 69 | // } catch (InterruptedException e) { } 70 | last=addNode; //更新尾节点 71 | } 72 | 73 | public void displayElement() { 74 | Node current=head.next; 75 | StringBuilder sb=new StringBuilder(); 76 | int count=0; 77 | while(current!=null){ 78 | T temp=current.element; 79 | sb.append(temp.toString()+" "); 80 | current=current.next; 81 | count++; 82 | } 83 | System.out.println(sb.toString()); 84 | System.out.println("共"+count+"元素"); 85 | } 86 | } 87 | 88 | /** 89 | * 同步的线程安全的链表 90 | * @author 58_zhl 91 | */ 92 | static class MyLinked_2 extends MyLinked_1 implements 93 | MyLinkedInterface { 94 | @Override 95 | public synchronized void add(T element) { 96 | super.add(element); 97 | } 98 | } 99 | 100 | /** 101 | * 非阻塞线程安全的链表 102 | * @author 58_zhl 103 | */ 104 | static class MyLinked_3 implements MyLinkedInterface{ 105 | /** 106 | * 默认头节点 107 | */ 108 | private final AtomicReference> head 109 | =new AtomicReference>(new Node(null,null)); 110 | 111 | /** 112 | * 尾节点,默认和头结点指向同一个Node 113 | * 注:AtomicReference使用是用于维护对某类型变量操作时原子化,而不是AtomicReference 114 | * 封装后的对象,可以进行原子化。因此,这里把head、last变量都设置为final类型的,仅能 115 | * 赋值一次,之后所有的操作对赋值的改变都是对AtomicReference维护的内部变量进行的。 116 | */ 117 | private final AtomicReference> last 118 | =new AtomicReference>(head.get()); 119 | 120 | public void add(T element) { 121 | Node newNode=new Node(element,null); 122 | while(true){ 123 | Node currentLast=last.get(); //获取最新的尾节点 124 | Node lastNext=currentLast.next.get(); //获取尾节点的下一个节点,用于做参照值 125 | if(currentLast==last.get()){ //判断在执行上面两句的时候,尾节点有没有发生变化,如果有,则可能需要重新获取到lastNext的值 126 | if(lastNext!=null){ //如果lastNext不等于null,则说明该链表处于中间状态,因为正常情况下,lastNext一定是null的 127 | //如果不处于中间状态,则推进节点,即帮助其它线程完成剩余操作 128 | /** 129 | * 正常情况下,更新分两步: 130 | * last.next=newNode; //进入此if语句,则说明,完成了这一步,在下一步时未完成 131 | * last=newNode; 132 | */ 133 | last.compareAndSet(currentLast, lastNext); //并发中,这句也不见得会成功,因为可能并发时又有新的节点被添加了 134 | //上面只是帮助其它线程推进了节点,但是还要通过下次循环,把自己持有的新节点添加进链表 135 | }else{ 136 | //如果链表处于稳定状态,稳定状态时,需要通过执行下面两步来完成节点添加 137 | /** 138 | * if中执行后的效果类似 139 | * last.next=newNode; 140 | */ 141 | if(currentLast.next.compareAndSet(null, newNode)){ //尝试将最新的节点添加到尾列表,这里认为之前的next是null,并且现在希望next是newNode 142 | // try { 143 | // Thread.sleep(20); //这里可以同样为了增大并发冲突的概率 144 | // } catch (InterruptedException e) { } 145 | /** 146 | * 这句执行后的操作类似于 147 | * last=newNode; 148 | */ 149 | last.compareAndSet(currentLast, newNode); 150 | return; //添加节点成功后跳出循环 151 | } 152 | } 153 | } 154 | } 155 | } 156 | 157 | public void displayElement() { 158 | if(head.get().next!=null){ 159 | Node current=head.get().next.get(); 160 | StringBuilder sb=new StringBuilder(); 161 | int count=0; 162 | Set hasSet=new HashSet(); 163 | while(current!=null){ 164 | T element=current.item; 165 | sb.append(element).append(" "); 166 | hasSet.add(element); 167 | count++; 168 | current=current.next.get(); 169 | } 170 | System.out.println(sb.toString()); 171 | System.out.println("共"+count+"元素,hasSet排重后"+hasSet.size()); 172 | } 173 | } 174 | 175 | private static class Node{ 176 | T item; 177 | AtomicReference> next; 178 | private Node(T item,Node next){ 179 | this.item=item; 180 | this.next=new AtomicReference>(next); 181 | } 182 | } 183 | } 184 | 185 | 186 | public static void testLinked(final MyLinkedInterface linked){ 187 | for(int i=0;i<10;i++){ //首先,单线程添加是个元素,测试链表的可用性 188 | linked.add(i); 189 | } 190 | linked.displayElement(); 191 | //下面开始并发 192 | final CountDownLatch latch=new CountDownLatch(concurrentCount); 193 | ExecutorService es=Executors.newCachedThreadPool(); 194 | List> list=new ArrayList>(); 195 | for(int i=10;i(){ 198 | 199 | public Long call() throws Exception { 200 | latch.countDown(); 201 | latch.await(); 202 | long start=System.nanoTime(); 203 | linked.add(idx); 204 | long end=System.nanoTime(); 205 | return (end-start); 206 | } 207 | }); 208 | } 209 | try { 210 | List> result=es.invokeAll(list); 211 | System.out.println("请求"+list.size()+"次并发..."); 212 | long countTime=0; 213 | int executeCount=0; 214 | for(Future r:result){ 215 | countTime+=r.get(); 216 | executeCount++; 217 | } 218 | System.out.println("并发"+executeCount+"次访问,全部返回..."); 219 | System.out.println("并发添加完所有元素的时间:"+countTime+"ns"); 220 | linked.displayElement(); 221 | es.shutdown(); 222 | } catch (InterruptedException e) { 223 | 224 | }catch (ExecutionException e) { 225 | 226 | } 227 | 228 | } 229 | 230 | public static void main(String args[]){ 231 | // testLinked(new MyLinked_1()); //非线程安全的链表 232 | System.out.println("-----------------------------------------------------------"); 233 | // testLinked(new MyLinked_2()); //线程安全的链表 234 | System.out.println("-----------------------------------------------------------"); 235 | testLinked(new MyLinked_3()); //非阻塞的链表 236 | } 237 | 238 | } 239 | -------------------------------------------------------------------------------- /zebra4j/zebra-boot/src/test/java/com58/zhl/concurrent/Cpt5_LoadTest.java: -------------------------------------------------------------------------------- 1 | package com58.zhl.concurrent; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.concurrent.Callable; 6 | import java.util.concurrent.CountDownLatch; 7 | import java.util.concurrent.ExecutionException; 8 | import java.util.concurrent.ExecutorService; 9 | import java.util.concurrent.Executors; 10 | import java.util.concurrent.Future; 11 | import java.util.concurrent.Semaphore; 12 | import java.util.concurrent.atomic.AtomicInteger; 13 | 14 | import com58.zhl.util.Operator; 15 | 16 | /** 17 | * 通过模拟压力测试,来介绍线程池、协调多线程工作的闩、原子变量等类的实现,并 18 | * 初步介绍各个类的作用,特性。 19 | * @author 58_zhl 20 | * 21 | */ 22 | public class Cpt5_LoadTest { 23 | 24 | /** 25 | * 聚集并发的聚集数量 26 | */ 27 | private static final int GATHER_COUNT=100; 28 | 29 | /** 30 | * 疲劳测试的最大并发数 31 | */ 32 | private static final int MAX_CONCURRENT=50; // 33 | 34 | /** 35 | * 疲劳测试的时间,毫秒 36 | */ 37 | private static final int TIRED_TIME=20*1000; 38 | 39 | 40 | public interface TestInterface{ 41 | /** 42 | * 开始执行测试 43 | */ 44 | public void startTest(); 45 | 46 | /** 47 | * 获取监控线程,用于监视,因为每个测试场景的实现内部维护的状态都不相同 48 | * 为了方便起见,直接返回Thread来打印结果,而没有单独抽象出内部状态集合 49 | * 接口 50 | * @return 51 | */ 52 | public Thread getMonitorThread(); 53 | 54 | } 55 | 56 | public static class GatherTest implements TestInterface{ 57 | private CountDownLatch latch=new CountDownLatch(GATHER_COUNT); //闩,用于等待其他线程 58 | private final List procedureList=new ArrayList(); //引用维护集合 59 | private AtomicInteger readyCount=new AtomicInteger(0); //已到达闩位置的线程数量i++ 60 | private int flag=1; //状态,1为准备中,2为开始执行 61 | private int successRequest=0; //请求成功数量统计 62 | private int sucessProcess=0; //请求成功后,正确处理的统计数量,真是环境中可能会拿具体结果集来对返回结果进行比对 63 | private int failCount=0; //请求失败数 64 | 65 | public void startTest(){ 66 | for(int i=0;i> list; 70 | try { 71 | ExecutorService es=Executors.newCachedThreadPool(); 72 | list = es.invokeAll(procedureList); 73 | flag=2; //将状态处于执行中,已经可以进行执行结果输出了 74 | System.out.println("已提交任务组....."); 75 | for(Future rq:list){ 76 | try { 77 | CallBean result=rq.get(); //因为这里是主线程,所以如果循环到这里没有执行完结果,那么就处于等待状态,一直到该线程执行完,才会继续遍历。 78 | // System.out.println(result.threadName+"取值完毕..."); //调试用 79 | if(result.result==1){ 80 | successRequest++; //统计成功数 81 | Operator.process(); //模拟处理结果 82 | sucessProcess++; //统计正确请求数 83 | }else{ 84 | failCount++; //统计失败数 85 | } 86 | } catch (ExecutionException e) { 87 | System.out.println("startTest 执行异常...."); 88 | } 89 | } 90 | flag=3; //退出监控循环 91 | es.shutdown(); //一定要执行这一句才会立刻退出,newCachedThreadPool会缓存一部分线程在 92 | //池中,以备在指定时间内还有新线程使用该连接池,只有执行了该方法才会清除 93 | //线程池内的缓存线程实体。 94 | } catch (InterruptedException e) { 95 | System.out.println(" startTest 请求中断...."); 96 | } 97 | } 98 | 99 | private class Procedure implements Callable{ 100 | @Override 101 | public CallBean call() throws Exception { 102 | //因为是聚集之后,统一并发,因此readyCount++操作可能会存在竞争 103 | GatherTest.this.readyCount.getAndIncrement(); //统计准备好的数量 104 | Operator.randomSleep(); //可能是登陆,或者到达指定页面准备好做某一个测试点的过程 105 | CallBean callBean=new CallBean(); 106 | callBean.threadName=Thread.currentThread().getName(); 107 | System.out.println(Thread.currentThread().getName()+"等待中..."); 108 | GatherTest.this.latch.countDown(); //准备好以后将线程数量减一 109 | GatherTest.this.latch.await(); //等待其它线程 110 | callBean.result=Operator.request()?1:2; //模拟请求 111 | return callBean; 112 | } 113 | } 114 | 115 | private class CallBean{ 116 | int result; 117 | String threadName; 118 | } 119 | 120 | @Override 121 | public Thread getMonitorThread() { 122 | return new Thread(){ 123 | public void run(){ 124 | while(true){ 125 | boolean b=false; 126 | switch(GatherTest.this.flag){ 127 | case 1: //准备状态 128 | System.out.println("聚集总数:" + Cpt5_LoadTest.GATHER_COUNT 129 | + " 已就绪:" + GatherTest.this.readyCount); 130 | break; 131 | case 2: // 执行状态 132 | System.out.println("成功请求数:" 133 | + GatherTest.this.successRequest 134 | + " 成功处理数:" 135 | + GatherTest.this.sucessProcess 136 | + " 失败总数:" + GatherTest.this.failCount); 137 | break; 138 | case 3: //执行结束 139 | b=true; 140 | System.out.println("成功请求数:" 141 | + GatherTest.this.successRequest 142 | + " 成功处理数:" 143 | + GatherTest.this.sucessProcess 144 | + " 失败总数:" + GatherTest.this.failCount); 145 | System.out.println("执行结束....."); 146 | break; 147 | default:break; 148 | } 149 | if(b) break; //如果执行结束,退出循环 150 | try { 151 | Thread.sleep(300); //有准备就绪的打印结果 152 | } catch (InterruptedException e) { 153 | System.out.println("monitor 请求中断...."); 154 | break; //必须处理中断 155 | } 156 | } 157 | } 158 | }; 159 | } 160 | } 161 | 162 | public static class TiredTest implements TestInterface{ 163 | 164 | /** 165 | * 注意:为什么下面不适用volatile int 而是用AtomicInteger,是因为即使是volatile 166 | * 变量,也不能保证 n++这个操作是原子化的。java中,除了锁机制以外,只能通过AtomicInteger 167 | * 来实现原子化递增。 168 | */ 169 | 170 | private AtomicInteger requestCount=new AtomicInteger(0); //请求总数量 171 | 172 | private AtomicInteger successRequestCount=new AtomicInteger(0); //成功数量 173 | 174 | private AtomicInteger successProcessCount=new AtomicInteger(0); //成功处理数量 175 | 176 | private AtomicInteger currentExecuteCount=new AtomicInteger(0); //当前正在执行的线程数 177 | 178 | private AtomicInteger interruptedCount=new AtomicInteger(0); //中断线程数 179 | 180 | private int executeFlag=0; //执行状态 181 | 182 | private Semaphore semaphore=new Semaphore(Cpt5_LoadTest.MAX_CONCURRENT); //信号量,用于协调生产者与消费者的工作 183 | 184 | @Override 185 | public void startTest() { 186 | final ExecutorService esPool=Executors.newCachedThreadPool(); 187 | Thread procedure=new Thread(){ 188 | public void run(){ 189 | while(true){ 190 | try{ 191 | TiredTest.this.semaphore.acquire(); //获取许可后才可以生产并提交到线程池中执行 192 | ProcedureUnit pUnit=new ProcedureUnit(); 193 | synchronized(esPool){ 194 | if(!esPool.isShutdown()){ //这里必须判断后提交任务,否则会出现RejectedExecutionException 195 | //因为有可能在执行shutdownNow后,正好执行到new ProcedureUnit() 196 | //这一句,而这一句是不能响应中断的 197 | esPool.submit(pUnit); //提交执行 198 | } 199 | } 200 | }catch(InterruptedException e){ 201 | System.out.println("生产者线程已停止...."); 202 | break; 203 | } 204 | } 205 | } 206 | }; 207 | procedure.start(); 208 | try { 209 | Thread.sleep(Cpt5_LoadTest.TIRED_TIME); 210 | procedure.interrupt(); //生产者停止 211 | synchronized(esPool){ 212 | esPool.shutdownNow(); //立刻停止,只有该方法才能发出interruptedException中断 213 | } 214 | executeFlag=2; //状态置为已结束 215 | } catch (InterruptedException e) { 216 | System.out.println("startTest 请求中断...."); 217 | } 218 | } 219 | 220 | private class ProcedureUnit implements Callable{ 221 | 222 | /** 223 | * 注意该方法的递增TiredTest类统计变量的位置,如果位置不对,很可能导致 224 | * 统计不准确, 225 | */ 226 | @Override 227 | public Integer call() throws Exception { //生产单元 228 | try{ 229 | TiredTest.this.currentExecuteCount.getAndIncrement(); //当前正在执行的线程数 230 | boolean result=Operator.request2(); //请求某个页面 231 | TiredTest.this.requestCount.getAndIncrement(); //如果请求完成,则进行请求总数的统计 232 | if(result){ //如果请求成功了 233 | TiredTest.this.successRequestCount.getAndIncrement(); //统计正确响应数 234 | Operator.process2(); //如果这里产生中断,则不统计到successProcessCount 235 | TiredTest.this.successProcessCount.getAndIncrement(); //成功处理数 236 | return 1; 237 | } 238 | }catch(InterruptedException e){ //这里捕获的是请求异常 239 | //这里捕获异常,则说明是本地中断请求产生的异常,不应该进行总数统计 240 | TiredTest.this.interruptedCount.getAndIncrement(); //中断数量 241 | }finally{ 242 | TiredTest.this.currentExecuteCount.getAndDecrement(); //不论何种情况发生异常,当前线程都要结束执行 243 | TiredTest.this.semaphore.release(); //一定要释放许可,否则将导致生产者的生产 244 | } 245 | return null; 246 | } 247 | } 248 | 249 | 250 | @Override 251 | public Thread getMonitorThread() { 252 | return new Thread(){ 253 | public void run() { 254 | while (true) { 255 | StringBuilder sb=new StringBuilder(); 256 | sb.append("请求总数:").append(TiredTest.this.requestCount).append("\t"); 257 | sb.append("成功响应:").append(TiredTest.this.successRequestCount).append("\t"); 258 | sb.append("处理成功:").append(TiredTest.this.successProcessCount).append("\t"); 259 | sb.append("正在执行线程数:").append(TiredTest.this.currentExecuteCount).append("\t"); 260 | sb.append("中断线程数:").append(TiredTest.this.interruptedCount).append("\t"); 261 | System.out.println(sb.toString()); 262 | if(executeFlag==2){ 263 | break; 264 | } 265 | try { 266 | Thread.sleep(300); // 有准备就绪的打印结果 267 | } catch (InterruptedException e) { 268 | System.out.println("monitor 请求中断...."); 269 | break; // 必须处理中断 270 | } 271 | } 272 | } 273 | }; 274 | } 275 | 276 | } 277 | 278 | public static void test(final TestInterface test){ 279 | //----------------------可以基于testInterface抽象出一系列的行为--------------------------------- 280 | Thread t=new Thread(){ 281 | public void run(){ 282 | test.startTest(); 283 | } 284 | }; 285 | t.start(); 286 | test.getMonitorThread().start(); 287 | System.out.println("监控启动.."); 288 | //暂时只抽象出两个方法,用来演示,应该有更多的操作被分离实现更详细的统计及后续行为 289 | //----------------------可以基于testInterface抽象出一系列的行为--------------------------------- 290 | } 291 | 292 | public static void main(String args[]){ 293 | // test(new GatherTest()); //聚集 294 | 295 | test(new TiredTest()); //疲劳测试 296 | } 297 | 298 | } 299 | -------------------------------------------------------------------------------- /maven-repo-settings-ali.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 21 | 22 | 46 | 49 | 55 | D:\Repositories\Maven 56 | 57 | 65 | 66 | 73 | 74 | 79 | 80 | 84 | org.mortbay.jetty 85 | 86 | 87 | 92 | 93 | 107 | 108 | 109 | 113 | 114 | 127 | 128 | 135 | 136 | releases 137 | ali 138 | ali 139 | 140 | 141 | Snapshots 142 | ali 143 | ali 144 | 145 | 146 | 147 | 158 | 159 | 171 | 172 | 173 | nexus 174 | * 175 | http://maven.aliyun.com/nexus/content/groups/public/ 176 | 177 | 178 | 180 | nexus-public-snapshots 181 | public-snapshots 182 | http://maven.aliyun.com/nexus/content/repositories/snapshots/ 183 | 184 | 185 | 186 | 207 | 208 | 209 | development 210 | 211 | 212 | central 213 | http://central 214 | truealways 215 | truealways 216 | 217 | 218 | 219 | 220 | central 221 | http://central 222 | truealways 223 | truealways 224 | 225 | 226 | 227 | 228 | 229 | public-snapshots 230 | 231 | 232 | public-snapshots 233 | http://public-snapshots 234 | false 235 | truealways 236 | 237 | 238 | 239 | 240 | public-snapshots 241 | http://public-snapshots 242 | false 243 | truealways 244 | 245 | 246 | 247 | 248 | 249 | 250 | development 251 | public-snapshots 252 | 253 | 254 | -------------------------------------------------------------------------------- /zebra4j/zebra-boot/src/test/java/com58/zhl/concurrent/Cpt8_TimeoutManager.java: -------------------------------------------------------------------------------- 1 | package com58.zhl.concurrent; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Iterator; 5 | import java.util.List; 6 | import java.util.Random; 7 | import java.util.concurrent.DelayQueue; 8 | import java.util.concurrent.Delayed; 9 | import java.util.concurrent.TimeUnit; 10 | import java.util.concurrent.atomic.AtomicInteger; 11 | import java.util.concurrent.atomic.AtomicLong; 12 | 13 | /** 14 | * 基于DelayQueue实现一个超时管理 15 | * @author 58_zhl 16 | * 17 | */ 18 | public class Cpt8_TimeoutManager { 19 | 20 | private static List result=new ArrayList(); 21 | 22 | /** 23 | * 遍历队列以便观察结果 24 | * @param queue 25 | */ 26 | private static String iteratorDelayQueue(DelayQueue queue){ 27 | Iterator it=queue.iterator(); 28 | StringBuilder sb=new StringBuilder(); 29 | while(it.hasNext()){ 30 | Session dt=it.next(); 31 | sb.append(dt.toString()+"\n"); 32 | } 33 | return sb.toString(); 34 | } 35 | 36 | 37 | public static void testDelayQueue(){ 38 | DelayQueue queue=new DelayQueue(); 39 | Random random=new Random(47); 40 | StringBuilder sb=new StringBuilder(); 41 | List list=new ArrayList(); 42 | //生产对象添加到队列中 43 | for(int i=0;i<5;i++){ 44 | long timeout=(random.nextInt(10)+1)*1000; //11以内的整数乘以1000毫秒 45 | Session temp=new Session(timeout); 46 | sb.append("id:"+temp.id+"-").append(timeout).append(" "); 47 | list.add(temp); 48 | queue.offer(temp); 49 | } 50 | System.out.println("=========================添加到队列中的顺序========================="); 51 | System.out.println(sb.toString()); 52 | //可以先观察queue的排序结果 53 | System.out.println("=========================队列中实际的顺序========================"); 54 | System.out.println(iteratorDelayQueue(queue)); 55 | System.out.println("=========================启动清理线程=============================="); 56 | monitorThread(queue); //启动监控清理线程 57 | //可先不执行延迟清理,进行观察 58 | updateObject(list,queue); //模拟因session最新被调用,而延迟清理 59 | } 60 | 61 | public static void monitorThread(final DelayQueue queue){ 62 | Thread thread=new Thread(){ 63 | public void run(){ 64 | while(!queue.isEmpty()){ 65 | try { 66 | Session dt=queue.take(); 67 | String str=dt.toString2()+"=====已被清理"+"\t currentTime:"+System.currentTimeMillis(); 68 | System.out.println(str); 69 | result.add(str); 70 | result.add(iteratorDelayQueue(queue)); //每次清理之后,都要保存一下队列的快照 71 | } catch (InterruptedException e) { System.out.println("清理中断...."); return; } 72 | } 73 | System.out.println("清理完所有缓存!!!!!"); 74 | 75 | System.out.println("======================延迟对象生命周期运行时queue的快照========================"); 76 | for(String tstr:result){ 77 | System.out.println(tstr); 78 | } 79 | System.out.println("=============================================="); 80 | } 81 | }; 82 | thread.start(); 83 | } 84 | 85 | /** 86 | * 模拟在清理session池的时候,session因重新调用而导致清理时间延迟 87 | * @param list 88 | */ 89 | public static void updateObject(final List list,final DelayQueue queue){ 90 | Thread thread=new Thread(){ 91 | public void run(){ 92 | try { 93 | //对于iteratorDelayQueue可能存在同步的问题,但是这里因sleep时间点的问题,不会发生异常 94 | //暂时不需要处理 95 | Thread.sleep(1000); //睡眠1000ms 96 | //list(4)默认生命周期是2000ms,睡眠1000后,现在应该还有1000ms左右 97 | list.get(4).updateTriger(); 98 | result.add("id:"+list.get(4).id+" 寿命延长\t currentTime:"+System.currentTimeMillis()); 99 | Thread.sleep(1000); //再次睡眠1000ms 100 | //再次延长list(4),这次延时后list(4)的总生命周期应该是4000ms 101 | list.get(4).updateTriger(); 102 | result.add("id:"+list.get(4).id+" 寿命延长\t currentTime:"+System.currentTimeMillis()); 103 | //执行到此处时,一共睡眠了2000ms,list(1)的初始生命是6000ms,此时延迟应该总共生命周期为8000ms 104 | list.get(1).updateTriger(); 105 | result.add("id:"+list.get(2).id+" 寿命延长\t currentTime:"+System.currentTimeMillis()); 106 | } catch (InterruptedException e) { } 107 | } 108 | }; 109 | thread.start(); 110 | } 111 | 112 | /** 113 | * 超时对象封装 114 | * @author 58_zhl 115 | * 116 | */ 117 | static class Session implements Delayed{ 118 | /** 119 | * 用于生成ID 120 | */ 121 | private static AtomicInteger objectId=new AtomicInteger(0); 122 | /** 123 | * 本对象的ID 124 | */ 125 | private int id=objectId.incrementAndGet(); //注意与getAndIncrement方法的区别 126 | /** 127 | * 到期时间 128 | */ 129 | private AtomicLong triger=null; 130 | /** 131 | * 创建时间 132 | */ 133 | private long createTime=System.nanoTime(); 134 | /** 135 | * 该对象被更新的次数 136 | */ 137 | private AtomicInteger count=new AtomicInteger(0); 138 | /** 139 | * 该对象的超时时间,对象存在的生命周期 140 | */ 141 | private final long timeout; 142 | 143 | public Session(long timeout){ 144 | this.timeout=TimeUnit.NANOSECONDS.convert(timeout, TimeUnit.MILLISECONDS); //保存对象 145 | this.triger=new AtomicLong(createTime+this.timeout); //对象的到期时间 146 | } 147 | 148 | /** 149 | * 更新超时时间,每使用某个对象时,应该调用此方法, 150 | * 来延长对象在内存的生命周期 151 | */ 152 | public void updateTriger(){ 153 | /* 154 | * 统计被更新的次数,在对象创建后,因再次使用导致对象的生命周期延长的次数 155 | */ 156 | count.getAndIncrement(); 157 | long oldValue=0; //获取当前值 158 | long newValue=0; 159 | do{ 160 | oldValue=triger.get(); 161 | newValue=System.nanoTime()+timeout; 162 | }while(!triger.weakCompareAndSet(oldValue, newValue)); 163 | } 164 | 165 | /** 166 | * 对比方法,按照从大到小的顺序 167 | * 在offer的时候只调用compareTo方法 168 | */ 169 | @Override 170 | public int compareTo(Delayed o) { 171 | Session dt=(Session)o; 172 | System.out.println("compareTo()方法被调用....id:"+id+"\t currentTime:"+System.currentTimeMillis()); 173 | return (this.triger.get()>dt.triger.get()?1:(this.triger.get() 2 | 3 | 4 | Not Found - ThinkJS 5 | 21 | 22 | 23 |

24 |
25 | 26 | 29 |
30 |
31 |
32 |
33 |

Not Found

34 |
ERROR_MESSAGE
35 |
36 | 37 | 38 | -------------------------------------------------------------------------------- /zebra4js/view/common/error_400.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Bad Request - ThinkJS 5 | 21 | 22 | 23 |
24 |
25 | 26 | 29 |
30 |
31 |
32 |
33 |

Bad Request

34 |
ERROR_MESSAGE
35 |
36 | 37 | 38 | --------------------------------------------------------------------------------