06CGLIB

CGLIB

public class CglibTest {
    public void function(){
        System.out.println("hello world");
    }

    @Test
    public  void test1() {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(CglibTest.class);
        /**
        enhancer.setCallbackFilter();
        enhancer.setCallbacks();
        enhancer.setInterfaces();
        //生成策略
        enhancer.setStrategy();
        **/

        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;
            }
        });
        CglibTest test = (CglibTest) enhancer.create();
        test.function();
        /**
         * before method run...
         * hello world
         * after method run...
         */
    }

    /**
     * ImmutableBean允许创建一个原来对象的包装类,这个包装类是不可变的,
     * 任何改变底层对象的包装类操作都会抛出IllegalStateException。
     * 但是我们可以通过直接操作底层对象来改变包装类对象。
     */
    @Test
    public void testImmutableBean(){
        Simple bean = new Simple();
        bean.setValue("Hello world");
        Simple immutableBean = (Simple) ImmutableBean.create(bean); //创建不可变类
        System.out.println(immutableBean.getValue());
        bean.setValue("Hello world, again"); //可以通过底层对象来进行修改
        System.out.println(immutableBean.getValue());
        try {
            immutableBean.setValue("Hello cglib"); //直接修改将throw exception
        } catch (Exception e) {
            System.out.println(e);
        }
        /**
         * Hello world
         * Hello world, again
         * java.lang.IllegalStateException: Bean is immutable
         */
    }

    /**
     * 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");
        System.out.println("getter.invoke(myBean) = " + getter.invoke(myBean));
        /**
         * getter.invoke(myBean) = Hello cglib
         */
    }

    /**
     * Bean Copier
     * cglib提供的能够从一个bean复制到另一个bean中,
     * 而且其还提供了一个转换器,
     * 用来在转换的时候对bean的属性进行操作。
     */
    @Test
    public void testBeanCopier() throws Exception{
        BeanCopier copier = BeanCopier.create(Simple.class, Simple2.class, true);//设置为true,则使用converter
        Simple myBean = new Simple();
        myBean.setValue("Hello cglib");
        Simple2 otherBean = new Simple2();
        copier.copy(myBean, otherBean, new Converter(){
            @Override
            public Object convert(Object value, Class target, Object context) {
                return value+" convert";
            }
        }); //设置为true,则传入converter指明怎么进行转换
        System.out.println("otherBean.getValue() = " + otherBean.getValue());
        //otherBean.getValue() = Hello cglib convert
    }

    /**
     * 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();
        Method 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);
        System.out.println("map.get(\"username\") = " + map.get("username"));
        System.out.println("map.get(\"password\") = " + map.get("password"));
    }
    /**
     * keyFactory
     * keyFactory类用来动态生成接口的实例,
     * 接口需要只包含一个newInstance方法,返回一个Object。
     * keyFactory为构造出来的实例动态生成了Object.equals和Object.hashCode方法,
     * 能够确保相同的参数构造出的实例为单例的。
     *
     */
    @Test
    public void testKeyFactory() throws Exception{
        SampleKeyFactory keyFactory = (SampleKeyFactory) KeyFactory.create(SampleKeyFactory.class);
        Object key = keyFactory.newInstance("foo", 42);
        Object key1 = keyFactory.newInstance("foo", 42);
        System.out.println("key = " + key+"  "+key.hashCode());
        System.out.println("key1 = " + key1+"  "+key1.hashCode());
        /**
         * key = foo, 42  -1181409833
         * key1 = foo, 42  -1181409833
         */
    }
    /**
     * Interface Maker
     * 正如名字所言,Interface Maker用来创建一个新的Interface
     */

    @Test
    public void testInterfaceMarker() throws Exception{
        Signature signature = new Signature("foo", Type.DOUBLE_TYPE, new Type[]{Type.INT_TYPE});
        InterfaceMaker interfaceMaker = new InterfaceMaker();
        interfaceMaker.add(signature, new Type[0]);
        Class iface = interfaceMaker.create();
        System.out.println("iface.getMethods().length = " + iface.getMethods().length);
        System.out.println("iface.getMethods()[0].getName() = " + iface.getMethods()[0].getName());
        System.out.println("iface.getMethods()[0].getReturnType() = " + iface.getMethods()[0].getReturnType());
        /**
         * iface.getMethods().length = 1
         * iface.getMethods()[0].getName() = foo
         * iface.getMethods()[0].getReturnType() = double
         *
         */

    }
}

Enhancer-CallBack

Callback-MethodInterceptor

  • 方法拦截器
  • Object intercept(Object obj, java.lang.reflect.Method method, Object[] args, MethodProxy proxy) throws Throwable
  • MethodProxy proxy参数一般是用来调用原来的对应方法的。比如可以proxy.invokeSuper(obj, args)。那么为什么不能像InvocationHandler那样用method来调用呢?因为如果用method调用会再次进入拦截器。为了避免这种情况,应该使用接口方法中第四个参数methodProxy调用invokeSuper方法。

Callback-NoOp

  • 这个回调相当简单,就是啥都不干的意思

Callback-LazyLoader

  • LazyLoader是cglib用于实现懒加载的callback。当被增强bean的方法初次被调用时,会触发回调,之后每次再进行方法调用都是对LazyLoader第一次返回的bean调用。
public class EnhancerTest {

    public static void main(String[] args) {
        CarFactory factory = new CarFactory();
        System.out.println("factory built");
        System.out.println(factory.car.getName());
        System.out.println(factory.car.getName());
    }

    static class Car {
        String name;
        Car() {
        }

        String getName() {
            return name;
        }
    }

    static class CarFactory {
        Car car;

        CarFactory() {
            car = carLazyProxy();
        }

        Car carLazyProxy() {
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(Car.class);
            enhancer.setCallback(new LazyLoader() {
                @Override
                public Object loadObject() throws Exception {
                    System.out.println("prepare loading");
                    Car car = new Car();
                    car.name = "this is a car";
                    System.out.println("after loading");
                    return car;
                }
            });
            return ((Car) enhancer.create());
        }
    }
}
/**
factory built
prepare loading
after loading
this is a car
this is a car
**/

Callback-Dispatcher

  • Dispatcher和LazyLoader作用很相似,区别是用Dispatcher的话每次对增强bean进行方法调用都会触发回调。
public class EnhancerTest {

    public static void main(String[] args) {
        CarFactory factory = new CarFactory();
        System.out.println("factory built");
        System.out.println(factory.car.getName());
        System.out.println(factory.car.getName());
    }

    static class Car {
        String name;
        Car() {
        }

        String getName() {
            return name;
        }
    }

    static class CarFactory {
        Car car;

        CarFactory() {
            car = carLazyProxy();
        }

        Car carLazyProxy() {
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(Car.class);
            enhancer.setCallback(new Dispatcher() {
                @Override
                public Object loadObject() throws Exception {
                    System.out.println("prepare loading");
                    Car car = new Car();
                    car.name = "this is a car";
                    System.out.println("after loading");
                    return car;
                }
            });
            return ((Car) enhancer.create());
        }
    }
}
/**
factory built
prepare loading
after loading
this is a car
prepare loading
after loading
this is a car
**/

Callback-InvocationHandler

  • 如果对参数中的method再次调用,会重复进入InvocationHandler。
public class EnhancerTest {

    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(Car.class);
        enhancer.setCallback(new InvocationHandler() {
            @Override
            public Object invoke(Object obj, Method method, Object[] args) throws Throwable {
                if (method.getReturnType() == void.class) {
                    System.out.println("hack");
                }
                return null;
            }
        });
        Car car = (Car) enhancer.create();
        car.print();
    }

    static class Car {
        void print() {
            System.out.println("I am a car");
        }
    }
}

Callback-FixedValue

  • FixedValue一般用于替换方法的返回值为回调方法的返回值,但必须保证返回类型是兼容的,否则会出转换异常。
public class EnhancerTest {
    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(Car.class);
        enhancer.setCallback(new FixedValue() {
            @Override
            public Object loadObject() throws Exception {
                return "hack!";
            }
        });

        Car car = (Car) enhancer.create();
        System.out.println(car.print1());
        System.out.println(car.print2());
    }

    static class Car {
        String print1() {
            return "car1";
        }
        String print2() {
            return "car2";
        }
    }
}

CallbackFilter

  • 上面都是为增强bean配置了一种代理callback,但是当需要作一些定制化的时候,CallbackFilter就派上用处了。
  • 当通过设置CallbackFilter增强bean之后,bean中原方法都会根据设置的filter与一个特定的callback映射。我们通常会使用cglib中CallbackFilter的默认实现CallbackHelper,它的getCallbacks方法可以返回生成的callback数组。
///被代理的类
public class ConcreteClassNoInterface {
	public String getConcreteMethodA(String str){
		System.out.println("ConcreteMethod A ... "+str);
		return str;
	}
	public int getConcreteMethodB(int n){
		System.out.println("ConcreteMethod B ... "+n);
		return n+10;
	}
	public int getConcreteMethodFixedValue(int n){
		System.out.println("getConcreteMethodFixedValue..."+n);
		return n+10;
	}
}

//CallbackFilter
public class ConcreteClassCallbackFilter implements CallbackFilter{
	public int accept(Method method) {
		if("getConcreteMethodB".equals(method.getName())){
			return 0;//Callback callbacks[0]--->interceptor
		}else if("getConcreteMethodA".equals(method.getName())){
			return 1;//Callback callbacks[1]--->noOp
		}else if("getConcreteMethodFixedValue".equals(method.getName())){
			return 2;//Callback callbacks[2]--->fixedValue
		}
		return 1;//Callback callbacks[1]--->noOp
	}
}
//
Enhancer enhancer=new Enhancer();
enhancer.setSuperclass(ConcreteClassNoInterface.class);
CallbackFilter filter=new ConcreteClassCallbackFilter();
enhancer.setCallbackFilter(filter);
 
Callback interceptor=new ConcreteClassInterceptor();
Callback noOp=NoOp.INSTANCE;
Callback fixedValue=new ConcreteClassFixedValue();
Callback[] callbacks=new Callback[]{interceptor,noOp,fixedValue};
enhancer.setCallbacks(callbacks);
ConcreteClassNoInterface proxyObject=(ConcreteClassNoInterface)enhancer.create();

06CGLIB
https://jiajun.xyz/2020/10/10/java/spring/06CGLIB/
作者
Lambda
发布于
2020年10月10日
许可协议