威尼斯wns.9778官网 > 计算机教程 > 详解java之redis篇(spring-【威尼斯wns.9778官网】dat

原标题:详解java之redis篇(spring-【威尼斯wns.9778官网】dat

浏览次数:194 时间:2020-01-11

前言

1,利用spring-data-redis整合

大家在工作中可能会遇到这样的需求,即Redis读写分离,目的是为了压力分散化。下面我将为大家介绍借助AWS的ELB实现读写分离,以写主读从为例。

项目使用的pom.xml:

实现

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 <modelVersion>4.0.0</modelVersion>

 <groupId>com.x.redis</groupId>
 <artifactId>Spring_redis</artifactId>
 <version>1.0-SNAPSHOT</version>
 <packaging>jar</packaging>

 <name>Spring_redis</name>
 <url>http://maven.apache.org</url>

 <properties>
 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
 </properties>

 <dependencies>
  <dependency> 
  <groupId>org.springframework.data</groupId> 
  <artifactId>spring-data-redis</artifactId> 
  <version>1.0.2.RELEASE</version> 
 </dependency> 
 <dependency> 
  <groupId>org.springframework</groupId> 
  <artifactId>spring-core</artifactId> 
  <version>3.1.2.RELEASE</version> 
 </dependency> 


 <dependency> 
  <groupId>redis.clients</groupId> 
  <artifactId>jedis</artifactId> 
  <version>2.1.0</version> 
 </dependency> 

  <dependency> 
  <groupId>junit</groupId> 
  <artifactId>junit</artifactId> 
  <version>4.8.2</version> 
  <scope>test</scope> 
 </dependency> 
    <dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.6.1</version>
   </dependency>
   <!-- 将现有的jakarta commons logging的调用转换成lsf4j的调用。 -->
   <dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>jcl-over-slf4j</artifactId>
    <version>1.6.1</version>
   </dependency>
   <!-- Hack:确保commons-logging的jar包不被引入,否则将和jcl-over-slf4j冲突 -->
   <dependency>
    <groupId>commons-logging</groupId>
    <artifactId>commons-logging</artifactId>
    <version>1.1.1</version>
    <scope>provided</scope>
   </dependency>
   <!-- slf4j的实现:logback,用来取代log4j。更快、更强! -->
   <dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>0.9.24</version>
    <scope>runtime</scope>
   </dependency>
 </dependencies>
</project>

引用库文件

除了log部分,只有一个spring core 和 spring-data-redis了

 !-- redis客户端 -- dependency groupIdredis.clients/groupId artifactIdjedis/artifactId version2.6.2/version /dependency

项目文件目录结构:

方式一,借助切面

威尼斯wns.9778官网 1

JedisPoolSelector

applicationContext.xml:

此类的目的是为读和写分别配置不同的注解,用来区分是主还是从。

1,context:property-placeholder 标签用来导入properties文件。从而替换${redis.maxIdle}这样的变量。

package com.silence.spring.redis.readwriteseparation;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;/** * Created by keysilence on 16/10/26. */@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.METHOD)public @interface JedisPoolSelector { String value();}

2,context:component-scan 是为了在com.x.redis.dao报下的类能够实用spring的注解注入的方式。

JedisPoolAspect

3,事实上我们只需要把JedisPoolConfig配数来就好了,接下来就是spring的封装了。所以直接看UserDAOImpl的实现就明白了。

此类的目的是针对主和从的注解,进行动态链接池调配,即主的使用主链接池,从的使用从连接池。

<?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:p="http://www.springframework.org/schema/p" 
 xmlns:context="http://www.springframework.org/schema/context" 
 xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx" 
 xmlns:aop="http://www.springframework.org/schema/aop" 
 xsi:schemaLocation=" 
   http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd 
   http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> 

 <context:property-placeholder location="classpath:redis.properties" /> 
 <context:component-scan base-package="com.x.redis.dao">
 </context:component-scan>
 <bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig"> 
  <property name="maxIdle" value="${redis.maxIdle}" /> 
  <property name="maxActive" value="${redis.maxActive}" /> 
  <property name="maxWait" value="${redis.maxWait}" /> 
  <property name="testOnBorrow" value="${redis.testOnBorrow}" /> 
 </bean> 

 <bean id="connectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" 
  p:host-name="${redis.host}" p:port="${redis.port}" p:password="${redis.pass}" p:pool-config-ref="poolConfig"/> 

 <bean id="redisTemplate" class="org.springframework.data.redis.core.StringRedisTemplate"> 
  <property name="connectionFactory" ref="connectionFactory" /> 
 </bean>   

 <bean id="userDAO" class="com.x.redis.dao.impl.UserDAOImpl" /> 
</beans>
package com.silence.spring.redis.readwriteseparation;import org.aspectj.lang.JoinPoint;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Before;import org.aspectj.lang.annotation.Pointcut;import org.aspectj.lang.reflect.MethodSignature;import org.springframework.beans.BeansException;import org.springframework.context.ApplicationContext;import org.springframework.context.ApplicationContextAware;import redis.clients.jedis.JedisPool;import javax.annotation.PostConstruct;import java.lang.reflect.Method;import java.util.Date;/** * Created by keysilence on 16/10/26. */@Aspectpublic class JedisPoolAspect implements ApplicationContextAware { private ApplicationContext ctx; @PostConstruct public void init() { System.out.println("jedis pool aspectj started @"   new Date()); } @Pointcut("execution(* com.silence.spring.redis.readwriteseparation.util.*.*(..))") private void allMethod() { } @Before("allMethod()") public void before(JoinPoint point) { Object target = point.getTarget(); String method = point.getSignature().getName(); Class classz = target.getClass(); Class[] parameterTypes = ((MethodSignature) point.getSignature()) .getMethod().getParameterTypes(); try { Method m = classz.getMethod(method, parameterTypes); if (m != null && m.isAnnotationPresent(JedisPoolSelector.class)) { JedisPoolSelector data = m .getAnnotation(JedisPoolSelector.class); JedisPool jedisPool = (JedisPool) ctx.getBean(data.value()); DynamicJedisPoolHolder.putJedisPool(jedisPool); } } catch (Exception e) { e.printStackTrace(); } } public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.ctx = applicationContext; }}

redis.properties:

DynamicJedisPoolHolder

# Redis settings
#redis.host=192.168.20.101
#redis.port=6380
#redis.pass=foobared
redis.host=127.0.0.1
redis.port=6379
redis.pass=

redis.maxIdle=300
redis.maxActive=600
redis.maxWait=1000
redis.testOnBorrow=true

此类目的是存储当前使用的JedisPool,即上面类赋值后的结果保存。

UserDAOImpl:

package com.silence.spring.redis.readwriteseparation;import redis.clients.jedis.JedisPool;/** * Created by keysilence on 16/10/26. */public class DynamicJedisPoolHolder { public static final ThreadLocalJedisPool holder = new ThreadLocalJedisPool(); public static void putJedisPool(JedisPool jedisPool) { holder.set(jedisPool); } public static JedisPool getJedisPool() { return holder.get(); }}

1,spring对dao层的封装很多用了类似于下面代码的模板方式。

RedisUtils

2,RedisTemplate就是spring对redis的一个封装而已。

此类目的是对Redis具体的调用,里面包含使用主还是从的方式调用。

public class UserDAOImpl implements UserDAO {

 @Autowired
 protected RedisTemplate<Serializable, Serializable> redisTemplate;

 public void saveUser(final User user) {
  redisTemplate.execute(new RedisCallback<Object>() {

   @Override
   public Object doInRedis(RedisConnection connection) throws DataAccessException {
    connection.set(redisTemplate.getStringSerializer().serialize("user.uid."   user.getId()),
        redisTemplate.getStringSerializer().serialize(user.getName()));
    return null;
   }
  });
 }

 @Override
 public User getUser(final long id) {
  return redisTemplate.execute(new RedisCallback<User>() {
   @Override
   public User doInRedis(RedisConnection connection) throws DataAccessException {
    byte[] key = redisTemplate.getStringSerializer().serialize("user.uid."   id);
    if (connection.exists(key)) {
     byte[] value = connection.get(key);
     String name = redisTemplate.getStringSerializer().deserialize(value);
     User user = new User();
     user.setName(name);
     user.setId(id);
     return user;
    }
    return null;
   }
  });
 }


}
package com.silence.spring.redis.readwriteseparation.util;import com.silence.spring.redis.readwriteseparation.DynamicJedisPoolHolder;import com.silence.spring.redis.readwriteseparation.JedisPoolSelector;import org.slf4j.Logger;import org.slf4j.LoggerFactory;/** * Created by keysilence on 16/10/26. */public class RedisUtils { private static Logger logger = LoggerFactory.getLogger(RedisUtils.class); @JedisPoolSelector("master") public String setString(final String key, final String value) { String ret = DynamicJedisPoolHolder.getJedisPool().getResource().set(key, value); System.out.println("key:"   key   ",value:"   value   ",ret:"   ret); return ret; } @JedisPoolSelector("slave") public String get(final String key) { String ret = DynamicJedisPoolHolder.getJedisPool().getResource().get(key); System.out.println("key:"   key   ",ret:"   ret); return ret; }}

其他:

spring-datasource.xml

User:

xml version="1.0" encoding="UTF-8"beans xmlns="" xmlns:xsi="" xmlns:aop="" xsi:schemaLocation="   " bean  !-- 池中最大链接数 -- property name="maxTotal" value="100"/ !-- 池中最大空闲链接数 -- property name="maxIdle" value="50"/ !-- 池中最小空闲链接数 -- property name="minIdle" value="20"/ !-- 当池中链接耗尽,调用者最大阻塞时间,超出此时间将跑出异常。 -- property name="maxWaitMillis" value="1000"/ !-- 参考: -- !-- 调用者获取链接时,是否检测当前链接有效性。无效则从链接池中移除,并尝试继续获取。 -- property name="testOnBorrow" value="true" / !-- 向链接池中归还链接时,是否检测链接有效性。 -- property name="testOnReturn" value="true" / !-- 调用者获取链接时,是否检测空闲超时。如果超时,则会被移除 -- property name="testWhileIdle" value="true" / !-- 空闲链接检测线程一次运行检测多少条链接 -- property name="numTestsPerEvictionRun" value="10" / !-- 空闲链接检测线程检测周期。如果为负值,表示不运行检测线程。 -- property name="timeBetweenEvictionRunsMillis" value="60000" / !-- 链接获取方式。队列:false;栈:true -- !--property name="lifo" value="false" /-- /bean bean  constructor-arg index="0" ref="poolConfig"/ constructor-arg index="1" value="192.168.100.110" type="java.lang.String"/ constructor-arg index="2" value="6379" type="int"/ /bean bean  constructor-arg index="0" ref="poolConfig"/ !-- 此处Host配置成ELB地址 -- constructor-arg index="1" value="192.168.100.110" type="java.lang.String"/ constructor-arg index="2" value="6380" type="int"/ /bean bean  /bean bean / aop:aspectj-autoproxy proxy-target-//beans
public class User {

 private long id;
 private String name;

 public long getId() {
  return id;
 }

 public void setId(long id) {
  this.id = id;
 }

 public String getName() {
  return name;
 }

 public void setName(String name) {
  this.name = name;
 }
}

Test

测试代码:

package com.silence.spring.redis.readwriteseparation;import com.silence.spring.redis.readwriteseparation.util.RedisUtils;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;/** * Created by keysilence on 16/10/26. */public class Test { public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-datasource.xml"); System.out.println(ctx); RedisUtils redisUtils = (RedisUtils) ctx.getBean("redisUtils"); redisUtils.setString("aaa", "111"); System.out.println(redisUtils.get("aaa")); }}
public static void main(String[] args) {
  ApplicationContext ac = new ClassPathXmlApplicationContext("classpath:/applicationContext.xml");
  UserDAO userDAO = (UserDAO)ac.getBean("userDAO");
  User user1 = new User();
  user1.setId(1);
  user1.setName("obama");
  userDAO.saveUser(user1);
  User user2 = userDAO.getUser(1);
  System.out.println(user2.getName());
 }

方式二,依赖注入

2,不利用spring-data-redis整合

与方式一类似,但是需要写死具体使用主的池还是从的池,思路如下: 放弃注解的方式,直接将主和从的两个链接池注入到具体实现类中。

个人觉得这样整合灵活度更大,能够更加明了的完成任务。

RedisUtils

pom.xml:

本文由威尼斯wns.9778官网发布于计算机教程,转载请注明出处:详解java之redis篇(spring-【威尼斯wns.9778官网】dat

关键词:

上一篇:Redis 对比 Memcached 并在 CentOS 下进行安装配置详解

下一篇:没有了