在我看Stackoverflow的时候,我碰到了这样一个有趣的问题:如何将Java属性文件Properties File绑定到Java接口。这个想法简单却有用!
当我们想在应用中使用常量的时候,我们只需简单地用一下loginConstants.appDescription().我们的应用框架会为这个接口创建一个动态代理。我们所要做的仅仅是调用这个方法,得到默认值或从属性文件中得到值。
基本上是这样做:你创建一个带有相关方法的接口,然后用@Key和@DefaultStringValue注释这些方法。
免责声明:不能用于生产环境。代码仅供参考。下面代码还需优化。
下面是代码样本。
package net.viralpatel;
import net.viralpatel.annotations.DefaultStringValue;
import net.viralpatel.annotations.Key;
interface LoginConstants extends Constants {
@DefaultStringValue("Wellcome to my super app")
@Key("appDescription")
String appDescription();
@DefaultStringValue("Ok")
@Key("okButtonLabel")
String okButtonLabel();
}
public class Main {
public static void main(String[] args) {
LoginConstants constants = DynamicProperty.create(LoginConstants.class);
System.out.println(constants.appDescription());
System.out.println(constants.okButtonLabel());
}
}
输出:
Wellcome to my super app
This is OK
一下是用Java反射实现的动态代理代码,能起到神奇的作用。
package net.viralpatel.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Key {
public String value();
}
package net.viralpatel.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface DefaultStringValue {
public String value();
}
package net.viralpatel;
import java.lang.reflect.Proxy;
public class DynamicProperty {
public static <T extends Constants> T create(Class<T> clazz) {
T object = (T) Proxy.newProxyInstance(clazz
.getClassLoader(), new Class[] { clazz },
new Handler(clazz));
return object;
}
}
package net.viralpatel;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import net.viralpatel.annotations.DefaultStringValue;
import net.viralpatel.annotations.Key;
public class Handler implements InvocationHandler {
Object obj;
public Handler(Object obj) {
this.obj = obj;
}
public Object invoke(Object proxy, Method m, Object[] args)
throws Throwable {
String key = null;
String defaultValue = null;
try {
Annotation[] annotations = m.getAnnotations();
for (Annotation annotation : annotations) {
if (annotation instanceof Key) {
key = ((Key)annotation).value();
} else if (annotation instanceof DefaultStringValue) {
defaultValue = ((DefaultStringValue)annotation).value();
}
}
String ret = PropertyLoader.get(key);
return (null == ret) ? defaultValue : ret;
// result = m.invoke(obj, args);
} catch (Exception e) {
// We could also put some code here if we want to do
// anything special in case an Exception is thrown from
// the inside of invoked method.
throw e;
}
}
}
package net.viralpatel;
public interface Constants {
//marker
}
package net.viralpatel;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
public class PropertyLoader {
private static Properties prop = null;
public static String get(String key) {
if (null == prop) {
init();
}
return (String) prop.get(key);
}
private static void init() {
prop = new Properties();
InputStream in = Properties.class
.getResourceAsStream("/net/viralpatel/config.properties");
try {
prop.load(in);
} catch (IOException e) {
e.printStackTrace();
}
}
}
原文: http://viralpatel.net/blogs/dynamic-property-loader-using-java-dynamic-proxy-pattern/
源代码:http://pan.baidu.com/share/link?shareid=553186681&uk=3878681452