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 Quartz定时任务的重复执行问题是一个常见的挑战。Spring Quartz是一个强大的、开源的作业调度框架,允许开发者定义和执行复杂的定时任务。然而,当多个服务器实例并行运行时,...
Ribbon是客户端负载均衡器,Feign是一个声明式HTTP客户端。配置它们可以使你的服务通过服务名而不是IP地址来调用其他服务,从而实现服务间的通信。 例如,为Ribbon配置一个配置类: ```java @Configuration public...
4. **Ribbon和Feign客户端**:在Spring Cloud中,Ribbon和Feign常用于服务间的负载均衡。如果各个服务连接不同的数据源,我们可以通过配置Ribbon或Feign客户端,使它们根据请求参数或特定规则选择合适的数据源。 5....
通过调整和优化相关的Spring配置,可以确保在不同服务器之间实现会话的一致性和系统的高可用性。需要注意的是,实际部署时应根据具体的硬件资源、网络环境以及安全性需求进行细致的调整和测试,以达到最佳效果。
配置`Nginx`进行负载均衡的步骤如下: 1. 安装`Nginx`:在服务器上安装`Nginx`,确保它能够正常启动和运行。 2. 配置`Nginx`:在`nginx.conf`配置文件中,我们需要定义一个upstream块,列出所有`Tomcat`服务器的IP...
2. 路由与负载均衡:使用Zuul或Spring Cloud Gateway作为API网关,实现请求的路由和负载均衡。 3. 配置管理:利用Spring Cloud Config服务器集中管理所有微服务的配置,方便统一更新。 4. 安全认证:集成Spring ...
本资料包“springboot-nginx-redis-session共享、TCPUDP负载均衡.zip”提供了一套完整的解决方案,涉及到Spring Boot、Nginx、Redis以及TCP/UDP负载均衡的整合。下面将详细解释这些技术及其在实际应用中的作用。 ...
在互联网行业中,数据库管理是关键的一环,尤其是在大型系统中,常常需要处理多个数据库以实现负载均衡、数据冗余或不同的访问策略。本方案主要探讨如何在基于Hibernate和Spring框架的环境中实现多数据库的管理,...
6. 测试配置,确保所有组件都能正常工作,并根据需求调整负载均衡策略。 在实际部署中,你可能还需要考虑其他的优化措施,如使用SSL加密通信、设置健康检查机制以检测后端服务器状态、调整`Nginx`和`Redis`的缓存...
通过上述分析,我们可以看到Spring框架下多数据源配置及动态数据源切换的实现并不复杂,但在实际应用中还需要注意一些细节问题,比如事务的一致性管理、数据源的负载均衡等。此外,随着技术的发展,未来还可能出现更...
该项目是一款基于SpringCloud框架的Idea集成Ribbon客户端负载均衡设计源码,总文件量达86个,涵盖33个Java源文件、12个XML配置文件、6个HTML文件、5个Git忽略文件、4个数据库文件、4个JAR包、4个属性文件、4个YAML...
在构建高性能、高可用性的Web应用...这个过程中涉及的关键技术包括Nginx的反向代理和负载均衡配置、Tomcat的session管理、以及Redis的分布式数据存储。正确配置和优化这些组件,将有助于构建一个健壮的分布式Web系统。
在实际的应用场景中,可能还需要考虑事务管理、异常处理以及读写分离、负载均衡等高级特性。例如,可以使用Spring的PlatformTransactionManager来管理跨数据库的事务,或者利用AOP(面向切面编程)来实现特定的策略...
在IT行业中,数据库读写分离是一种常见的优化策略,主要用于提高系统的并发处理能力和数据读取...在实际项目中,还可以考虑使用中间件如MySQL的Proxy或商业化解决方案如MaxScale来实现更高级的读写分离和负载均衡策略。
使用Java编程语言和SpringBoot框架开发各服务,集成SpringCloud组件,实现服务注册与发现、负载均衡等功能。利用MyBatis作为持久层框架,操作MySQL数据库。系统完成后,进行全面的功能测试、性能测试和安全测试,...
spring cloud微服务框架demo完整可用2版 比第一版多集成了mybatis...(注册中心+生产者+消费者+feign负载均衡+hystrix断路器+仪表盘+gate路由网关+config配置中心+mybatis+oracle+mybatisPlus generator代码自动生成)
以下将详细阐述Spring配置各种数据源的方法、原理以及优缺点。 1. **单数据源配置** 单一数据源是最常见的配置,适用于大多数简单应用。在Spring Boot中,可以通过`application.properties`或`application.yml`...
Nginx的负载均衡功能可以通过配置upstream模块实现。它可以根据不同的策略(如轮询、最少连接、IP哈希等)将请求分发到后端服务器集群,提高服务的并发处理能力。在多服务器环境中,确保用户在切换服务器时仍能访问...
Spring框架提供了灵活且强大的机制来处理这种场景,使得开发者能够在一个应用中集成多个数据源,从而实现数据的分区存储、读写分离、负载均衡等策略。本文将详细探讨如何在Spring环境中配置多个数据源,包括...
在配置`nginx`进行负载均衡时,通常会使用轮询、权重轮询、最少连接数等策略。例如,一个简单的`nginx`负载均衡配置示例: ```nginx http { upstream backend { server backend1.example.com; server backend2....