关于cglib代理的概念和原理,这里就不多说了,详细请参考以往的博客:
  本篇主要介绍cglib的主要(常用)的api。
一、MethodInterceptor
入门的helloword
import net.sf.cglib.proxy.*;
import java.lang.reflect.Method;
class SampleClass{
    public void test(){
        System.out.println("test");
    }
    public void test2(){
        System.out.println("test2");
    }
}
public class test {
    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(SampleClass.class);
        enhancer.setCallback(new MethodInterceptor(){
            @Override
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                System.out.println("before");
                Object res=methodProxy.invokeSuper(o, objects);
                System.out.println("after");
                return res;
            }
        });
        SampleClass proxy = (SampleClass) enhancer.create();
        proxy.test();
        proxy.test2();
    }
}
输出:
before
test
after
before
test2
after
  该种方法将代理SampleClass类的非final的所有成员方法。如果只想代理某个指定的方法,可以实现CallbackFilter接口,如下:
import net.sf.cglib.proxy.*;
import java.lang.reflect.Method;
class SampleClass{
    public void test(){
        System.out.println("test");
    }
    public void test2(){
        System.out.println("test2");
    }
}
public class test {
    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(SampleClass.class);
        CallbackHelper callbackHelper = new CallbackHelper(SampleClass.class, new Class[0]) {
            @Override
            protected Object getCallback(Method method) {
                // 只代理方法名是test的方法
                if(method.getName().equals("test")){
                    return new MethodInterceptor(){
                        @Override
                        public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                            System.out.print("代理---");
                            return methodProxy.invokeSuper(o, objects);
                        }
                    };
                }else{
                    return NoOp.INSTANCE;
                }
            }
        };
        enhancer.setCallbackFilter(callbackHelper);
        enhancer.setCallbacks(callbackHelper.getCallbacks());
        SampleClass proxy = (SampleClass) enhancer.create();
        proxy.test();
        proxy.test2();
    }
}
输出:
代理---test
test2
  这种方法可以指定具体代理某一个方法。
二、InvocationHandler
  InvocationHandler可以实现对接口的代理,类似与mybatis,代码中开发者只需要写一个接口和一个xml,mybatis会根据xml的描述信息,帮你生成对应的方法实现,参数的解析、sql的生成、发送、结果集的封装等都不用开发者去写。而其中的原理就是利用了代理模式。
  首先定义一个接口,这个接口里有各种返回值类型的方法。
import java.util.List;
public interface TestInterface {
    String testString(Integer id);
    int testInt(String value);
    List testList(Integer age,Integer g);
    SampleClass testSampleClass();
}
  用代理模式去实现这些方法。实现类交由cglib去动态创建。
import net.sf.cglib.proxy.*;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
public class test2 {
    public static void main(String[] args)  {
        Class[] classes = {TestInterface.class};
        Enhancer enhancer = new Enhancer();
        enhancer.setInterfaces(classes);
        CallbackHelper callbackHelper = new CallbackHelper(Object.class, classes) {
            @Override
            protected Object getCallback(Method method) {
                // 只代理TestInterface中的方法
                if(method.getDeclaringClass() == TestInterface.class){
                    return new InvocationHandler() {
                        @Override
                        public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
                            System.out.print("参数:");
                            for (Object object : objects) {
                                System.out.print(object+"\t");
                            }
                            System.out.println();
                            Class<?> returnType = method.getReturnType();
                            if (returnType == int.class || returnType == Integer.class) {
                                // 返回值类型是整数类型
                                return 1;
                            }else if(returnType == String.class){
                                // 返回值类型是字符串
                                return "string";
                            }else if(returnType == List.class){
                                // 返回值类型是集合
                                ArrayList arrayList = new ArrayList();
                                arrayList.add("11");
                                return arrayList;
                            }
                            // ... 等等
                            else{
                                // 自定义类型
                                return returnType.newInstance();
                            }
                        }
                    };
                }else{
                    // 什么都不做
                    return NoOp.INSTANCE;
                }
            }
        };
        enhancer.setCallbackFilter(callbackHelper);
        enhancer.setCallbacks(callbackHelper.getCallbacks());
        TestInterface proxy = (TestInterface) enhancer.create();
        System.out.println("返回值:"+proxy.testInt("123"));;
        System.out.println("返回值:"+proxy.testList(1,1));;
        System.out.println("返回值:"+proxy.testString(1));;
        System.out.println("返回值:"+proxy.testSampleClass());;
    }
}
三、FixedValue
  该方法会对所有拦截的方法返回同样的值。
import net.sf.cglib.proxy.*;
import java.lang.reflect.Method;
class SampleClass{
    public String test(){
        return "test";
    }
    public String test2(){
        return "test2";
    }
}
public class test {
    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(SampleClass.class);
        CallbackHelper callbackHelper = new CallbackHelper(SampleClass.class, new Class[0]) {
            @Override
            protected Object getCallback(Method method) {
                // 只代理返回值类型是String类型的方法,如果返回值类型不是String将会抛异常。
                if(method.getReturnType()==String.class){
                    return new FixedValue() {
                        @Override
                        public Object loadObject() throws Exception {
                            return "proxy ...";
                        }
                    };
                }else{
                    return NoOp.INSTANCE;
                }
            }
        };
        enhancer.setCallbackFilter(callbackHelper);
        enhancer.setCallbacks(callbackHelper.getCallbacks());
        SampleClass proxy = (SampleClass) enhancer.create();
        System.out.println(proxy.test());
        System.out.println(proxy.test2());
        System.out.println(proxy.toString());
        System.out.println(proxy.hashCode());
    }
}
输出:
proxy ...
proxy ...
proxy ...
1874154700
返回值是String类型的都返回同样的值。
四、ImmutableBean
  不可变的Bean。ImmutableBean允许创建一个原来对象的包装类,这个包装类是不可变的,任何改变底层对象的包装类操作都会抛出IllegalStateException。但是我们可以通过直接操作底层对象来改变包装类对象。
import net.sf.cglib.beans.ImmutableBean;
class SampleBean{
    SampleBean(){
    }
    SampleBean(int id){
        this.id = id;
    }
    private int id;
    public int getId(){
        return this.id;
    }
    public void setId(int id){
        this.id = id;
    }
}
public class test2 {
    public static void main(String[] args) {
        SampleBean bean = new SampleBean();
        bean.setId(1);
        SampleBean immutableBean = (SampleBean)ImmutableBean.create(bean);
        System.out.println(bean.getId());
        System.out.println(immutableBean.getId());
        bean.setId(2);
        System.out.println(bean.getId());
        System.out.println(immutableBean.getId());
        immutableBean.setId(3); // 包装类修改将会抛异常
        System.out.println(bean.getId());
        System.out.println(immutableBean.getId());
    }
}
输出:
1
1
2
2
Exception in thread "main" java.lang.IllegalStateException: Bean is immutable
    at com.example.SampleBean$$ImmutableBeanByCGLIB$$e23e512b.setId(<generated>)
    at com.example.test2.main(test2.java:31)
五、BeanGenerator
  cglib提供的一个操作bean的工具,使用它能够在运行时动态的创建一个bean。
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class test2 {
    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        BeanGenerator beanGenerator = new BeanGenerator();
        beanGenerator.addProperty("id",int.class);
        Object myBean = beanGenerator.create();
        Method setter = myBean.getClass().getMethod("setId",int.class);
        setter.invoke(myBean,1);
        Method getter = myBean.getClass().getMethod("getId");
        System.out.println(getter.invoke(myBean));
    }
}
动态创建一个类,该类包含一个int类型的id属性,并包含get,set方法。
六、BeanMap
  BeanMap类实现了Java Map,将一个bean对象中的所有属性转换为一个String-to-Obejct的Java Map
import net.sf.cglib.beans.BeanMap;
import java.lang.reflect.InvocationTargetException;
class Bean{
    int id = 1;
    String name = "name";
    public int getId(){
        return this.id;
    }
    public String getName(){
        return this.name;
    }
}
public class test2 {
    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        Bean bean = new Bean();
        BeanMap beanMap = BeanMap.create(bean);
        Object id = beanMap.get("id");
        Object name = beanMap.get("name");
        System.out.println(id);
        System.out.println(name);
    }
}
输出:
1
name