Java動態代理在一些中間件中經常用到,或者一些大型項目中都會用到。
這裏順帶使用一下自定義註解方式,基於java 反射機制讀取.properties格式文件。
demo的大致內容包含以下:
1.配置文件:config.properties
url=http://www.hrsstd.com
password= root
username= zhanghuilong
port = 8080
isOpen = true
2.自定義註解類
註解中的原生標籤具體含義可以自行了解
/**
* @author zhanghuilong
* @desc 自定義註解,讀取配置文件內容
* @since 2019/01/02
*/
@Target({ ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ReadConf {
/**
* read config.properties context eg: key = value
* @return
*/
String value();
}
3.demo接口定義
/**
* @author zhanghuilong
* @desc 配置中心
* @since 2019/01/02
*/
public interface HrsConfigService {
@ReadConf(value = "url")
String getUrl();
@ReadConf("password")
String getPwd();
@ReadConf("username")
String getUserName();
@ReadConf("port")
Integer getPort();
@ReadConf("isOpen")
Boolean getOff();
}
4.動態代理核心實現
invocationHandler的實現
/**
* @author zhanghuilong
* @desc 動態代理具體實現方法
* @since 2019/01/02
*/
public class PropertyInvocationHandler implements InvocationHandler {
private Properties properties;
public PropertyInvocationHandler(Properties properties) {
this.properties = properties;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println(" 調用 method = [" + method.getName() +"]");
ReadConf readConf = method.getAnnotation(ReadConf.class);
if (readConf == null){
return null;
}
String value = readConf.value();
String property = properties.getProperty(value);
if (StringUtils.isEmpty(property)){
return null;
}
Class<?> returnClass = method.getReturnType();
// 基本原始類型,這裏只寫了部分類型,滿足當前demo接口返回值類型,如遇項目有多重類型,可以添加補全所以類型
if (returnClass.isPrimitive()){
if (returnClass.equals(int.class)){
return Integer.valueOf(property);
}
else if (returnClass.equals(long.class)){ return (Long.valueOf(property));}
else if (returnClass.equals(double.class)) {return (Double.valueOf(property));}
else if (returnClass.equals(float.class)) { return (Float.valueOf(property)); }
else if (returnClass.equals(boolean.class)) { return (Boolean.valueOf(property));}
}else {
if (returnClass.equals(Integer.class)){
return Integer.valueOf(property);
}else if (returnClass.equals(String.class)){
return String.valueOf(property);
}else if (returnClass.equals(Boolean.class)){
return Boolean.valueOf(property);
}
}
return property;
}
}
5.讀取配置的通用工廠方法
/**
* @author zhanghuilong
* @desc 讀取配置工廠方法
* @since 2019/01/02
*/
public class HrsConfigFactory {
public HrsConfigFactory() {
}
/**
* 讀取方法
* @param inputStream
* @return
*/
public static HrsConfigService readProperties(final InputStream inputStream){
final Properties properties = new Properties();
try {
properties.load(inputStream);
} catch (IOException e) {
System.out.println("load inputStream error ");
return null;
}
// java 代理機制
return (HrsConfigService)Proxy
.newProxyInstance(HrsConfigService.class.getClassLoader(), new Class[] { HrsConfigService.class },
new PropertyInvocationHandler(properties));
}
}
6.demo 的測試執行類main方法
/**
* @author zhanghuilong
* @desc 動態代理+自定義註解
* @since 2019/01/02
*/
public class DemoTest {
public static void main(String[] args) {
try {
// 文件地址可以直接copypath
InputStream fileInputStream = new FileInputStream("/Users/zhanghuilong/demo/config.properties");
HrsConfigService configService = HrsConfigFactory.readProperties(fileInputStream);
if (configService == null){
return;
}
Integer port = configService.getPort();
String url = configService.getUrl();
String userName = configService.getUserName();
String pwd = configService.getPwd();
Boolean off = configService.getOff();
String format = String.format("讀取配置信息,url: %s, username: %s, password: %s, port :%s, 開關:%s",
url, userName, pwd, port, off);
System.out.println( format );
} catch (FileNotFoundException e) {
System.out.println("文件不存在");
}
}
}
輸出:
調用 method = [getPort]
調用 method = [getUrl]
調用 method = [getUserName]
調用 method = [getPwd]
調用 method = [getOff]
讀取配置信息,url: http://www.hrsstd.com, username: zhanghuilong, password: root, port :8080, 開關:true
本文主要想簡單說明下 java 動態代理在實際工作中的應用 和實踐。