jdk7监听文件变化感知

我们常常会遇到需要修改配置文件,却不得不重启应用才能使配置生效的问题。

使用spring可以自动感知变化,但我们自己写的配置读取却需要通过jdk7提供的库来实现。

说白了,就是需要在适当的位置开启一个监听线程,使用WatchService去监听变化,处理变化。

例如我们在拦截器中读取了当前项目的config/Application.properties配置文件,把配置中的ip白名单读取到成员变量中,在配置文件改变后才会去刷新该成员变量。

配置

#Only allows auth ip visit
auth.ip[0]=127.0.0.1
auth.ip[1]=192.168.10.254
auth.ip[2]=192.168.0.170


拦截器写法


private List<String> ipList;

/**

 *这里构造函数启动线程

 */

public AuthInInterceptor(List<String> ipList) {
new Thread(new Runnable() {
@Override
public void run() {
propertiesListener();
}
}).start();
}


    /**
     * 配置文件监听,只监听外部配置
     */
    public void propertiesListener(){
    try {
FileSystem fileSystem = FileSystems.getDefault();  //启动默认文件系统
WatchService watcher = fileSystem.newWatchService();//获取到监听服务
String dir = System.getProperty("user.dir");//读取当前应用目录
String p = dir + "\\config";
if(!new File(p).exists()){
p = dir;
}
if(!new File(p).exists()){//指定配置文件目录不存在直接返回
return;
}
Path myDir = fileSystem.getPath(p);  //要监听的文件目录
myDir.register(watcher,StandardWatchEventKinds.ENTRY_MODIFY);  //对该目录的修改进行注册监听
WatchKey watchKey = null;  
            while (true) { 
            watchKey = watcher.take();  
            for (WatchEvent<?> event : watchKey.pollEvents()) {  
                     if (event.kind() == StandardWatchEventKinds.ENTRY_MODIFY) {  //监听事件是修改
                      List<String> ips = null;
                        if("Application.properties".equalsIgnoreCase(event.context().toString())){ //修改的文件是指定的配置文件

//读取文件配置
                          InputStream in = new FileInputStream(p +"\\" + event.context().toString());   
                          Properties properties = new Properties();
                          properties.load(in);
                          ips = new ArrayList<String>();
                          for (Object key : properties.keySet()) {
                          String strkey = key.toString();
                          String val = properties.getProperty(strkey);
      if(strkey.startsWith("auth.ip") && !StringUtils.isEmpty(val)){
      ips.add(val);
      }
      }
                         }

//读取到了新的配置,就替换到成员变量
                         if(!CollectionUtils.isEmpty(ips)){
                          ipList.clear();
                          ipList.addAll(ips);
                         }
                     }  
                }
            //执行过一次就得把监控池重置,才能再次监控
            boolean reset = watchKey.reset();
      if (!reset)
      break;
            }
} catch (IOException e) {
logger.error("load properties error", e);
} catch (InterruptedException e) {
logger.error("watch properties events error", e);
}
    }


如何判断请求ip是否在白名单里面呢?

                boolean flag = false;
String ipAddress = getUsrIPAddr(request);// 获取客户端的IP地址
for (String ipString : ipList) {
if (ipAddress.equals(ipString)) {
flag = true;
break;
}
}

为true则允许访问


/** 
     * 获取客户端ip地址   
     * @param request 
     * @return 
     */  
    public String getUsrIPAddr(HttpServletRequest request) {  
        String ip = "";  
        //1.首先考虑有反向代理的情况,如果有代理,通过“x-forwarded-for”获取真实ip地址  
        ip = request.getHeader("x-forwarded-for");  
        //2.如果squid.conf的配制文件forwarded_for项默认是off,则:X-Forwarded-For:unknown。考虑用Proxy-Client-IP或WL-Proxy-Client-IP获取  
        if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {  
            ip = request.getHeader("Proxy-Client-IP");  
        }  
        if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {  
            ip = request.getHeader("WL-Proxy-Client-IP");  
        }  
        //3.最后考虑没有代理的情况,直接用request.getRemoteAddr()获取ip  
        if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {  
            ip = request.getRemoteAddr();  
        }  
        //4.如果通过多级反向代理,则可能产生多个ip,其中第一个非unknown的IP为客户端真实IP(IP按照','分割)  
        if(ip != null && ip.split(",").length > 1){  
            ip = (ip.split(","))[0];  
        }          
        //5.如果是服务器本地访问,需要根据网卡获取本机真实ip  
        if("127.0.0.1".equals(ip)) {  
            try {  
                ip = InetAddress.getLocalHost().getHostAddress();  
            } catch (UnknownHostException e) {  
                logger.error(e.getMessage(),e);//获取服务器(本地)ip信息失败  
                return "";  
            }  
        }  
//        6.校验ip的合法性,不合法返回""  
        if(!isValidIp(ip)) {  
            return "The ip is invalid.";  
        }else {  
            return ip;  
        }  
    }  
  
    /** 
     * 判断是否为合法IP地址 
     * @param ipAddress 
     * @return 
     */  
    private boolean isValidIp(String ipAddress) {  
        boolean retVal = false;  
        try {  
            if(ipAddress!=null && !"".equals(ipAddress)){  
                Pattern pattern = Pattern.compile("([1-9]|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])(\\.(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])){3}");  
                retVal = pattern.matcher(ipAddress).matches();  
            }              
        } catch(Exception e){  
            logger.error(e.getMessage(), e);  
        }  
        return retVal;  
    }  


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值