动态代理、CGLIB 与 切面编程

来自Wikioe
跳到导航 跳到搜索


关于代理

代理,简单说就是:不直接操作对象,而使用代理对象来完成操作。

通过代理对象,可以对原对象进行方法扩展

代理又可以分为:

  1. 静态代理:通过聚合、继承的方式生成代理对象;
    • 代理关系在编译时就确定了
  2. 动态代理:
    • 运行期动态生成代理对象;
    1. Java动态代理
      • 只能够对接口(目标类必须实现接口)进行代理 —— 因为所有生成的代理类的父类为 Proxy,而 Java 类继承机制不允许多重继承;
      • 类的生成过程更高效 —— 使用 Java 原生的反射 API 进行操作;
      • “代理类”为 Proxy 的子类
    2. CGLIB
      • 能够对普通类(没有实现接口的类)进行代理;
      • 类的执行过程更高效 —— 使用 ASM 框架直接对字节码进行操作;
      • “代理类”为“目标类”的子类
    3. AspectJ:(SpringFramework 的 AOP 基于此实现)。

Java动态代理

示例

Java中动态代理的实现,关键在于:“Proxy”、“InvocationHandler”的关联。

注意:invoke 方法的自动调用。

以实例分析:

  1. 抽象接口:
    //抽象角色(动态代理只能代理接口)  
    public interface Subject {  
        public void request();  
    }
    
  2. 抽象接口实现:
    //真实角色:实现了Subject的request()方法  
    public class RealSubject implements Subject{  
        public void request(){  
            System.out.println("From real subject.");  
        }  
    }
    
  3. “InvocationHandler”接口的实现类:
    //实现了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;  
        }
    }
    
    • “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);”,即调用此处,从而调用陷入死循环;
  4. 测试类:
    //客户端:生成代理实例,并调用了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();
        } 
    }
    
    运行结果如下:
    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()
    
    • 如果初始化“DynamicSubject”时,传入参数不是“RealSubject”类型,则,DynamicSubject中的“method.invoke(obj, args); ”将不能执行:
      错误信息:“object is not an instance of declaring class

代码分析

  • “Proxy”的部分源码:
    class Proxy{  
        InvocationHandler h=null;  
        protected Proxy(InvocationHandler h) {  
            this.h = h;  
        }  
        ...  
        public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
    }
    
    • Proxy 会生成一个“由loader加载”、“继承于Proxy”、“实现了interfaces等接口”的代理类“$Proxy0”;
    • Proxy 会将“InvocationHandler”实例保存在属性中;
  • 生成的“$Proxy0”:
    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);  
            }  
        }  
    }
    
    • 其中“m1”、“m0”、“m3”、“m2”是“Method”类型的字段,表示“$Proxy0”中方法所对应的原方法;包括:
      1. 继承于“Object”的“equals”(m1)、“hashCode”(m0)、“toString”(m2)
      2. 实现“Subject”的“request”(m3);
    • “$Proxy0”的方法实现:“super.h.invoke(this, m3, null);”:
      1. 调用父类的“h”(“InvocationHandler”实例)的“invoke”方法;(“invoke”中进行代理处置,并调用原始方法)
      2. 参数:“this”($Proxy0)、“m2”(原始方法)、“null”(方法参数)

AspectJ

CGLIB

CGLIB(Code Generation Library),是一个功能强大,高性能的代码生成包。

  • 使用CGLib实现动态代理,完全不受“被代理类必须实现接口”的限制
  • CGLib底层采用ASM字节码生成框架,使用字节码技术生成代理类,比使用Java反射效率要高。

原理

  1. 动态生成一个目标类的子类,子类重写目标类的“所有非 Final”的方法。
  2. 在子类中采用方法拦截的技术,拦截所有父类方法的调用,并织入横切逻辑。
  • 为没有实现接口的类提供代理,比于“JDK 动态代理”(只能代理接口)更加强大;
  • 不能代理 Final 方法;

CGLIB组成结构

CGLIB组成结构.png

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

见:CGLIB(Code Generation Library)详解
命令 说明 示例
Enhancer Enhancer创建一个被代理对象的子类并且拦截所有的方法调用(包括从Object中继承的toString和hashCode方法)
  • 作用类似Proxy类;但Enhancer既能够代理普通的class,也能够代理接口;(不能代理final方法)
  1. “Enhancer.setSuperclass()”:设置父类型;
  2. “Enhancer.create(Object…)”:创建增强对象;
  3. “Enhancer.createClass()”:创建字节码(.class);
  4. “Enhancer.setCallback()”:设置回调;
    • InvocationHandler”可以作为回调,但必须防止死循环;
      (invoke中调用的任何原代理类方法,均会重新代理到invoke方法中)
    • MethodInterceptor”可以作为回调,且不会出现死循环;
  • 如果只想对特定的方法进行拦截,对其他的方法直接放行:
    “enhancer.setCallbackFilter(callbackHelper);”
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();
    }
}

输出:

before method run...
hello world
after method run...
ImmutableBean 不可变的Bean
  • ImmutableBean允许创建一个原来对象的包装类,这个包装类是不可变的,任何改变底层对象的包装类操作都会抛出IllegalStateException
  • 但是可以通过直接操作底层对象来改变包装类对象。
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;
    }
}
@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
}
Bean generator cglib提供的一个操作bean的工具,使用它能够在运行时动态的创建一个bean。
@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));
}
Bean Copier cglib提供的能够从一个bean复制到另一个bean中,而且其还提供了一个转换器,用来在转换的时候对bean的属性进行操作。
public class OtherSampleBean {
    private String value;

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }
}
@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());
}
BulkBean 复制bean,BulkBean将copy的动作拆分为getPropertyValues和setPropertyValues两个方法,允许自定义处理属性;
  • 避免每次进行BulkBean.create创建对象,一般将其声明为static的
  • 应用场景:针对特定属性的get,set操作,一般适用通过xml配置注入和注出的属性,运行时才确定处理的Source,Target类,只需要关注属性名即可。
@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());
}
BeanMap BeanMap类实现了Java Map,将一个bean对象中的所有属性转换为一个String-to-Obejct的Java Map
@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"));
}
keyFactory eyFactory类用来动态生成接口的实例,接口需要只包含一个newInstance方法,返回一个Object。keyFactory为构造出来的实例动态生成了Object.equals和Object.hashCode方法,能够确保相同的参数构造出的实例为单例的。
Parallel Sorter (并行排序器)
FastClass 对Class对象进行特定的处理,比如通过数组保存method引用,因此FastClass引出了一个index下标的新概念,比如getIndex(String name, Class[] parameterTypes)就是以前的获取method的方法。
  • 通过数组存储method,constructor等class信息,从而将原先的反射调用,转化为class.index的直接调用,从而体现所谓的FastClass。
@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]));
}


使用

  1. 被代理类:(没有接口实现)
    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();
        }
    }
    
  2. 拦截器:
    • (类似于JDK中的“InvocationHandler”接口。)
    • 在调用目标方法时,CGLib会回调“MethodInterceptor”接口方法拦截,来实现代理逻辑;
    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;
        }
    }
    
    • 【与“InvocationHandler”接口的“invoke”方法有点类似】
    • “obj”:生成的代理实例;
    • “method”:被代理类(即,TargetObject)的方法;
    • “params”:方法参数;
    • “proxy”:生成的代理实例的方法;
    • “proxy.invokeSuper(obj, params);”:调用代理类方法所对应的,父类(即,被代理类)的方法;
  3. 生成动态代理类:
    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));
        }
    }
    
    • Enhancer类是CGLib中的一个字节码增强器,用于对类的扩展处理;步骤为:
    1. 创建 Enhancer 对象;
    2. 设置父类(被代理类);
    3. 设置回调方法(拦截器);
    4. 使用 Enhancer 对象,生成代理类;

回调过滤器 CallbackFilter

“JDK 动态代理”中,InvocationHandler 接口方法的调用对代理类内的所以方法都有效;不能针对单个方法实现代理逻辑。


在 CGLib 回调时可以设置对不同方法执行不同的回调逻辑,或者根本不执行回调:

1、添加多个不同的 Callback。

2、设置 CallbackFilter。


【Callback 可以是:“不同的 MethodInterceptor 实现”(不同的拦截器)、“NoOp”(不代理)、“FixedValue”(方法返固定值)

示例:

  1. 设置回调过滤器(实现“CallbackFilter”接口):
    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;
        }
    }
    
    • 其中 return 值:为目标类的各个方法在回调数组“Callback[]”中的位置索引(使用哪一个回调函数);
      如上:method1 将使用下面 Callback[] 中的“callback1”,method2 将使用下面 Callback[] 中的“noopCb”,method3 将使用下面 Callback[] 中的“fixedValue”。
  2. 锁定方法返回值(实现“FixedValue”接口):
    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;
        }
    }
    
  3. 使用过滤:
    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));
        }
    }
    
    • 其中设置了回调过滤器:通过过滤器,决定不同的方法使用不同的回调函数
      如上,可以添加更多的 callback2、callback3、callback4 ……
    • 其中设置了多个回调函数:
    1. “noopCb”:不做操作;
    2. “callback1”:(见上一节)实现代理逻辑;
    3. “fixedValue”:返回固定值的回调;


如上:method1 将通过代理(“callback1”),method2 并不代理(“noopCb”),method3 方法将返回固定值(“fixedValue”)。

延迟加载对象

CGLib 中,实现延迟加载的方式:

1、“LazyLoader”接口:(继承于“Callback”)只在第一次访问延迟加载属性时触发代理类回调方法;

2、“Dispatcher”接口:(继承于“Callback”)在每次访问延迟加载属性时都会触发代理类回调方法;

示例:

  1. 实体类 LoaderBean,延迟加载“PropertyBean”和“propertyBeanDispatcher”:
    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 + "]";
        }
    }
    
  2. “PropertyBean”类如下:
    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();
        }
    }
    
  3. “ConcreteClassLazyLoader”接口(实现了“LazyLoader”):
    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;
        }
    }
    
  4. “ConcreteClassDispatcher”接口(实现了“Dispatcher”):
    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;
        }
     
    }
    

接口生成器(InterfaceMaker)

InterfaceMaker:用于动态生成一个接口,该接口包含指定类定义的所有方法

示例:

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"}));
    }
}