查看“动态代理、CGLIB 与 切面编程”的源代码
←
动态代理、CGLIB 与 切面编程
跳到导航
跳到搜索
因为以下原因,您没有权限编辑本页:
您请求的操作仅限属于该用户组的用户执行:
用户
您可以查看和复制此页面的源代码。
[[category:Java]] == 关于代理 == 代理,简单说就是:不直接操作对象,而使用代理对象来完成操作。 通过代理对象,可以'''对原对象进行方法扩展'''。 代理又可以分为: # 静态代理:通过聚合、继承的方式生成代理对象; #* 代理关系在编译时就确定了 # 动态代理: #* 运行期动态生成代理对象; ## '''Java动态代理''': ##* 只能够对'''接口'''(目标类必须实现接口)进行代理 —— 因为所有生成的代理类的父类为 Proxy,而 Java 类继承机制不允许多重继承; ##* 类的生成过程更高效 —— 使用 Java 原生的'''反射''' API 进行操作; ##* “代理类”为 '''Proxy 的子类'''; ## '''CGLIB''': ##* 能够对'''普通类'''(没有实现接口的类)进行代理; ##* 类的执行过程更高效 —— 使用 '''ASM''' 框架直接对字节码进行操作; ##* “代理类”为'''“目标类”的子类'''; ## '''AspectJ''':(SpringFramework 的 '''AOP''' 基于此实现)。 == Java动态代理 == * 参见:'''[http://wiki.eijux.com/%E6%A0%B8%E5%BF%83%E6%8A%80%E6%9C%AF%EF%BC%9A%E6%8E%A5%E5%8F%A3%E3%80%81lambda%E8%A1%A8%E8%BE%BE%E5%BC%8F%E4%B8%8E%E5%86%85%E9%83%A8%E7%B1%BB#.E5.86.85.E9.83.A8.E7.B1.BB JavaCore:接口(代理)]''' === 示例 === Java中动态代理的实现,关键在于:“Proxy”、“InvocationHandler”的关联。 注意:invoke 方法的自动调用。 以实例分析: # 抽象接口: #: <syntaxhighlight lang="java" line highlight=""> //抽象角色(动态代理只能代理接口) public interface Subject { public void request(); } </syntaxhighlight> # 抽象接口实现: #: <syntaxhighlight lang="java" line highlight=""> //真实角色:实现了Subject的request()方法 public class RealSubject implements Subject{ public void request(){ System.out.println("From real subject."); } } </syntaxhighlight> # “InvocationHandler”接口的实现类: #: <syntaxhighlight lang="java" line highlight="20"> //实现了InvocationHandler public class DynamicSubject implements InvocationHandler { private Object obj;//这是动态代理的好处,被封装的对象是Object类型,接受任意类型的对象 public DynamicSubject() { } public DynamicSubject(Object obj) { this.obj = obj; } //这个方法不是我们显示的去调用 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("before calling " + method); method.invoke(obj, args); System.out.println("after calling " + method); return null; } } </syntaxhighlight> #* “invoke”方法进行代理处理逻辑,并调用对应的接口方法; #* 使用“method.invoke(obj, args);”,而'''不能使用“method.invoke(proxy, args); ”'''(后者将会导致死循环); #** “obj”:类型为“RealSubject”(由下面测试类中,初始化“DynamicSubject”的参数而来): #** “proxy”:就是代理实例“$Proxy0”: #**:“method.invoke(proxy, args);”将会调用“$Proxy0”的method方法; #**: 而“$Proxy0”的method方法,会执行“super.h.invoke(this, m3, null);”,即调用此处,从而调用陷入死循环; # 测试类: #: <syntaxhighlight lang="java" line highlight="5,6,34"> //客户端:生成代理实例,并调用了request()方法 public class Client { public static void main(String[] args) throws Throwable{ Subject rs = new RealSubject();//这里指定被代理类 InvocationHandler ds = new DynamicSubject(rs); Class<?> cls = rs.getClass(); //以下是一次性生成代理 Subject subject=(Subject) Proxy.newProxyInstance(cls.getClassLoader(),cls.getInterfaces(), ds); //这里可以看出subject的Class类是$Proxy0,这个$Proxy0类继承了Proxy,实现了Subject接口 System.out.println("subject的Class类是:"+subject.getClass().toString()); System.out.println("subject的父类是:"+subject.getClass().getSuperclass()); System.out.print("\n"+"subject实现的接口是:"); Class<?>[] interfaces=subject.getClass().getInterfaces(); for(Class<?> i:interfaces){ System.out.print(i.getName()+", "); } System.out.print("\n"+"subject中的属性有:"); Field[] field=subject.getClass().getDeclaredFields(); for(Field f:field){ System.out.print(f.getName()+", "); } System.out.print("\n"+"subject中的方法有:"); Method[] method=subject.getClass().getDeclaredMethods(); for(Method m:method){ System.out.print(m.getName()+", "); } System.out.println("\n\n"+"运行结果为:"); subject.request(); } } </syntaxhighlight> #: 运行结果如下: #: <syntaxhighlight lang="java" line highlight=""> subject的Class类是:class com.sun.proxy.$Proxy0 subject的父类是:class java.lang.reflect.Proxy subject实现的接口是:Test1.Subject, subject中的属性有:m1, m2, m3, m0, subject中的方法有:equals, toString, hashCode, request, 运行结果为: before calling public abstract void Test1.Subject.request() From real subject. after calling public abstract void Test1.Subject.request() </syntaxhighlight> #* 如果初始化“DynamicSubject”时,传入参数不是“RealSubject”类型,则,DynamicSubject中的“method.invoke(obj, args); ”将不能执行: #*: 错误信息:“'''object is not an instance of declaring class'''” === 代码分析 === * “Proxy”的部分源码: *: <syntaxhighlight lang="java" line highlight=""> class Proxy{ InvocationHandler h=null; protected Proxy(InvocationHandler h) { this.h = h; } ... public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) } </syntaxhighlight> #* Proxy 会生成一个“'''由loader加载'''”、“'''继承于Proxy'''”、“'''实现了interfaces等接口'''”的代理类“$Proxy0”; #* Proxy 会将'''“InvocationHandler”实例保存在属性'''中; #* * 生成的“$Proxy0”: *: <syntaxhighlight lang="java" line highlight="9,12,15,18,35,44,52,63"> public final class $Proxy0 extends Proxy implements Subject { private static Method m1; private static Method m0; private static Method m3; private static Method m2; static { try { m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") }); m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]); m3 = Class.forName("***.RealSubject").getMethod("request", new Class[0]); m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]); } catch (NoSuchMethodException nosuchmethodexception) { throw new NoSuchMethodError(nosuchmethodexception.getMessage()); } catch (ClassNotFoundException classnotfoundexception) { throw new NoClassDefFoundError(classnotfoundexception.getMessage()); } } //static public $Proxy0(InvocationHandler invocationhandler) { super(invocationhandler); } @Override public final boolean equals(Object obj) { try { return ((Boolean) super.h.invoke(this, m1, new Object[] { obj })) .booleanValue(); } catch (Throwable throwable) { throw new UndeclaredThrowableException(throwable); } } @Override public final int hashCode() { try { return ((Integer) super.h.invoke(this, m0, null)).intValue(); } catch (Throwable throwable) { throw new UndeclaredThrowableException(throwable); } } public final void request() { try { super.h.invoke(this, m3, null); return; } catch (Error e) { } catch (Throwable throwable) { throw new UndeclaredThrowableException(throwable); } } @Override public final String toString() { try { return (String) super.h.invoke(this, m2, null); } catch (Throwable throwable) { throw new UndeclaredThrowableException(throwable); } } } </syntaxhighlight> ** 其中“m1”、“m0”、“m3”、“m2”是“Method”类型的字段,表示“$Proxy0”中方法所'''对应的原方法''';包括: **# 继承于“Object”的“equals”(m1)、“hashCode”(m0)、“toString”(m2) **# 实现“Subject”的“request”(m3); ** “$Proxy0”的方法实现:“'''super.h.invoke(this, m3, null);'''”: **# 调用父类的“h”(“InvocationHandler”实例)的“invoke”方法;(“invoke”中进行代理处置,并调用原始方法) **# 参数:“this”($Proxy0)、“m2”(原始方法)、“null”(方法参数) == AspectJ == * 参见:'''[[Spring:AOP]]''' == CGLIB == CGLIB('''<big>Code Generation Library</big>'''),是一个功能强大,高性能的代码生成包。 * 使用CGLib实现动态代理,完全'''不受“被代理类必须实现接口”的限制'''; * CGLib底层采用ASM字节码生成框架,使用'''字节码技术生成代理类''',比使用Java反射效率要高。 === 原理 === # 动态生成一个'''目标类的子类''',子类重写目标类的“所有非 Final”的方法。 # 在子类中采用'''方法拦截'''的技术,拦截所有父类方法的调用,并织入横切逻辑。 * 为没有实现接口的类提供代理,比于“JDK 动态代理”(只能代理接口)更加强大; * 不能代理 Final 方法; === CGLIB组成结构 === :[[File:CGLIB组成结构.png|400px]] CGLIB 底层使用了'''ASM'''(一个短小精悍的字节码操作框架)来操作字节码生成新的类。 * 因为使用字节码技术生成代理类,所以 CGLIB 比采用“Java反射”的“JDK 动态代理”更快; * 关于“ASM”: ** 除了CGLIB库外,脚本语言(如:“Groovy”、“BeanShell”)也使用ASM生成字节码; ** ASM使用类似SAX的解析器来实现高性能; **(如果直接使用ASM,需要对Java字节码非常了解) === jar包 === * “cglib-nodep-2.2.jar”:使用nodep包不需要关联asm的jar包,jar包内部包含asm的类. * “cglib-2.2.jar”:使用此jar包需要关联asm的jar包,否则运行时报错. === 类库 === CGLIB 类库: * “net.sf.cglib.core”:底层字节码处理类,他们大部分与ASM有关系; * “net.sf.cglib.transform”:编译期或运行期类和类文件的转换; * “net.sf.cglib.proxy”:实现创建代理和方法拦截器的类; * “net.sf.cglib.reflect”:实现快速反射和C#风格代理的类; * “net.sf.cglib.util”:集合排序等工具类; * “net.sf.cglib.beans”:JavaBean相关的工具类; === 常用的API === 见:<big>'''[https://blog.csdn.net/danchu/article/details/70238002 CGLIB(Code Generation Library)详解]'''</big> {| class="wikitable" ! style="width: 5%;"| 命令 ! style="width: 45%;"| 说明 ! style="width: 50%;"| 示例 |- | '''Enhancer''' | Enhancer创建一个被代理对象的子类并且拦截所有的方法调用(包括从Object中继承的toString和hashCode方法) * 作用类似Proxy类;但Enhancer既能够代理普通的class,也能够代理接口;(不能代理final方法) # “Enhancer.setSuperclass()”:设置父类型; # “Enhancer.create(Object…)”:创建增强对象; # “Enhancer.createClass()”:创建字节码(.class); # “Enhancer.setCallback()”:设置回调; #* “'''InvocationHandler'''”可以作为回调,但必须防止死循环; #*:(invoke中调用的任何原代理类方法,均会重新代理到invoke方法中) #* “'''MethodInterceptor'''”可以作为回调,且不会出现死循环; * 如果只想对特定的方法进行拦截,对其他的方法直接放行: *: “enhancer.setCallbackFilter(callbackHelper);” | <syntaxhighlight lang="java" line highlight="7-9,11,13,18"> public class SampleClass { public void test(){ System.out.println("hello world"); } public static void main(String[] args) { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(SampleClass.class); enhancer.setCallback(new MethodInterceptor() { @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("before method run..."); Object result = proxy.invokeSuper(obj, args); System.out.println("after method run..."); return result; } }); SampleClass sample = (SampleClass) enhancer.create(); sample.test(); } } </syntaxhighlight> 输出: <syntaxhighlight lang="xml"> before method run... hello world after method run... </syntaxhighlight> |- | '''ImmutableBean''' | 不可变的Bean * ImmutableBean允许创建一个原来对象的包装类,这个包装类是'''不可变的''',任何改变底层对象的包装类操作都会抛出'''IllegalStateException'''。 * 但是可以通过直接操作底层对象来改变包装类对象。 | <syntaxhighlight lang="java"> public class SampleBean { private String value; public SampleBean() { } public SampleBean(String value) { this.value = value; } public String getValue() { return value; } public void setValue(String value) { this.value = value; } } </syntaxhighlight> <syntaxhighlight lang="java"> @Test(expected = IllegalStateException.class) public void testImmutableBean() throws Exception{ SampleBean bean = new SampleBean(); bean.setValue("Hello world"); SampleBean immutableBean = (SampleBean) ImmutableBean.create(bean); //创建不可变类 Assert.assertEquals("Hello world",immutableBean.getValue()); bean.setValue("Hello world, again"); //可以通过底层对象来进行修改 Assert.assertEquals("Hello world, again", immutableBean.getValue()); immutableBean.setValue("Hello cglib"); //直接修改将throw exception } </syntaxhighlight> |- | '''Bean generator''' | cglib提供的一个操作bean的工具,使用它能够在运行时动态的创建一个bean。 | <syntaxhighlight lang="java"> @Test public void testBeanGenerator() throws Exception{ BeanGenerator beanGenerator = new BeanGenerator(); beanGenerator.addProperty("value",String.class); Object myBean = beanGenerator.create(); Method setter = myBean.getClass().getMethod("setValue",String.class); setter.invoke(myBean,"Hello cglib"); Method getter = myBean.getClass().getMethod("getValue"); Assert.assertEquals("Hello cglib",getter.invoke(myBean)); } </syntaxhighlight> |- | '''Bean Copier''' | cglib提供的能够从一个bean复制到另一个bean中,而且其还提供了一个转换器,用来在转换的时候对bean的属性进行操作。 | <syntaxhighlight lang="java"> public class OtherSampleBean { private String value; public String getValue() { return value; } public void setValue(String value) { this.value = value; } } </syntaxhighlight> <syntaxhighlight lang="java"> @Test public void testBeanCopier() throws Exception{ BeanCopier copier = BeanCopier.create(SampleBean.class, OtherSampleBean.class, false);//设置为true,则使用converter SampleBean myBean = new SampleBean(); myBean.setValue("Hello cglib"); OtherSampleBean otherBean = new OtherSampleBean(); copier.copy(myBean, otherBean, null); //设置为true,则传入converter指明怎么进行转换 assertEquals("Hello cglib", otherBean.getValue()); } </syntaxhighlight> |- | '''BulkBean''' | 复制bean,BulkBean将copy的动作拆分为getPropertyValues和setPropertyValues两个方法,允许自定义处理属性; * 避免每次进行BulkBean.create创建对象,一般将其声明为static的 * 应用场景:针对特定属性的get,set操作,一般适用通过xml配置注入和注出的属性,运行时才确定处理的Source,Target类,只需要关注属性名即可。 | <syntaxhighlight lang="java"> @Test public void testBulkBean() throws Exception{ BulkBean bulkBean = BulkBean.create(SampleBean.class, new String[]{"getValue"}, new String[]{"setValue"}, new Class[]{String.class}); SampleBean bean = new SampleBean(); bean.setValue("Hello world"); Object[] propertyValues = bulkBean.getPropertyValues(bean); assertEquals(1, bulkBean.getPropertyValues(bean).length); assertEquals("Hello world", bulkBean.getPropertyValues(bean)[0]); bulkBean.setPropertyValues(bean,new Object[]{"Hello cglib"}); assertEquals("Hello cglib", bean.getValue()); } </syntaxhighlight> |- | '''BeanMap''' | BeanMap类实现了Java Map,将一个bean对象中的所有属性转换为一个String-to-Obejct的Java Map | <syntaxhighlight lang="java"> @Test public void testBeanMap() throws Exception{ BeanGenerator generator = new BeanGenerator(); generator.addProperty("username",String.class); generator.addProperty("password",String.class); Object bean = generator.create(); Metod setUserName = bean.getClass().getMethod("setUsername", String.class); Method setPassword = bean.getClass().getMethod("setPassword", String.class); setUserName.invoke(bean, "admin"); setPassword.invoke(bean,"password"); BeanMap map = BeanMap.create(bean); Assert.assertEquals("admin", map.get("username")); Assert.assertEquals("password", map.get("password")); } </syntaxhighlight> |- | keyFactory | eyFactory类用来动态生成接口的实例,接口需要只包含一个newInstance方法,返回一个Object。keyFactory为构造出来的实例动态生成了Object.equals和Object.hashCode方法,能够确保相同的参数构造出的实例为单例的。 | <syntaxhighlight lang="java"> </syntaxhighlight> |- | | | <syntaxhighlight lang="java"> </syntaxhighlight> |- | | | <syntaxhighlight lang="java"> </syntaxhighlight> |- | | | <syntaxhighlight lang="java"> </syntaxhighlight> |- | | | <syntaxhighlight lang="java"> </syntaxhighlight> |- | | | <syntaxhighlight lang="java"> </syntaxhighlight> |- | | | <syntaxhighlight lang="java"> </syntaxhighlight> |- | '''Parallel Sorter''' | (并行排序器) | <syntaxhighlight lang="java"> </syntaxhighlight> |- | '''FastClass''' | 对Class对象进行特定的处理,比如通过数组保存method引用,因此FastClass引出了一个index下标的新概念,比如getIndex(String name, Class[] parameterTypes)就是以前的获取method的方法。 * 通过数组存储method,constructor等class信息,从而将原先的反射调用,转化为class.index的直接调用,从而体现所谓的FastClass。 | <syntaxhighlight lang="java"> @Test public void testFastClass() throws Exception{ FastClass fastClass = FastClass.create(SampleBean.class); FastMethod fastMethod = fastClass.getMethod("getValue",new Class[0]); SampleBean bean = new SampleBean(); bean.setValue("Hello world"); assertEquals("Hello world",fastMethod.invoke(bean, new Object[0])); } </syntaxhighlight> |} <syntaxhighlight lang="java"> </syntaxhighlight> === 使用 === # 被代理类:(没有接口实现) #: <syntaxhighlight lang="java"> public class TargetObject { public String method1(String paramName) { return paramName; } public int method2(int count) { return count; } public int method3(int count) { return count; } @Override public String toString() { return "TargetObject []"+ getClass(); } } </syntaxhighlight> # 拦截器: #* (类似于JDK中的“InvocationHandler”接口。) #* 在调用目标方法时,CGLib会回调“'''MethodInterceptor'''”接口方法拦截,来实现代理逻辑; #: <syntaxhighlight lang="java" highlight="5,17"> import java.lang.reflect.Method; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; public class TargetInterceptor implements MethodInterceptor{ /** * 重写方法拦截在方法前和方法后加入业务 * Object obj为目标对象 * Method method为目标方法 * Object[] params 为参数, * MethodProxy proxy CGlib方法代理对象 */ @Override public Object intercept(Object obj, Method method, Object[] params, MethodProxy proxy) throws Throwable { System.out.println("调用前"); Object result = proxy.invokeSuper(obj, params); System.out.println(" 调用后"+result); return result; } } </syntaxhighlight> #*【与“InvocationHandler”接口的“invoke”方法有点类似】 #* “obj”:生成的代理实例; #* “method”:被代理类(即,TargetObject)的方法; #* “params”:方法参数; #* “proxy”:生成的代理实例的方法; #* “proxy.invokeSuper(obj, params);”:调用代理类方法所对应的,父类(即,被代理类)的方法; # 生成动态代理类: #: <syntaxhighlight lang="java" highlight="8-10,12"> import net.sf.cglib.proxy.Callback; import net.sf.cglib.proxy.CallbackFilter; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.NoOp; public class TestCglib { public static void main(String args[]) { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(TargetObject.class); enhancer.setCallback(new TargetInterceptor()); TargetObject targetObject2=(TargetObject)enhancer.create(); System.out.println(targetObject2); System.out.println(targetObject2.method1("mmm1")); System.out.println(targetObject2.method2(100)); System.out.println(targetObject2.method3(200)); } } </syntaxhighlight> #* Enhancer类是CGLib中的一个字节码增强器,用于对类的扩展处理;步骤为: ## 创建 Enhancer 对象; ## 设置父类(被代理类); ## 设置回调方法(拦截器); ## 使用 Enhancer 对象,生成代理类; ==== 回调过滤器 CallbackFilter ==== “JDK 动态代理”中,InvocationHandler 接口方法的调用对代理类内的所以方法都有效;不能针对单个方法实现代理逻辑。 在 CGLib 回调时可以设置对不同方法执行不同的回调逻辑,或者根本不执行回调: 1、添加多个不同的 '''Callback'''。 2、设置 '''CallbackFilter'''。 【<span style="color: blue; font-size: 120%">Callback 可以是:'''“不同的 MethodInterceptor 实现”'''(不同的拦截器)、'''“NoOp”'''(不代理)、'''“FixedValue”'''(方法返固定值)</span>】 示例: # 设置回调过滤器(实现“'''CallbackFilter'''”接口): #: <syntaxhighlight lang="java" highlight=""> import java.lang.reflect.Method; import net.sf.cglib.proxy.CallbackFilter; public class TargetMethodCallbackFilter implements CallbackFilter { /** * 过滤方法 * 返回的值为数字,代表了Callback数组中的索引位置,要到用的Callback */ @Override public int accept(Method method) { if(method.getName().equals("method1")){ System.out.println("filter method1 ==0"); return 0; } if(method.getName().equals("method2")){ System.out.println("filter method2 ==1"); return 1; } if(method.getName().equals("method3")){ System.out.println("filter method3 ==2"); return 2; } return 0; } } </syntaxhighlight> #* 其中 return 值:为目标类的各个方法在回调数组“Callback[]”中的位置索引('''使用哪一个回调函数'''); #*: 如上:method1 将使用下面 Callback[] 中的“callback1”,method2 将使用下面 Callback[] 中的“noopCb”,method3 将使用下面 Callback[] 中的“fixedValue”。 # 锁定方法返回值(实现“'''FixedValue'''”接口): #: <syntaxhighlight lang="java"> import net.sf.cglib.proxy.FixedValue; /** * 表示锁定方法返回值,无论被代理类的方法返回什么值,回调方法都返回固定值。 * @author zghw * */ public class TargetResultFixed implements FixedValue{ /** * 该类实现FixedValue接口,同时锁定回调值为999 * (整型,CallbackFilter 中定义的使用 FixedValue 型回调的方法为 getConcreteMethodFixedValue,该方法返回值为整型)。 */ @Override public Object loadObject() throws Exception { System.out.println("锁定结果"); Object obj = 999; return obj; } } </syntaxhighlight> # 使用过滤: #: <syntaxhighlight lang="java" highlight="11,21,23,24"> import net.sf.cglib.proxy.Callback; import net.sf.cglib.proxy.CallbackFilter; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.NoOp; public class TestCglib { public static void main(String args[]) { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(TargetObject.class); CallbackFilter callbackFilter = new TargetMethodCallbackFilter(); /** * (1)callback1:方法拦截器 (2)NoOp.INSTANCE:这个NoOp表示no operator,即什么操作也不做,代理类直接调用被代理的方法不进行拦截。 (3)FixedValue:表示锁定方法返回值,无论被代理类的方法返回什么值,回调方法都返回固定值。 */ Callback noopCb = NoOp.INSTANCE; Callback callback1 = new TargetInterceptor(); Callback fixedValue = new TargetResultFixed(); Callback[] cbarray = new Callback[]{ callback1, noopCb, fixedValue }; enhancer.setCallbacks(cbarray); enhancer.setCallbackFilter(callbackFilter); TargetObject targetObject2 = (TargetObject)enhancer.create(); System.out.println(targetObject2); System.out.println(targetObject2.method1("mmm1")); System.out.println(targetObject2.method2(100)); System.out.println(targetObject2.method3(100)); System.out.println(targetObject2.method3(200)); } } </syntaxhighlight> #* 其中设置了回调过滤器:'''通过过滤器,决定不同的方法使用不同的回调函数'''; #*: 如上,'''可以添加更多的 callback2、callback3、callback4 ……'''; #* 其中设置了多个回调函数: ## “noopCb”:不做操作; ## “callback1”:(见上一节)实现代理逻辑; ## “fixedValue”:返回固定值的回调; :: 如上:method1 将通过代理(“callback1”),method2 并不代理(“noopCb”),method3 方法将返回固定值(“fixedValue”)。 ==== 延迟加载对象 ==== CGLib 中,实现延迟加载的方式: 1、“'''LazyLoader'''”接口:(继承于“Callback”)只在'''第一次'''访问延迟加载属性时触发代理类回调方法; 2、“'''Dispatcher'''”接口:(继承于“Callback”)在'''每次'''访问延迟加载属性时都会触发代理类回调方法; 示例: # 实体类 LoaderBean,延迟加载“PropertyBean”和“propertyBeanDispatcher”: #: <syntaxhighlight lang="java" line highlight="14,16,29-32,39-42"> import net.sf.cglib.proxy.Enhancer; public class LazyBean { private String name; private int age; private PropertyBean propertyBean; private PropertyBean propertyBeanDispatcher; public LazyBean(String name, int age) { System.out.println("lazy bean init"); this.name = name; this.age = age; // 延迟加载 propertyBean this.propertyBean = createPropertyBean(); // 延迟加载 propertyBeanDispatcher this.propertyBeanDispatcher = createPropertyBeanDispatcher(); } /** * 只第一次懒加载 * @return */ private PropertyBean createPropertyBean() { /** * 使用cglib进行懒加载 对需要延迟加载的对象添加代理,在获取该对象属性时先通过代理类回调方法进行对象初始化。 * 在不需要加载该对象时,只要不去获取该对象内属性,该对象就不会被初始化了。 * (在CGLib的实现中只要去访问该对象内属性的getter方法,就会自动触发代理类回调)。 */ Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(PropertyBean.class); PropertyBean pb = (PropertyBean) enhancer.create(PropertyBean.class, new ConcreteClassLazyLoader()); return pb; } /** * 每次都懒加载 * @return */ private PropertyBean createPropertyBeanDispatcher() { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(PropertyBean.class); PropertyBean pb = (PropertyBean) enhancer.create(PropertyBean.class, new ConcreteClassDispatcher()); return pb; } // getter(name、age、propertyBean、propertyBeanDispatcher) ... // setter(name、age、propertyBean、propertyBeanDispatcher) ... @Override public String toString() { return "LazyBean [name=" + name + ", age=" + age + ", propertyBean=" + propertyBean + "]"; } } </syntaxhighlight> # “PropertyBean”类如下: #: <syntaxhighlight lang="java"> public class PropertyBean { private String key; private Object value; // getter(key、value) ... // setter(key、value) ... @Override public String toString() { return "PropertyBean [key=" + key + ", value=" + value + "]" + getClass(); } } </syntaxhighlight> # “ConcreteClassLazyLoader”接口(实现了“LazyLoader”): #: <syntaxhighlight lang="java" highlight="12"> import net.sf.cglib.proxy.LazyLoader; public class ConcreteClassLazyLoader implements LazyLoader { @Override public Object loadObject() throws Exception { System.out.println("before lazyLoader..."); PropertyBean propertyBean = new PropertyBean(); propertyBean.setKey("xxx"); propertyBean.setValue(new TargetObject()); System.out.println("after lazyLoader..."); return propertyBean; } } </syntaxhighlight> # “ConcreteClassDispatcher”接口(实现了“Dispatcher”): #: <syntaxhighlight lang="java" highlight="12"> import net.sf.cglib.proxy.Dispatcher; public class ConcreteClassDispatcher implements Dispatcher{ @Override public Object loadObject() throws Exception { System.out.println("before Dispatcher..."); PropertyBean propertyBean = new PropertyBean(); propertyBean.setKey("xxx"); propertyBean.setValue(new TargetObject()); System.out.println("after Dispatcher..."); return propertyBean; } } </syntaxhighlight> ==== 接口生成器(InterfaceMaker) ==== '''InterfaceMaker''':用于动态生成一个接口,该接口'''包含指定类定义的所有方法'''。 示例: : <syntaxhighlight lang="java" highlight="13,16,18"> import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.InterfaceMaker; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; public class TestInterfaceMaker { public static void main(String[] args) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { InterfaceMaker interfaceMaker = new InterfaceMaker(); //抽取某个类的方法生成接口方法 interfaceMaker.add(TargetObject.class); Class<?> targetInterface = interfaceMaker.create(); for(Method method : targetInterface.getMethods()){ System.out.println(method.getName()); } //接口代理并设置代理接口方法拦截 Object object = Enhancer.create( Object.class, new Class[]{targetInterface}, new MethodInterceptor(){ @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { if(method.getName().equals("method1")){ System.out.println("filter method1 "); return "mmmmmmmmm"; } if(method.getName().equals("method2")){ System.out.println("filter method2 "); return 1111111; } if(method.getName().equals("method3")){ System.out.println("filter method3 "); return 3333; } return "default"; }}); Method targetMethod1 = object.getClass().getMethod("method3",new Class[]{int.class}); int i = (int)targetMethod1.invoke(object, new Object[]{33}); Method targetMethod = object.getClass().getMethod("method1",new Class[]{String.class}); System.out.println(targetMethod.invoke(object, new Object[]{"sdfs"})); } } </syntaxhighlight>
返回至“
动态代理、CGLIB 与 切面编程
”。
导航菜单
个人工具
登录
命名空间
页面
讨论
大陆简体
已展开
已折叠
查看
阅读
查看源代码
查看历史
更多
已展开
已折叠
搜索
导航
首页
最近更改
随机页面
MediaWiki帮助
笔记
服务器
数据库
后端
前端
工具
《To do list》
日常
阅读
电影
摄影
其他
Software
Windows
WIKIOE
所有分类
所有页面
侧边栏
站点日志
工具
链入页面
相关更改
特殊页面
页面信息