diff --git a/src/org/redkale/util/ResourceFactory.java b/src/org/redkale/util/ResourceFactory.java index 915792b85..178005a9c 100644 --- a/src/org/redkale/util/ResourceFactory.java +++ b/src/org/redkale/util/ResourceFactory.java @@ -175,7 +175,7 @@ public final class ResourceFactory { if (re == null) { map.put(name, new ResourceEntry(rs)); } else { - map.put(name, new ResourceEntry(rs, re.elements, autoSync)); + map.put(name, new ResourceEntry(rs, name, re.elements, autoSync)); } return re == null ? null : (A) re.value; } @@ -405,7 +405,7 @@ public final class ResourceFactory { this.elements = new CopyOnWriteArrayList<>(); } - public ResourceEntry(T value, final List elements, boolean sync) { + public ResourceEntry(T value, final String name, final List elements, boolean sync) { this.value = value; this.elements = elements == null ? new CopyOnWriteArrayList<>() : elements; if (sync && elements != null && !elements.isEmpty()) { @@ -433,11 +433,26 @@ public final class ResourceFactory { } } if (rs == null && classtype.isPrimitive()) rs = Array.get(Array.newInstance(classtype, 1), 0); + Object oldVal = null; + if (element.listener != null) { + try { + oldVal = element.field.get(dest); + } catch (Exception e) { + e.printStackTrace(); + } + } try { element.field.set(dest, rs); } catch (Exception e) { e.printStackTrace(); } + if (element.listener != null) { + try { + element.listener.invoke(dest, name, rs, oldVal); + } catch (Exception e) { + e.printStackTrace(); + } + } } } } @@ -445,16 +460,41 @@ public final class ResourceFactory { private static class ResourceElement { + private static final HashMap listenerMethods = new HashMap<>(); //不使用ConcurrentHashMap是因为value不能存null + public final WeakReference dest; - public final Field field; + public final Field field; //Resource 字段 public final Class fieldType; + public final Method listener; + public ResourceElement(T dest, Field field) { this.dest = new WeakReference(dest); this.field = field; this.fieldType = field.getType(); + Class t = dest.getClass(); + String tn = t.getName(); + this.listener = tn.startsWith("java.") || tn.startsWith("javax.") ? null : findListener(t); + } + + private static synchronized Method findListener(Class clazz) { + Class loop = clazz; + Method m = null; + do { + for (Method method : loop.getDeclaredMethods()) { + if (method.getAnnotation(ResourceListener.class) != null + && method.getParameterCount() == 3 + && String.class.isAssignableFrom(method.getParameterTypes()[0])) { + m = method; + m.setAccessible(true); + break; + } + } + } while ((loop = loop.getSuperclass()) != Object.class); + listenerMethods.put(clazz, m); + return m; } } diff --git a/src/org/redkale/util/ResourceListener.java b/src/org/redkale/util/ResourceListener.java new file mode 100644 index 000000000..a86a59487 --- /dev/null +++ b/src/org/redkale/util/ResourceListener.java @@ -0,0 +1,51 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.util; + +import java.lang.annotation.*; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * @Resource资源被更新时的监听事件。改注解只能标记在方法参数为(String name, T newVal, T oldVal)上。 + * + *
+ * public class Record {
+ *
+ *    @Resource(name = "record.id")
+ *    private int id;
+ *
+ *    @Resource(name = "record.name")
+ *    private String name;
+ *
+ *    @ResourceListener
+ *    private void changeResource(String name, Object newVal, Object oldVal) {
+ *        System.out.println("@Resource = " + name + " 资源变更:  newVal = " + newVal + ", oldVal = " + oldVal);
+ *    }
+ *
+ *    public static void main(String[] args) throws Exception {
+ *        ResourceFactory factory = ResourceFactory.root();
+ *        factory.register("record.id", "2345"); 
+ *        factory.register("record.name", "my old name"); 
+ *        Record record = new Record();
+ *        factory.inject(record);
+ *        factory.register("record.name", "my new name"); 
+ *   }
+ * 
+ * }
+ * 
+ * + *

+ * 详情见: http://redkale.org + * + * @author zhangjx + */ +@Documented +@Target({METHOD}) +@Retention(RUNTIME) +public @interface ResourceListener { + +} diff --git a/test/org/redkale/test/util/ResourceTest.java b/test/org/redkale/test/util/ResourceTest.java index 5460d5000..b35586607 100644 --- a/test/org/redkale/test/util/ResourceTest.java +++ b/test/org/redkale/test/util/ResourceTest.java @@ -15,35 +15,35 @@ import org.redkale.util.*; */ public class ResourceTest { -public static void main(String[] args) throws Exception { - ResourceFactory factory = ResourceFactory.root(); - factory.register("property.id", "2345"); //注入String类型的property.id - AService aservice = new AService(); - BService bservice = new BService("eeeee"); + public static void main(String[] args) throws Exception { + ResourceFactory factory = ResourceFactory.root(); + factory.register("property.id", "2345"); //注入String类型的property.id + AService aservice = new AService(); + BService bservice = new BService("eeeee"); - factory.register(aservice); //放进Resource池内,默认的资源名name为"" - factory.register(bservice); //放进Resource池内,默认的资源名name为"" + factory.register(aservice); //放进Resource池内,默认的资源名name为"" + factory.register(bservice); //放进Resource池内,默认的资源名name为"" - factory.inject(aservice); //给aservice注入id、bservice,bigint没有资源,所以为null - factory.inject(bservice); //给bservice注入id、aservice - System.out.println(aservice); //输出结果为:{id:"2345", intid: 2345, bigint:null, bservice:{name:eeeee}} - System.out.println(bservice); //输出结果为:{name:"eeeee", id: 2345, aserivce:{id:"2345", intid: 2345, bigint:null, bservice:{name:eeeee}}} + factory.inject(aservice); //给aservice注入id、bservice,bigint没有资源,所以为null + factory.inject(bservice); //给bservice注入id、aservice + System.out.println(aservice); //输出结果为:{id:"2345", intid: 2345, bigint:null, bservice:{name:eeeee}} + System.out.println(bservice); //输出结果为:{name:"eeeee", id: 2345, aserivce:{id:"2345", intid: 2345, bigint:null, bservice:{name:eeeee}}} - factory.register("seqid", 200); //放进Resource池内, 同时ResourceFactory会自动更新aservice的seqid值 - System.out.println(factory.find("seqid", int.class)); //输出结果为:200 - factory.register("bigint", new BigInteger("666666666666666")); //放进Resource池内, 同时ResourceFactory会自动更新aservice对象的bigint值 - System.out.println(aservice); //输出结果为:{id:"2345", intid: 2345, bigint:666666666666666, bservice:{name:eeeee}} 可以看出seqid与bigint值都已自动更新 + factory.register("seqid", 200); //放进Resource池内, 同时ResourceFactory会自动更新aservice的seqid值 + System.out.println(factory.find("seqid", int.class)); //输出结果为:200 + factory.register("bigint", new BigInteger("666666666666666")); //放进Resource池内, 同时ResourceFactory会自动更新aservice对象的bigint值 + System.out.println(aservice); //输出结果为:{id:"2345", intid: 2345, bigint:666666666666666, bservice:{name:eeeee}} 可以看出seqid与bigint值都已自动更新 - factory.register("property.id", "6789"); //更新Resource池内的id资源值, 同时ResourceFactory会自动更新aservice、bservice的id值 - System.out.println(aservice); //输出结果为:{id:"6789", intid: 6789, bigint:666666666666666, bservice:{name:eeeee}} - System.out.println(bservice); //输出结果为:{name:"eeeee", id: 6789, aserivce:{id:"6789", intid: 6789, bigint:666666666666666, bservice:{name:eeeee}}} + factory.register("property.id", "6789"); //更新Resource池内的id资源值, 同时ResourceFactory会自动更新aservice、bservice的id值 + System.out.println(aservice); //输出结果为:{id:"6789", intid: 6789, bigint:666666666666666, bservice:{name:eeeee}} + System.out.println(bservice); //输出结果为:{name:"eeeee", id: 6789, aserivce:{id:"6789", intid: 6789, bigint:666666666666666, bservice:{name:eeeee}}} - bservice = new BService("ffff"); - factory.register(bservice); //更新Resource池内name=""的BService资源, 同时ResourceFactory会自动更新aservice的bservice对象 - factory.inject(bservice); - System.out.println(aservice); //输出结果为:{id:"6789", intid: 6789, bigint:666666666666666, bservice:{name:ffff}} + bservice = new BService("ffff"); + factory.register(bservice); //更新Resource池内name=""的BService资源, 同时ResourceFactory会自动更新aservice的bservice对象 + factory.inject(bservice); + System.out.println(aservice); //输出结果为:{id:"6789", intid: 6789, bigint:666666666666666, bservice:{name:ffff}} -} + } } @@ -57,6 +57,11 @@ class BService { private String name = ""; + @ResourceListener + private void changeResource(String name, Object newVal, Object oldVal) { + System.out.println("@Resource = " + name + " 资源变更: newVal = " + newVal + ", oldVal = " + oldVal); + } + @java.beans.ConstructorProperties({"name"}) public BService(String name) { this.name = name;