为了巩固 CGLib 的知识下面我们实现一个稍微复杂一点的例子 例请实现一个拦截器使其能够检测一个 JavaBean 的哪些字段改变了 ( )首先定义一个 JavaBean public class PersonInfo { private String name; private String email; private int age; private String address; public String getEmail() { return email; } public void setEmail(String email) { thisemail = email; } public String getName() { return name; } public void setName(String name) { thisname = name; } public String getAddress() { return address; } public void setAddress(String address) { thisaddress = address; } public int getAge() { return age; } public void setAge(int age) { thisage = age; } } ( )定义一个 MethodInterceptor 这一步是最关键的 import javalangreflectMethod; import javautilCollections; import javautilHashSet; import javautilSet; import netsfcglibproxyMethodInterceptor; import netsfcglibproxyMethodProxy; public class JavaBeanDataChangeInterceptor implements MethodInterceptor { private static final String SET = set; private Set changedPropSet; public JavaBeanDataChangeInterceptor() { changedPropSet = new HashSet(); } public Object intercept(Object obj Method method Object[] args MethodProxy proxy) throws Throwable { String name = methodgetName(); if (namestartsWith(SET)) { String s = namesubstring(SETlength()); changedPropSetadd(s); } return proxyinvokeSuper(obj args); } public Set getChangedPropSet() { return CollectionsunmodifiableSet(changedPropSet); } public void reset() { changedPropSetclear(); } } 定义一个集合 changedPropSet 用来存放修改了的字段名增加了一个方法 reset 用来清空此集合增加了一个 getChangedPropSet 方法用来供外界得到修改了的字段为了防止调用者对 changedPropSet 做修改因此我们采用 CollectionsunmodifiableSet 对返回的集合进行不可修改的修饰 在 intercept 方法中我们判断如果被调用的方法以 set 开头则把此字段名放入 changedPropSet 集合中 ( )定义剖析用工具类 import netsfcglibproxyCallback; import netsfcglibproxyFactory; public class JavaBeanInterceptorUtils { public static JavaBeanDataChangeInterceptor getInterceptor( Object obj) { if (!(obj instanceof Factory)) { return null; } Factory f = (Factory) obj; Callback[] callBacks = fgetCallbacks(); for (int i = n = callBackslength; i < n; i++) { Callback callBack = callBacks[i]; if (callBack instanceof JavaBeanDataChangeInterceptor) { return (JavaBeanDataChangeInterceptor) callBack; } } return null; } } 这个 JavaBeanInterceptorUtils 只有一个方法 getInterceptor 这个方法用于从一个被 CGLib 代理的 JavaBean 中取出拦截器 JavaBeanDataChangeInterceptor 前边提到了 CGLib 实现拦截的方式就是生成被拦截类的子类这个子类实现了 netsfcglibproxyFactory 接口这个接口中有一个非常重要的方法 getCallbacks() 通过这个方法我们可以得到所有的拦截器 ( ) 主程序 public class MainApp { public static void main(String[] args) { Enhancer enhancer = new Enhancer(); enhancersetSuperclass(PersonInfoclass); enhancersetCallback(new JavaBeanDataChangeInterceptor()); PersonInfo info = (PersonInfo) enhancercreate(); // 对生成的 JavaBean 做一些初始化 infosetAddress( 地址 ); infosetAge(); infosetName(tom); // 得到拦截器 JavaBeanDataChangeInterceptor interceptor = JavaBeanInterceptorUtils getInterceptor(info); // 复位修改字段记录集合 interceptorreset(); // 对 JavaBean 做一些修改 editPersonInf(info); // 得到修改了的字段 Iterator it = interceptorgetChangedPropSet(erator(); while (ithasNext()) { Systemoutprintln(itnext()); } } private static void editPersonInf(PersonInfo info) { infosetName(Jim); infosetAddress(NY Street); } } 运行结果 Address Name 这个变化字段拦截器是有一定实际意义的比如可以用来实现只保存修改了的字段以提高效率等功能 很多资料中都说如果要使用 JDK Proxy 被代理的对象的类必须要实现接口这种说法是不严谨的从上边的例子我们可以看出正确的说法应该是如果要使用 JDK Proxy 那么我们要通过代理调用的方法必须定义在一个接口中面向接口编程而不是面向实现编程是 OOP 开发中的一条基本原则因此这种限制并不会对我们的开发造成障碍 |