package com.hengyu.ticket.common; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Collections; import java.util.List; /** * Created by lgf on 2016/4/3. * 使用多台数据库服务区器负载 */ public class CommonLoadBalancing { private static final String SERVER_CONFIG = "SERVER.JSON"; public static String DB_DRIVER; public static String DB_PORT; public static String DB_USER_NAME; public static String DB_PASSWORD; public static String DB_URL; //选择服务器类型(线程安全) private static final ThreadLocal<String> SERVER_HOLDER = new ThreadLocal<>(); //服务器类型 private final static String SERVER_MASTER = "MASTER"; private final static String SERVER_SLAVE = "SLAVE"; //当前服务器的编号 private static Integer CURRENT_INDEX = -1; //当前权重 private static Integer CURRENT_WEIGHT = 0; //最大权重 private static Integer MAX_WEIGHT = 0; //权重公约数 private static Integer GCD_WEIGHT = 1; //最小公约数 private static Integer MIN_WEIGHT = 1; //主服务器 private static Server MASTER; //备用主服务器 private static Server MASTER_RESERVED; //服务器集合 public static final List<Server> servers = Collections.synchronizedList(new ArrayList<Server>()); //脱机服务器集合 private static final List<Server> down_servers = Collections.synchronizedList(new ArrayList<Server>()); static { DBConfig.init(); } //获取主服务器,备用主服务器 public static Server getMaster() { if (MASTER.isDown()) { if (MASTER_RESERVED != null && !MASTER_RESERVED.isDown()) { return MASTER_RESERVED; } else { throw new RuntimeException("error:tow master is down!"); } } return MASTER; } public static void setMaster(Server master) { CommonLoadBalancing.MASTER = master; } //添加服务器 public static void addServer(Server server) { addServer(server, false); } //添加服务器 public static void addServer(Server server, boolean isReload) { if (server == null) { throw new RuntimeException("error: server cant't not be null !"); } int index = servers.size(); if (server.getType() != null && SERVER_MASTER.equals(server.getType())) { MASTER = server; } else if (server.getType() == null) { server.setType(SERVER_SLAVE); } servers.add(server); if (isReload) { initOrReload(); } } //添加服务器 public static void addServer(List<Server> servers) { for (int i = 0; i < servers.size(); i++) { Server server = servers.get(i); addServer(server); } CommonLoadBalancing.initOrReload(); } //查找权重,计算权重公约数 public synchronized static void initOrReload() { for (Server server : servers) { if (server == null || server.isDown()) { continue; } if (server.getWeight() > MAX_WEIGHT) { MAX_WEIGHT = server.getWeight(); } if (server.getWeight() < MIN_WEIGHT) { MIN_WEIGHT = server.getWeight(); } } if (MASTER == null) { MASTER = servers.get(0); MASTER.setType(SERVER_MASTER); } GCD_WEIGHT = gcd(servers); } //获取权重公因数 public static int gcd(List<Server> servers) { if (servers == null || servers.size() == 0) { return 1; } int min = servers.get(0).getWeight(); for (int i = 0; i < servers.size(); i++) { Server server = servers.get(i); if (server.getWeight() < min) { min = server.getWeight(); } } while (min >= 1) { boolean isCommon = true; for (int i = 0; i < servers.size(); i++) { Server server = servers.get(i); if (server.getWeight() % min != 0) { isCommon = false; break; } } if (isCommon) { break; } min--; } return min<1?1:min; } //轮询服务器 public static Server getServer() { int count = 0; int size = servers.size(); if (size == 0 || getServerType().equals(SERVER_MASTER)) { return getMaster().addAccessCount(); } clearServerHolder(); while (true) { CURRENT_INDEX = (CURRENT_INDEX + 1) % size; if (CURRENT_INDEX == 0) { CURRENT_WEIGHT = CURRENT_WEIGHT - GCD_WEIGHT; if (CURRENT_WEIGHT <= 0) { CURRENT_WEIGHT = MAX_WEIGHT; } } Server server = servers.get(CURRENT_INDEX); if (server != null && server.getWeight() >= CURRENT_WEIGHT && !server.isDown) { return server.addAccessCount(); } if (count >= size) { return getMaster().addAccessCount(); } count++; } } public static List<Server> getServers() { return servers; } public static void setMasterReserved(Server masterReserved) { CommonLoadBalancing.MASTER_RESERVED = masterReserved; } public static List<Server> getDown_servers() { return down_servers; } public static void setServerType(boolean isReadOnly) { if (isReadOnly) { SERVER_HOLDER.set(SERVER_SLAVE); } else { SERVER_HOLDER.set(SERVER_MASTER); } } public static void clearServerHolder() { SERVER_HOLDER.set(SERVER_SLAVE); } public static String getServerType() { String type = SERVER_HOLDER.get(); if (type == null || type.equals(SERVER_SLAVE)) { return SERVER_SLAVE; } return SERVER_MASTER; } public static class Server { //服务器编号 private String id; //服务器索引 private Integer index; ///服务器ip private String ip; //权重 private int weight; //类型,主从 private String type; //用户名 private String username; //密码 private String password; //端口 private String port; //url链接 private String url; //访问数量 private Integer accessCount = 0; //是否脱机 private boolean isDown; public Server() { } @Override public String toString() { return "Server{type='" + type + '\'' + ", ip='" + ip + '\'' + ", weight=" + weight + ", accessCount=" + accessCount + '}'; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getPort() { return port; } public void setPort(String port) { this.port = port; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } public Integer getIndex() { return index; } public void setIndex(Integer index) { this.index = index; } public Server(String ip, int weight) { this.ip = ip; this.weight = weight; } public int getAccessCount() { return accessCount; } public void setAccessCount(int accessCount) { this.accessCount = accessCount; } public Server addAccessCount() { synchronized (this.accessCount) { this.accessCount++; return this; } } public String getType() { return type; } public void setType(String type) { this.type = type; } public String getId() { return id; } public void setId(String id) { this.id = id; } public String getIp() { return ip; } public void setIp(String ip) { this.ip = ip; } public int getWeight() { if (weight < 1) { weight = 1; } return weight; } public void setWeight(int weight) { if (weight < 1) { weight = 1; } this.weight = weight; } public boolean isDown() { return isDown; } public void setDown(boolean down) { isDown = down; } } //数据库配置 public static class DBConfig { /* * { "username": "root", "password": "admin", "port": "3306", "driver": "com.mysql.jdbc.Driver" * , "url": "jdbc:mysql://${host}:${prot}/ticket?characterEncoding=utf8", "master": [ "127.0.0.1" ], * "slave": [ "192.168.0.10 -w100", "192.168.0.11 -w50" ] } * * */ //初始化 public static void init() { InputStream in = null; try { in = Thread.currentThread().getContextClassLoader().getResourceAsStream(SERVER_CONFIG); if (in == null) { throw new RuntimeException("error:" + SERVER_CONFIG + " cat't not be null"); } byte[] bs = new byte[in.available()]; in.read(bs); JSONObject base = JSON.parseObject(new String(bs)); DB_USER_NAME = base.get("username") == null ? "" : base.get("username").toString(); DB_PASSWORD = base.get("password") == null ? "" : base.get("password").toString(); DB_URL = base.get("url") == null ? "" : base.get("url").toString(); DB_DRIVER = base.get("driver") == null ? "" : base.get("driver").toString(); DB_PORT = base.get("port") == null ? "" : base.get("port").toString(); List<String> masters = JSON.parseArray(base.get("master").toString(), String.class); List<String> slaves = null; if (base.get("slave") != null) { slaves = JSON.parseArray(base.get("slave").toString(), String.class); } createServer(masters, slaves); } catch (IOException e) { e.printStackTrace(); } finally { try { if (in != null) { in.close(); } } catch (IOException e) { } } } //创建服务器 public synchronized static void createServer(List<String> masters, List<String> slave) { List<Server> servers = new ArrayList<>(); int i = 0; if (masters != null) { //主服务器 for (String info : masters) { Server server = new Server(); server.setId(String.valueOf(i)); createServer(SERVER_MASTER, server, info); server.setIndex(servers.size()); servers.add(server); CommonLoadBalancing.MASTER = server; if (i == 1) { CommonLoadBalancing.MASTER_RESERVED = server; } i++; } } //从服务器 if (slave != null) { for (String info : slave) { Server sa = new Server(); sa.setId(String.valueOf(i)); createServer(SERVER_SLAVE, sa, info); sa.setIndex(i); servers.add(sa); i++; } } CommonLoadBalancing.addServer(servers); } //创建服务器 public static void createServer(String type, Server server, String info) { server.setUrl(DB_URL); server.setPort(DB_PORT); server.setUsername(DB_USER_NAME); server.setPassword(DB_PASSWORD); server.setType(type); String[] array = info.trim().split("\\s"); int i = 0; for (String item : array) { if (item.startsWith("-w")) { server.setWeight(Integer.parseInt(getConfigString(item, array, i))); } else if (item.startsWith("-u")) { server.setUsername(getConfigString(item, array, i)); } else if (item.startsWith("-p")) { server.setPassword(getConfigString(item, array, i)); } else if (item.startsWith("-P")) { server.setPort(getConfigString(item, array, i)); } else if (item.startsWith("-U")) { server.setUrl(getConfigString(item, array, i)); } else if (item.startsWith("-h")) { server.setIp(getConfigString(item, array, i)); } else if (item.startsWith("-i")) { server.setId(getConfigString(item, array, i)); } else if (i == 0) { server.setIp(item); } i++; } String _url = server.getUrl(); server.setUrl(_url.replace("${host}", server.getIp()).replace("${port}", server.getPort())); } public static String getConfigString(String item, String[] array, int i) { return (item.length() == 2 ? array[i + 1] : item.substring(2)).trim(); } } }
//数据源配置
package com.hengyu.ticket.common; import org.springframework.jdbc.datasource.DriverManagerDataSource; import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; import java.io.IOException; import java.util.HashMap; import java.util.List; import java.util.Map; /** * Created by lgf on 2016/4/3. */ public class DynamicDataSource extends AbstractRoutingDataSource { private static Map<Object, Object> targetDataSources = new HashMap<>(); //初始化数据源 public static void initDataSource(){ try { List<CommonLoadBalancing.Server> servers = CommonLoadBalancing.getServers() ; for (CommonLoadBalancing.Server server:servers){ DriverManagerDataSource ds = new DriverManagerDataSource(); ds.setUsername(server.getUsername()); ds.setPassword(server.getPassword()); ds.setDriverClassName(CommonLoadBalancing.DB_DRIVER); ds.setUrl(server.getUrl()); targetDataSources.put(String.valueOf(server.getId()),ds); } }catch (Exception e){ e.printStackTrace(); } } static { initDataSource(); } public DynamicDataSource() throws IOException { super.setTargetDataSources(targetDataSources); } @Override protected Object determineCurrentLookupKey() { CommonLoadBalancing.Server server = CommonLoadBalancing.getServer(); System.out.println("=====>>获取数据源:" +server); return server.getIndex().toString(); } public Map<Object, Object> getTargetDataSources() { return targetDataSources; } @Override public void setTargetDataSources(Map<Object, Object> targetDataSources) { this.targetDataSources = targetDataSources; } }
//spring配置
package com.hengyu.ticket.common; import org.aopalliance.intercept.MethodInvocation; import org.aspectj.lang.JoinPoint; import org.springframework.aop.support.AopUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.interceptor.TransactionAttribute; import org.springframework.transaction.interceptor.TransactionInterceptor; import org.springframework.web.filter.OncePerRequestFilter; import java.lang.reflect.Method; /** * Created by lgf on 2016/4/4. */ public class MethodInterceptor implements org.aopalliance.intercept.MethodInterceptor { @Autowired private TransactionInterceptor transactionInterceptor; @Override public Object invoke(MethodInvocation invocation) throws Throwable { Class targetClass = invocation.getThis() != null? AopUtils.getTargetClass(invocation.getThis()):null; final TransactionAttribute txAttr = transactionInterceptor.getTransactionAttributeSource().getTransactionAttribute(invocation.getMethod(), targetClass); System.out.println("*******"+txAttr.isReadOnly()); CommonLoadBalancing.setServerType(txAttr.isReadOnly()); Object proceed = invocation.proceed(); return proceed; } }
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:task="http://www.springframework.org/schema/task" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd"> <!-- 支持注解 --> <mvc:annotation-driven /> <!-- 扫描控制器类 --> <context:component-scan base-package="com.hengyu.ticket.service" /> <!-- 加载配置文件 --> <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="locations"> <list> <value>classpath:config.properties</value> </list> </property> </bean> <bean id="dynamicDataSource" class="com.hengyu.ticket.common.DynamicDataSource"> </bean> <!-- 配置 sqlSessionFactory --> <bean id="sqlSessionFactory" name="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dynamicDataSource"/> <property name="plugins"> <array> <bean class="com.hengyu.ticket.common.SqlIntercept"> <property name="show_sql" value="false"></property> </bean> </array> </property> <property name="configurationProperties"> <props> <!-- <prop key="cacheEnabled">true</prop> --> </props> </property> <property name="mapperLocations" value="com.hengyu.ticket.dao.*.xml"/> <property name="typeAliasesPackage" value="com.hengyu.ticket.entity"/> </bean> <!-- 配置 mapperScannerConfigurer 扫描配置文件 --> <bean id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/> <property name="basePackage" value="com.hengyu.ticket.dao"/> <!-- <property name="sqlSessionTemplateBeanName" value="SqlSessionTemplate"/> --> </bean> <!-- 事务管理器 --> <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dynamicDataSource"></property> </bean> <!-- 事物切面 --> <tx:advice id="txAdvice" transaction-manager="txManager"> <tx:attributes > <tx:method name="insert*" propagation="REQUIRED" /> <tx:method name="add*" propagation="REQUIRED" /> <tx:method name="save*" propagation="REQUIRED" /> <tx:method name="update*" propagation="REQUIRED" /> <tx:method name="edit*" propagation="REQUIRED" /> <tx:method name="del*" propagation="REQUIRED" /> <tx:method name="remove*" propagation="REQUIRED" /> <tx:method name="get*" propagation="SUPPORTS" read-only="true" /> <tx:method name="find*" propagation="SUPPORTS" read-only="true" /> <tx:method name="select*" propagation="SUPPORTS" read-only="true" /> <tx:method name="load*" propagation="SUPPORTS" read-only="true" /> <tx:method name="*" /> </tx:attributes> </tx:advice> <aop:config> <aop:advisor pointcut="execution(* com.hengyu.ticket.service.*.*(..))" advice-ref="txAdvice"/> <aop:advisor pointcut="execution(* com.hengyu.ticket.service.*.*(..))" advice-ref="methodInterceptor" order="1"/> <aop:aspect id="im" ref="methodInterceptor"> <aop:pointcut id="mi" expression="execution(* com.hengyu.ticket.service.*.*(..))"></aop:pointcut> </aop:aspect> </aop:config> <bean id="methodInterceptor" class="com.hengyu.ticket.common.MethodInterceptor"></bean> </beans>
//数据库配置SERVER.JSON
{ "username": "root", "password": "admin", "port": "3306", "driver": "com.mysql.jdbc.Driver", "url": "jdbc:mysql://${host}:${port}/ticket?characterEncoding=utf8", "master": [ "127.0.0.1" ], "slave": [ "localhost" ] }
相关推荐
spring cloud微服务框架demo完整可用2版 比第一版多集成了mybatis...(注册中心+生产者+消费者+feign负载均衡+hystrix断路器+仪表盘+gate路由网关+config配置中心+mybatis+oracle+mybatisPlus generator代码自动生成)
源代码使用idea开发,主要讲解springcloud的Eureka服务注册中心,Ribbon负载均衡,Feign,断路器Hystrix,ZUUL网关服务及配置服务中心,共8个module 1.服务注册中心模块(eureka-server) 2.普通服务模块(service-...
这里面包含的组件和内容有: spring cloud eureka,服务注册和服务发现 spring cloud config,动态配置项 ribbon,客户端负载均衡 feign, hystrix,熔断 turbine Spring Cloud Starters 同一个服务中的多数据库支持...
本项目示例基于spring boot 最新版本(2.1.9)实现,Spring Boot、Spring Cloud 学习示例...多数Spring Boot应用只需要很少的Spring配置。 Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Sprin
ribbon,客户端负载均衡 feign, hystrix,熔断 turbine Spring Cloud Starters 同一个服务中的多数据库支持(AOP) 全链路traceId追踪 velocity 前端模板 mybatis, pageHelper (分页), druid (连接池) redis(序列...
SpringBoot集成Atomikos框架-实现分布式数据库XA事务; SpringBoot集成Seata框架-实现TCC模式柔性事务; SpringBoot集成Seata框架-实现AT模式柔性事务;...SpringCloud集成Consul+Ribbon框架-实现注册中心和负载均衡; 等等
本资源为《基于Spring Cloud的...项目包含Eureka注册中心、Zuul网关验证、Config分布式配置管理、Ribbon负载均衡、Feign接口调用、Hystrix容错处理、Sleuth微服务追踪、ELK+Kafka日志收集、RabbitMQ实现分布式事务等。
大觅网-数据库初始化脚本 ...项目包含Eureka注册中心、Zuul网关验证、Config分布式配置管理、Ribbon负载均衡、Feign接口调用、Hystrix容错处理、Sleuth微服务追踪、ELK+Kafka日志收集、RabbitMQ实现分布式事务等。
Spring Cloud利用Spring Boot的开发便利性巧妙地简化了分布式系统基础设施的开发,如服务发现注册、配置中心、消息总线、负载均衡、断路器、数据监控等,还可以将Spring Boot的开发风格做到一键启动和部署。...
## 开发环境 - 操作系统:Windows 10 Enterprise ...- 反向代理负载均衡:Nginx ## 前后分离 - 前端框架:NodeJS + Vue + Axios - 前端模板:ElementUI ## 持续集成 - 持续集成:GitLab - 持续交付:Jenkins
它利用Spring Boot的开发便利性巧妙地简化了分布式系统基础设施的开发,如服务发现注册、配置中心、智能路由、消息总线、负载均衡、断路器、数据监控等,都可以用Spring Boot的开发风格做到一键启动和部署。...
* 反向代理负载均衡:Nginx * CDN服务器:基于Nginx搭建 前端主要技术栈 * 前端框架:Bootstrap + jQuery * 前端模板:AdminLTE 自动化运维 * 持续集成:GitLab * 持续交付:Jenkins (后期考虑加入) * 容器...
12.2.4 负载均衡 457 12.2.5 断路器 458 12.3 实战 458 12.3.1 项目构建 458 12.3.2 服务发现——Discovery(Eureka Server) 459 12.3.3 配置——Config(Config Server) 461 12.3.4 服务模块——Person 服务 463 ...
部署过程中需要配置数据库连接信息、调整服务器环境等。系统介绍:项目简介部分详细介绍了在线网上书店的功能和特点,如用户注册登录、图书分类浏览、购物车管理、订单处理等。此外,还介绍了系统的性能优化策略,如...
微服务模块初始化时,常量和数据库信息等使用云配置服务(spring config)获取; 微服务之间使用负载均衡(ribbon); 微服务网关路由配置; 微服务断路器(hystrix)及监听服务等 启动步骤: 1.启动server-...
12.2.4 负载均衡 457 12.2.5 断路器 458 12.3 实战 458 12.3.1 项目构建 458 12.3.2 服务发现——Discovery(Eureka Server) 459 12.3.3 配置——Config(Config Server) 461 12.3.4 服务模块——Person 服务 463 ...
4.配置Nginx文件,使其负载均衡。 5.待项目构建完成后,运行redis和Nginx(或者跳过Nginx)。 6.修改resource文件中的application.properties,配置其中的数据库信息 7.修改com.wsk.movie.email.Send文件中的用户...
12.2.4 负载均衡 457 12.2.5 断路器 458 12.3 实战 458 12.3.1 项目构建 458 12.3.2 服务发现——Discovery(Eureka Server) 459 12.3.3 配置——Config(Config Server) 461 12.3.4 服务模块——Person 服务 463 ...
客户端负载均衡 Spring Cloud OpenFeign - 内部服务调用 Spring Cloud Hystrix - 熔断 Spring Boot Admin - 程序监控 Spring Cloud Config - 配置中心 暂时本地 Spring Cloud Sleuth - 服务链跟踪 Redis 单机/集群/...
基于SpringCloud+Oauth2+...负载均衡:Nginx 消息中间件:RabbitMq 搜索引擎:ElasticSearch 数据库连接池: Druid 定时任务:xxl-job 对象存储: OSS、MINIO 全局事务管理框架:Seata 应用容器引擎: Docker 可视化D