喜新别厌旧 - 妥妥处理新旧库兼容性问题的一个方法 - 运用java反射+代理思想...

    地球上的程序员都知道,当自己发布一个新版本库的时候,一定要注意向上下左右前后东南西北中发白各个方向的兼容性,尽可能做到最大程度的兼容。

    然而还有另外一种情况 -- 如果自己依赖的库,某天升级后新旧版本间有少量不兼容,这时该怎么办?最直接的办法是也随着它拆分为两个版本,适用于绝大部分情况,但是也有额外的维护负担等缺点;此外如果这个第三方库并不是那么重要,或者其不兼容的地方不是特别多的话,那么为了它而拆分就没必要了。

    记录下这个有两个目的,一个是分享一下实际项目中遇到这个兼容性问题是如何解决的;另外就是看看朋友们有没有其它的思路可以再开拓一下。

    下面就用简化过的代码来说明一下问题以及解决思路:

    (1)第三方库的第一个版本中,有一个业务函数可供调用:

 

package org.otherlib;

public class Otherlib{

	public static String getLibVersion(){
		return "Otherlib V1.0 (use static method)";
	}

	// others... ...

}

 

     (2)自己的库中,用到了这个函数

 

package com.iteye.goonfly;
import org.otherlib.*;

public class Ourlib{

	public static void main(String[] args){
		System.out.println("==== Using lib : " + Otherlib.getLibVersion() + " ====");
	}
}

 

     编译运行如下:

 

$javac -d ./classes/ otherlib1/Otherlib.java
$javac -cp ./classes/ -d ./classes/ oursrc/Ourlib.java
$java -cp ./classes/ com.iteye.goonfly.Ourlib
==== Using lib : Otherlib V1.0 (use static method) ====

 

     (3)第三方库的第二个版本,删掉了这个函数,改用了静态常量字符串

 

package org.otherlib;

public class Otherlib{

	public static final String LIB_VERSION = 
			"Otherlib V2.0 (use static String)";
	
	// others... ...
	
}

 

     这种情况下,可以逐个修改自己的库里面的调用处代码,与之新版本对应:

 

package com.iteye.goonfly;
import org.otherlib.*;

public class Ourlib2{

	public static void main(String[] args){
		//System.out.println("Using lib : " + Otherlib.getLibVersion());
		System.out.println("==== Using lib : " + Otherlib.LIB_VERSION + " ====");
	}

}

 

     但是问题则是,自己的库与第三方库新版本可以配合适用,和旧版本则不行了,喜新厌旧,恐怕要出大事。。。


    由于兼容性的问题不大(不是逻辑上的架构上的或者有大量的接口变更等),所以除了也随着发布两个版本外,还可以采用“反射机制+代理思想,用一个自己的库,可以同时兼容两个版本的第三方库,代码如下:

    (4)自己库的新版本,不再直接调用有变更的地方,而是调用代理类,差异的部分,让代理通过反射处理

 

package com.iteye.goonfly;
//import org.otherlib.*;

public class Ourlib3{

	public static void main(String[] args){
		//System.out.println("Using lib : " + Otherlib.getLibVersion());
		System.out.println("==== Using lib : " + OtherlibProxy.getLibVersion() + " ====");
	}

}

 

    (5)新增的代理类

package com.iteye.goonfly;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class OtherlibProxy{

	public static String getLibVersion(){
		Class clazz = null;
		try {
			clazz = Class.forName("org.otherlib.Otherlib");
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		if(null == clazz){
			return "!!!!Class org.otherlib.Otherlib NOT found!!!!";
		}
		
		try {
			// if it has getLibVersionMethod() method
			Method getLibVersionMethod = clazz.getMethod("getLibVersion", new Class[0]);
			return (String)getLibVersionMethod.invoke(null, new Object[0]);
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		}
		
		try {
			// or else it has the static string field			
			Field field = clazz.getField("LIB_VERSION");
			return (String)field.get(clazz);
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (NoSuchFieldException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
		
		return "!!!!NO getLibVersion() method OR LIB_VERSION string found!!!!";
	}
}

 

    (6)测试验证一下

先试试旧版本

 

$javac -d ./classes/ otherlib1/Otherlib.java
$javac -cp ./classes/ -d ./classes/ oursrc/OtherlibProxy.java
$javac -cp ./classes/ -d ./classes/ oursrc/Ourlib3.java
$java -cp ./classes/ com.iteye.goonfly.Ourlib3
==== Using lib : Otherlib V1.0 (use static method) ====

再试试新版本

 

$javac -d ./classes/ otherlib2/Otherlib.java
$javac -cp ./classes/ -d ./classes/ oursrc/OtherlibProxy.java
$javac -cp ./classes/ -d ./classes/ oursrc/Ourlib3.java
$java -cp ./classes/ com.iteye.goonfly.Ourlib3
java.lang.NoSuchMethodException: org.otherlib.Otherlib.getLibVersion()
	at java.lang.Class.getMethod(Class.java:1622)
	at com.iteye.goonfly.OtherlibProxy.getLibVersion(OtherlibProxy.java:22)
	at com.iteye.goonfly.Ourlib3.main(Ourlib3.java:8)
==== Using lib : Otherlib V2.0 (use static String) ====

 

可以看到,抛出了异常,并且成功调用到了新版本库,测试一切正常后,捕获到异常不输出信息即可,将来的某一天,如果新版本把旧版本彻底的替换淘汰了,那就代理类里面修改一下,是不是design pattern相关的味道出来一点点了^_^

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值