为了巩固
				CGLib
				的知识,下面我们实现一个稍微复杂一点的例子。
		
		
				例、请实现一个拦截器,使其能够检测一个
				JavaBean
				的哪些字段改变了。
		
		
				(
				1
				)首先定义一个
				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)
						
				
		
		
				
						
								
										     {
						
				
		
		
				
						
								
										         this.email = email;
						
				
		
		
				
						
								
										     }
						
				
		
		
				
						
								 
						
				
		
		
				
						
								
										     public String getName()
						
				
		
		
				
						
								
										     {
						
				
		
		
				
						
								
										         return name;
						
				
		
		
				
						
								
										     }
						
				
		
		
				
						
								 
						
				
		
		
				
						
								
										     public void setName(String name)
						
				
		
		
				
						
								
										     {
						
				
		
		
				
						
								
										         this.name = name;
						
				
		
		
				
						
								
										     }
						
				
		
		
				
						
								 
						
				
		
		
				
						
								
										     public String getAddress()
						
				
		
		
				
						
								
										     {
						
				
		
		
				
						
								
										         return address;
						
				
		
		
				
						
								
										     }
						
				
		
		
				
						
								 
						
				
		
		
				
						
								
										     public void setAddress(String address)
						
				
		
		
				
						
								
										     {
						
				
		
		
				
						
								
										         this.address = address;
						
				
		
		
				
						
								
										     }
						
				
		
		
				
						
								 
						
				
		
		
				
						
								
										     public int getAge()
						
				
		
		
				
						
								
										     {
						
				
		
		
				
						
								
										         return age;
						
				
		
		
				
						
								
										     }
						
				
		
		
				
						
								 
						
				
		
		
				
						
								
										     public void setAge(int age)
						
				
		
		
				
						
								
										     {
						
				
		
		
				
						
								
										         this.age = age;
						
				
		
		
				
						
								
										     }
						
				
		
		
				
						}
				
		
		
				(
				2
				)定义一个
				MethodInterceptor
				,这一步是最关键的
				。
		
		
				
						import java.lang.reflect.Method;
				
		
		
				
						import java.util.Collections;
				
		
		
				
						import java.util.HashSet;
				
		
		
				
						import java.util.Set;
				
		
		
				
						
								 
						
				
		
		
				
						import net.sf.cglib.proxy.MethodInterceptor;
				
		
		
				
						import net.sf.cglib.proxy.MethodProxy;
				
		
		
				
						
								 
						
				
		
		
				
						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 = method.getName();
						
				
		
		
				
						
								
										         if (name.startsWith(SET))
						
				
		
		
				
						
								
										         {
						
				
		
		
				
						
								
										              String s = name.substring(SET.length());
						
				
		
		
				
						
								
										              changedPropSet.add(s);
						
				
		
		
				
						
								
										         }
						
				
		
		
				
						
								
										         return proxy.invokeSuper(obj, args);
						
				
		
		
				
						
								
										     }
						
				
		
		
				
						
								 
						
				
		
		
				
						
								
										     public Set getChangedPropSet()
						
				
		
		
				
						
								
										     {
						
				
		
		
				
						
								
										         return Collections.unmodifiableSet(changedPropSet);
						
				
		
		
				
						
								
										     }
						
				
		
		
				
						
								 
						
				
		
		
				
						
								
										     public void reset()
						
				
		
		
				
						
								
										     {
						
				
		
		
				
						
								
										         changedPropSet.clear();
						
				
		
		
				
						
								
										     }
						
				
		
		
				
						}
				
		
		
				定义一个集合
				changedPropSet
				用来存放修改了的字段名,增加了一个方法
				reset
				用来清空此集合,增加了一个
				getChangedPropSet
				方法用来供外界得到修改了的字段,为了防止调用者对
				changedPropSet
				做修改,因此我们采用
				Collections.unmodifiableSet
				对返回的集合进行不可修改的修饰。
		
		
				在
				intercept
				方法中,我们判断如果被调用的方法以
				set
				开头,则把此字段名放入
				changedPropSet
				集合中。
		
		
				(
				3
				)定义剖析用工具类。
		
		
				
						import net.sf.cglib.proxy.Callback;
				
		
		
				
						import net.sf.cglib.proxy.Factory;
				
		
		
				
						
								 
						
				
		
		
				
						public class JavaBeanInterceptorUtils
				
		
		
				
						{
				
		
		
				
						
								
										     public static JavaBeanDataChangeInterceptor getInterceptor(
						
				
		
		
				
						
								
										              Object obj)
						
				
		
		
				
						
								
										     {
						
				
		
		
				
						
								
										         if (!(obj instanceof Factory))
						
				
		
		
				
						
								
										         {
						
				
		
		
				
						
								
										              return null;
						
				
		
		
				
						
								
										         }
						
				
		
		
				
						
								
										         Factory f = (Factory) obj;
						
				
		
		
				
						
								
										         Callback[] callBacks = f.getCallbacks();
						
				
		
		
				
						
								
										         for (int i = 0, n = callBacks.length; i < n; i++)
						
				
		
		
				
						
								
										         {
						
				
		
		
				
						
								
										              Callback callBack = callBacks[i];
						
				
		
		
				
						
								
										              if (callBack instanceof JavaBeanDataChangeInterceptor)
						
				
		
		
				
						
								
										              {
						
				
		
		
				
						
								
										                   return (JavaBeanDataChangeInterceptor) callBack;
						
				
		
		
				
						
								
										              }
						
				
		
		
				
						
								
										         }
						
				
		
		
				
						
								
										         return null;
						
				
		
		
				
						
								
										     }
						
				
		
		
				
						}
				
		
		
				这个
				JavaBeanInterceptorUtils
				只有一个方法
				getInterceptor
				,这个方法用于从一个被
				CGLib
				代理的
				JavaBean
				中取出拦截器
				JavaBeanDataChangeInterceptor
				。
		
		
				前边提到了,
				CGLib
				实现拦截的方式就是生成被拦截类的子类,这个子类实现了
				net.sf.cglib.proxy.Factory
				接口,这个接口中有一个非常重要的方法
				getCallbacks()
				,通过这个方法我们可以得到所有的拦截器
				。
				
						
						
				
		
		
				(
				4
				)
				主程序
				
						
						
				
		
		
				
						public class MainApp
				
		
		
				
						{
				
		
		
				
						
								
										     public static void main(String[] args)
						
				
		
		
				
						
								
										     {
						
				
		
		
				
						
								
										         Enhancer enhancer = new Enhancer();
						
				
		
		
				
						
								
										         enhancer.setSuperclass(PersonInfo.class);
						
				
		
		
				
						
								
										         enhancer.setCallback(new JavaBeanDataChangeInterceptor());
						
				
		
		
				
						
								 
						
				
		
		
				
						
								
										         PersonInfo info = (PersonInfo) enhancer.create();
						
				
		
		
				
						
								
										         // 
						
						对生成的
						
								JavaBean
						
						做一些初始化
				
		
		
				
						
								
										         info.setAddress("
						
						地址
						
								1");
						
				
		
		
				
						
								
										         info.setAge(21);
						
				
		
		
				
						
								
										         info.setName("tom");
						
				
		
		
				
						
								 
						
				
		
		
				
						
								
										         // 
						
						得到拦截器
				
		
		
				
						
								
										         JavaBeanDataChangeInterceptor interceptor = JavaBeanInterceptorUtils
						
				
		
		
				
						
								
										                   .getInterceptor(info);
						
				
		
		
				
						
								
										         // 
						
						复位修改字段记录集合
				
		
		
				
						
								
										         interceptor.reset();
						
				
		
		
				
						
								 
						
				
		
		
				
						
								
										         // 
						
						对
						
								JavaBean
						
						做一些修改
				
		
		
				
						
								
										         editPersonInf(info);
						
				
		
		
				
						
								 
						
				
		
		
				
						
								
										         // 
						
						得到修改了的字段
				
		
		
				
						
								
										         Iterator it = interceptor.getChangedPropSet().iterator();
						
				
		
		
				
						
								
										         while (it.hasNext())
						
				
		
		
				
						
								
										         {
						
				
		
		
				
						
								
										              System.out.println(it.next());
						
				
		
		
				
						
								
										         }
						
				
		
		
				
						
								
										     }
						
				
		
		
				
						
								 
						
				
		
		
				
						
								
										     private static void editPersonInf(PersonInfo info)
						
				
		
		
				
						
								
										     {
						
				
		
		
				
						
								
										         info.setName("Jim");
						
				
		
		
				
						
								
										         info.setAddress("N.Y Street");
						
				
		
		
				
						
								
										     }
						
				
		
		
				
						
								}    
						
				
		
		
				
						运行结果:
				
		
		
				
						Address
				
		
		
				
						Name
				
		
		
				
						 
				
		
		
				这个“变化字段拦截器”是有一定实际意义的,比如可以用来实现“只保存修改了的字段以提高效率”等功能
				。
		
		
				
						 
				
		
		
				很多资料中都说如果要使用
				JDK Proxy
				,被代理的对象的类必须要实现接口,这种说法是不严谨的。从上边的例子我们可以看出,正确的说法应该是:如果要使用
				JDK Proxy
				,那么我们要通过代理调用的方法必须定义在一个接口中。“面向接口编程而不是面向实现编程”是
				OOP
				开发中的一条基本原则,因此这种限制并不会对我们的开发造成障碍。