前言
redis是很常用的一个中间件,下面就spring+xxl-conf配置中心+redis做一下整合。
备注:以后的中间件整合都按照这种规则和模式进行的。
初始化配置中心的数据
实际上手动输入数据是很容易出错的,而且有三个环境,test、ppe、product,手滑了输错一个配置,到时候错问题,报null,正式环境都挂了谁能负起这种责任,下面是一份用来初始化各个环境下面配置的脚本:
-- 直接用脚本导入数据库默认配置,方便省事。
-- 小技巧,如果是手动添加数据,那么可以执行这个sql从数据库中直接查找需要的数据,生成需要的数据拼接字符串:
-- with t1 as(
-- select concat("key",'->',"title",'->',value,'$$') as str from xxl_conf_node where env='test' and "key" like 'file-server.redis.%')
-- select string_agg(str,'') from t1;
create or replace function "initRedisConfig"(
in envName varchar,
in para_appname varchar
)
returns varchar
as $BODY$
declare _defaultValues varchar;
declare _envName varchar;
declare _appname varchar;
declare _prefix varchar;
declare strArrays varchar[];
declare arrItemLv1 varchar;
declare tempArrSubItem varchar;
declare valArrs varchar[];
declare item_attr varchar;
declare item_title varchar;
declare item_val varchar;
begin
if envName <> 'test' and envName<> 'ppe' and envName<> 'product' then
raise notice '环境变量异常,只能为test、ppe以及product其中一个。';
return '环境变量异常,只能为test、ppe以及product其中一个。';
end if;
_appname:=para_appname;
_prefix:=concat(_appname,'.redis.','');
_defaultValues:=
'auth->验证用的密码,假如没有不需要验证的话,请留空->$$' ||
'dbIndex->redis默认使用的db的序号【共有12个】->1$$' ||
'host->redis服务器所在ip地址或者hostname->localhost$$' ||
'max_active->redis最大激活连接数量->1000$$' ||
'max_idle->redis控制一个pool最多有多少个状态为idle(空闲的)的jedis实例,默认值也是8。->200$$' ||
'max_wait->等待可用连接的最大时间,单位毫秒,默认值为-1,表示永不超时。如果超过等待时间,则直接抛出JedisConnectionException;->5000$$' ||
'needAuth->是否需要验证,输入 true 或者 false 两种布尔值->false$$' ||
'port->redis的服务端口,请填写数字->6379$$' ||
'test_on_borrow->在borrow一个jedis实例时,是否提前进行validate操作;如果为true,则得到的jedis实例均是可用的->true$$' ||
'timeout->超时时间->10000$$'
;
strArrays:=string_to_array(_defaultValues,'$$');
_envName:=envName;
insert into xxl_conf_project ("appname", title) values (_appname,_appname) on conflict ("appname") do nothing;
<<loop4BigArray>>
foreach arrItemLv1 in array strArrays
loop
if char_length(arrItemLv1) < 1 then
raise notice '空字符串无须处理';
continue ;
end if;
valArrs:=string_to_array(arrItemLv1,'->');
item_attr:=valArrs[1];
item_title:=valArrs[2];
item_val:=valArrs[3];
raise notice '属性名称:%,描述:%,当前值:%',item_attr,item_title,item_val;
raise notice '开始添加记录';
insert into xxl_conf_node("env","key","appname","title","value")
values (_envName,concat(_prefix,item_attr),_appname,item_title,item_val)
on conflict ("env","key") do nothing ;
end loop loop4BigArray;
return envName||'环境下的'||_appName||'配置成功';
end;
$BODY$ language plpgsql volatile ;
-- 记住执行下面方法分别添加三个环境下的默认数据。
-- select "initRedisConfig"('test','file-server');
-- select "initRedisConfig"('ppe','file-server');
-- select "initRedisConfig"('product','file-server');
用工具远程登录配置中心的数据库,直接执行即可:
select "initRedisConfig"('test','file-server');
select "initRedisConfig"('ppe','file-server');
select "initRedisConfig"('product','file-server');
编写配置类以及对应插件
redis的相对应的配置类:
请放到WebExt下面
package net.w2p.WebExt.config;
/***
*
* 提取redis的设置
*
* redis.needAuth = false
* redis.auth = none
* #host
* redis.HOST = localhost
* #port
* redis.PORT = 6379
* #db index
* redis.DbIndex = 3
* ***/
public class RedisConf {
public Boolean needAuth = false;//是否需要验证
public String auth = "";//验证用的密码
public String host = "localhost";
public Integer port = 6379;
public Integer dbIndex = 3;
// public Integer MAX_ACTIVE =1000;
public Integer max_active =1000;
// FileUtil.getPropertyValueInt("/properties/redis.properties", "max_active");;
//控制一个pool最多有多少个状态为idle(空闲的)的jedis实例,默认值也是8。
public Integer max_idle = 200;
//FileUtil.getPropertyValueInt("/properties/redis.properties", "max_idle");;
//等待可用连接的最大时间,单位毫秒,默认值为-1,表示永不超时。如果超过等待时间,则直接抛出JedisConnectionException;
public Integer max_wait =5000;
//FileUtil.getPropertyValueInt("/properties/redis.properties", "max_wait");;
//超时时间
public Integer timeout = 10000;
//FileUtil.getPropertyValueInt("/properties/redis.properties", "timeout");;
//在borrow一个jedis实例时,是否提前进行validate操作;如果为true,则得到的jedis实例均是可用的;
public Boolean test_on_borrow = true;
//FileUtil.getPropertyValueBoolean("/properties/redis.properties", "test_on_borrow");
public Boolean getNeedAuth() {
return needAuth;
}
public void setNeedAuth(Boolean needAuth) {
this.needAuth = needAuth;
}
public String getAuth() {
return auth;
}
public void setAuth(String auth) {
this.auth = auth;
}
public String getHost() {
return host;
}
public void setHost(String host) {
this.host = host;
}
public Integer getPort() {
return port;
}
public void setPort(Integer port) {
this.port = port;
}
public Integer getDbIndex() {
return dbIndex;
}
public void setDbIndex(Integer dbIndex) {
this.dbIndex = dbIndex;
}
public Integer getMax_active() {
return max_active;
}
public void setMax_active(Integer max_active) {
this.max_active = max_active;
}
public Integer getMax_idle() {
return max_idle;
}
public void setMax_idle(Integer max_idle) {
this.max_idle = max_idle;
}
public Integer getMax_wait() {
return max_wait;
}
public void setMax_wait(Integer max_wait) {
this.max_wait = max_wait;
}
public Integer getTimeout() {
return timeout;
}
public void setTimeout(Integer timeout) {
this.timeout = timeout;
}
public Boolean isTest_on_borrow() {
return test_on_borrow;
}
public void setTest_on_borrow(Boolean test_on_borrow) {
this.test_on_borrow = test_on_borrow;
}
}
对应plugin插件:
package net.w2p.WebExt.Plugins;
import net.w2p.Shared.common.WebTools;
import net.w2p.WebExt.config.RedisConf;
import org.springframework.context.annotation.DependsOn;
import org.springframework.stereotype.Service;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import java.io.*;
import java.net.URL;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
/****
*
* 需要在spring里面进行托管。
*
* ***/
public class RedisPlugin {
/****
* 注意,这里需要存储一下其他redis的实例,假如因为某个原因而没有释放资源,那么这里就需要释放资源了,你永远也不知道什么地方漏了释放资源的。
* **/
private ConcurrentHashMap<Jedis,Long> redisInstanceCachePool =new ConcurrentHashMap<>();
private JedisPool jedisPool = null;
/**
* redis过期时间,以秒为单位
*/
public final static int EXRP_HOUR = 60*60; //一小时
public final static int EXRP_DAY = 60*60*24; //一天
public final static int EXRP_MONTH = 60*60*24*30; //一个月
private RedisConf redisConf;
public RedisPlugin(RedisConf redisConf){
this.redisConf=redisConf;
}
/**
* 初始化Redis连接池
*/
private void initialPool(){
try {
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxTotal(redisConf.max_active);
config.setMaxIdle(redisConf.max_idle);
config.setMaxWaitMillis(redisConf.max_wait);
config.setTestOnBorrow(redisConf.test_on_borrow);
if(redisConf.needAuth){
jedisPool = new JedisPool(config, redisConf.host,
redisConf.port,
redisConf.timeout,redisConf.auth);
}
else{
jedisPool = new JedisPool(config, redisConf.host, redisConf.port,
redisConf.timeout);
}
} catch (Exception e) {
e.printStackTrace();
try{
}catch(Exception e2){
e2.printStackTrace();
}
}
}
/**
* 同步获取Jedis实例
* @return Jedis
*/
public synchronized Jedis getJedis() {
if (jedisPool == null) {
initialPool();
}
Jedis jedis = null;
try {
if (jedisPool != null) {
jedis = jedisPool.getResource();
jedis.select(redisConf.dbIndex);
Long nowTime= WebTools.getPhpTimeStamp(new Date().getTime());
redisInstanceCachePool.put(jedis,nowTime);
}
} catch (Exception e) {
e.printStackTrace();
}finally{
}
return jedis;
}
/**
* 释放jedis资源
* @param jedis
*/
public synchronized void returnResource(final Jedis jedis) {
if (jedis != null && jedisPool !=null) {
jedisPool.returnResource(jedis);
if(redisInstanceCachePool.containsKey(jedis)){
redisInstanceCachePool.remove(jedis);
}
}
}
}
好了,现在来将redis整合到spring中
使用java代码整合到spring中进行设置
在FileServerWebApp的BeanConfiguration下面添加:
package net.w2p.local.plugins.BeanConfiguration;
import com.xxl.conf.core.XxlConfClient;
import net.w2p.WebExt.Plugins.RedisPlugin;
import net.w2p.WebExt.config.RedisConf;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/***
*
* redis配置
* ***/
@Configuration
public class RedisConfiguration {
//--提醒一下。@Primary注解是在有多个同类型bean时候,指定默认注入的那一个,除非用@Qualifier
//--明确指定bean的id。
//--这样做的目的是,以后要自定义的session会存放到redis里面---多个子网站的session都放同一个redis,
//--这个redis专门存放session,与网站的缓存不是一回事,故此要分开。
@Bean(name="redisConf")
@Primary
public RedisConf redisConf(){
RedisConf redisConf=new RedisConf();
final String VarPrefix="file-server.redis.";
redisConf.needAuth=XxlConfClient.getBoolean(VarPrefix+"needAuth");
redisConf.auth=XxlConfClient.get(VarPrefix+"auth");
redisConf.host=XxlConfClient.get(VarPrefix+"host");
redisConf.port=XxlConfClient.getInt(VarPrefix+"port");
redisConf.dbIndex=XxlConfClient.getInt(VarPrefix+"dbIndex");
redisConf.max_active=XxlConfClient.getInt(VarPrefix+"max_active");
redisConf.max_idle=XxlConfClient.getInt(VarPrefix+"max_idle");
redisConf.max_wait=XxlConfClient.getInt(VarPrefix+"max_wait");
redisConf.timeout=XxlConfClient.getInt(VarPrefix+"timeout");
redisConf.test_on_borrow=XxlConfClient.getBoolean(VarPrefix+"test_on_borrow");
return redisConf;
}
//--提醒一下。@Primary注解是在有多个同类型bean时候,指定默认注入的那一个,除非用@Qualifier
//--明确指定bean的id。
//--这样做的目的是,以后要自定义的session会存放到redis里面---多个子网站的session都放同一个redis,
//--这个redis专门存放session,与网站的缓存不是一回事,故此要分开。
@Bean(name="redisPlugin")
@Primary
@Autowired
public RedisPlugin redisPlugin(@Qualifier("redisConf")RedisConf redisConf){
RedisPlugin redisPlugin=new RedisPlugin(redisConf);
return redisPlugin;
}
}
进行测试
测试代码如下:
@Autowired
RedisPlugin redisPlugin;
@Test
public void trySetRedisVal(){
Jedis client=redisPlugin.getJedis();
client.set("test005",new Date().toString());
System.out.println("设置时间为:"+client.get("test005"));
client.close();
}
测试结果:
好了,测试通过。
ps:目前的进度已经是基本整合完sofarpc这个大头了,所以在输出日志可以看到sofarpc的字眼,目前就是回来补充各个整合的流程。