快捷搜索:

CGLib实现变化字段探测的供能

为了巩固 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

{

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 开拓中的一条基滥觞基本则,是以这种限定并不会对我们的开拓造成障碍。

您可能还会对下面的文章感兴趣: