码迷,mamicode.com
首页 > 其他好文 > 详细

cglib的简单案例

时间:2015-04-05 16:03:41      阅读:187      评论:0      收藏:0      [点我收藏+]

标签:

本文的例子全部来自github上cglib的官方文档,有关cglib的教程少之又少,如果想学习觉得还是看看诸如Hibernate和Spring的源码来的实在。

package com.tang;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotSame;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

import net.sf.cglib.beans.BeanCopier;
import net.sf.cglib.beans.BeanGenerator;
import net.sf.cglib.beans.BeanMap;
import net.sf.cglib.beans.BulkBean;
import net.sf.cglib.beans.ImmutableBean;
import net.sf.cglib.core.KeyFactory;
import net.sf.cglib.core.Signature;
import net.sf.cglib.proxy.CallbackHelper;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.FixedValue;
import net.sf.cglib.proxy.InterfaceMaker;
import net.sf.cglib.proxy.InvocationHandler;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import net.sf.cglib.proxy.Mixin;
import net.sf.cglib.proxy.NoOp;
import net.sf.cglib.reflect.ConstructorDelegate;
import net.sf.cglib.reflect.FastClass;
import net.sf.cglib.reflect.FastMethod;
import net.sf.cglib.reflect.MethodDelegate;
import net.sf.cglib.reflect.MulticastDelegate;
import net.sf.cglib.util.ParallelSorter;
import net.sf.cglib.util.StringSwitcher;

import org.junit.Test;
import org.objectweb.asm.Type;

import com.pojo.BeanDelegate;
import com.pojo.Class1;
import com.pojo.Class2;
import com.pojo.DelegatationProvider;
import com.pojo.Interface1;
import com.pojo.Interface2;
import com.pojo.MixinInterface;
import com.pojo.OtherSampleClass;
import com.pojo.SampleBeanConstructorDelegate;
import com.pojo.SampleClass;
import com.pojo.SimpleMulticastBean;

/**
 * 字节码增强类
 * 
 * @author Administrator
 * 
 */
public class Cglib {
	/**
	 * 将一个方法的返回值设置为固定的值 使用FixedValue,SimpleClass类的所有方法包括父类的 方法都试图返回"Hello cglib"
	 */
	@Test
	public void testFixedValue() {
		Enhancer e = new Enhancer();
		e.setSuperclass(SampleClass.class);
		e.setCallback(new FixedValue() {

			@Override
			public Object loadObject() throws Exception {
				return "Hello cglib";
			}
		});

		SampleClass proxy = (SampleClass) e.create();
		assertEquals("Hello cglib", proxy.test(null));
		assertEquals("Hello cglib", proxy.toString());
		// 调用hashCode方法将返回ClassCastException
		try {
			proxy.hashCode();
		} catch (Exception e1) {
			assertEquals(e1.getClass(), ClassCastException.class);
		}
		// getClass方法为final修饰的,cglib不会对final的方法修饰。
		proxy.getClass();
	}

	/*
	 * 测试InvocationHandler
	 */
	@Test
	public void testInvocationHandler() {
		Enhancer e = new Enhancer();
		e.setSuperclass(SampleClass.class);
		e.setCallback(new InvocationHandler() {

			@Override
			public Object invoke(Object proxy, Method method, Object[] args)
					throws Throwable {
				// 对非Object类并且方法的返回值是String类型的方法增强
				if (method.getDeclaringClass() != Object.class
						&& method.getReturnType() == String.class) {
					return "Hello cglib!";
				} else {
					// 其他方法抛异常
					throw new RuntimeException("Do not know what to do.");
					// 如果写成下面这种调用本类中的其他方法,则会出现死循环。后面的方法能够解决这个问题
					/*
					 * System.out.println("else"); return method.invoke(proxy,
					 * args);
					 */
				}
			}
		});
		SampleClass proxy = (SampleClass) e.create();
		assertEquals("Hello cglib!", proxy.test(null));
		try {
			proxy.hashCode();
		} catch (Exception e1) {
			assertEquals(e1.getMessage(), "Do not know what to do.");
		}
	}

	/**
	 * 该方法比InvocationHandler更常用,因为InvocationHandler有死循环的危险
	 */
	@Test
	public void testMethodInterceptor() {
		Enhancer e = new Enhancer();
		e.setSuperclass(SampleClass.class);
		e.setCallback(new MethodInterceptor() {

			// 相比invoke方法多出一个MethodProxy,为被代理类原方法的一个包装,有时候因为性能问题我们需要调用原类中的方法
			@Override
			public Object intercept(Object obj, Method method, Object[] args,
					MethodProxy proxy) throws Throwable {
				// 对非Object类并且方法的返回值是String类型的方法增强
				if (method.getDeclaringClass() != Object.class
						&& method.getReturnType() == String.class) {
					return "Hello cglib!";
				} else {
					// 调用原方法
					return proxy.invokeSuper(obj, args);
				}
			}
		});
		SampleClass proxy = (SampleClass) e.create();
		assertEquals("Hello cglib!", proxy.test(null));
		assertEquals(1, proxy.random());
	}

	/**
	 * callback的回调可以指定多个,既然有多个回调,那么需要指定一个策略来决定本次 调用要回调哪个
	 * 下面这个例子类似上面testMethodInterceptor方法。
	 */
	@Test
	public void testCallbackFilter() {
		Enhancer e = new Enhancer();
		CallbackHelper callbackHelper = new CallbackHelper(SampleClass.class,
				new Class[0]) {
			/**
			 * 根据不同的情况返回不同的callback类
			 */
			@Override
			protected Object getCallback(Method method) {

				if (method.getDeclaringClass() != Object.class
						&& method.getReturnType() == String.class) {
					return new FixedValue() {
						@Override
						public Object loadObject() throws Exception {
							return "Hello cglib!";
						}
					};
					// 返回原类默认的方法实现
				} else {
					return NoOp.INSTANCE; // A singleton provided by NoOp.
				}
			}
		};
		e.setSuperclass(SampleClass.class);
		e.setCallbackFilter(callbackHelper);
		e.setCallbacks(callbackHelper.getCallbacks());
		SampleClass proxy = (SampleClass) e.create();
		assertEquals("Hello cglib!", proxy.test(null));
		assertNotSame("Hello cglib!", proxy.random());
	}

	/**
	 * 创建不可变的bean
	 */
	@Test
	public void testImmutableBean() {
		SampleClass sample = new SampleClass();
		sample.setValue("Hello world!");
		SampleClass immutable = (SampleClass) ImmutableBean.create(sample);
		assertEquals("Hello world!", immutable.getValue());

		sample.setValue("Hello world again!");
		assertEquals("Hello world again!", sample.getValue());

		immutable.setValue("!");// 报错,因为immutable是不可变的bean
	}

	/**
	 * bean生成器,动态生成bean
	 * 
	 * @throws NoSuchMethodException
	 * @throws SecurityException
	 */
	@Test
	public void testBeanGenerator() throws Exception {
		BeanGenerator generator = new BeanGenerator();
		generator.addProperty("value", String.class);

		Object bean = generator.create();
		Method setter = bean.getClass().getMethod("setValue", String.class);
		setter.invoke(bean, "Hello world!");

		Method getter = bean.getClass().getMethod("getValue");

		assertEquals("Hello world!", getter.invoke(bean));
	}

	/**
	 * 属性拷贝器,如果两个类有相同的属性,则该拷贝器起作用
	 */
	@Test
	public void testBeanCopier() {
		BeanCopier copier = BeanCopier.create(SampleClass.class,
				OtherSampleClass.class, false);
		SampleClass bean = new SampleClass();
		bean.setValue("Hello cglib!");
		OtherSampleClass otherBean = new OtherSampleClass();
		copier.copy(bean, otherBean, null);
		assertEquals("Hello cglib!", otherBean.getValue());
	}

	/**
	 * bulkbean将一个bean中的get,set,返回值 分别看做一一对应的数组
	 */
	@Test
	public void testBulkBean() {
		BulkBean bulkBean = BulkBean.create(SampleClass.class,
				new String[] { "getValue" }, new String[] { "setValue" },
				new Class[] { String.class });
		SampleClass bean = new SampleClass();
		bean.setValue("Hello world!");

		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());

	}

	/**
	 * cglib中的最后一个工具类,将bean的所有属性转换成key-map的形式
	 */
	@Test
	public void testBeanMap() {
		SampleClass bean = new SampleClass();
		bean.setValue("Hello world!");

		BeanMap map = BeanMap.create(bean);
		assertEquals("Hello world!", map.get("value"));
	}

	/**
	 * keyfactory能够创建key的实例,key可以由不同的值组成,能够被map来使用
	 * 想要使用该功能需要定义一个接口,该接口必须有一个newInstance方法,且返回Object
	 */
	@Test
	public void testKeyFactory() {
		SampleKeyFactory keyFactory = (SampleKeyFactory) KeyFactory
				.create(SampleKeyFactory.class);
		// foo和42共同作为key
		Object key = keyFactory.newInstance("foo", 42);
		Map<Object, String> map = new HashMap<Object, String>();
		map.put(key, "Hello cglib!");

		assertEquals("Hello cglib!", map.get(keyFactory.newInstance("foo", 42)));
	}

	/**
	 * Mixin可以对多个对象进行代理,需要同时指定多个接口和者多个接口对应的代理对象
	 */
	@Test
	public void testMixin() {
		Mixin mixin = Mixin.create(new Class[] { Interface1.class,
				Interface2.class, MixinInterface.class }, new Object[] {
				new Class1(), new Class2() });
		MixinInterface mixinDelegate = (MixinInterface) mixin;
		assertEquals("first", mixinDelegate.first());
		assertEquals("second", mixinDelegate.second());
	}

	/**
	 * stringswitcher将在string和int之间建立一种映射,java 7已经内建的支持该 功能了。
	 * 
	 * @throws Exception
	 */
	@Test
	public void testStringSwitcher() throws Exception {
		String[] strings = new String[] { "one", "two" };
		int[] values = new int[] { 10, 20 };
		StringSwitcher stringSwitcher = StringSwitcher.create(strings, values,
				true);
		assertEquals(10, stringSwitcher.intValue("one"));
		assertEquals(20, stringSwitcher.intValue("two"));
		assertEquals(-1, stringSwitcher.intValue("three"));
	}

	/**
	 * 运行时生成接口,依赖ASM
	 */
	@Test
	public void testInterfaceMaker() {
		Signature signature = new Signature("foo", Type.DOUBLE_TYPE,
				new Type[] { Type.INT_TYPE });
		InterfaceMaker maker = new InterfaceMaker();
		maker.add(signature, new Type[0]);

		Class iface = maker.create();
		assertEquals(1, iface.getMethods().length);
		assertEquals("foo", iface.getMethods()[0].getName());
		assertEquals(double.class, iface.getMethods()[0].getReturnType());
	}

	/**
	 * 方法代理
	 * 
	 * @throws Exception
	 */
	@Test
	public void testMethodDelegate() throws Exception {
		SampleClass bean = new SampleClass();
		bean.setValue("Hello cglib!");
		// 使用BeanDelegate代理sampleclass的getValue方法
		BeanDelegate delegate = (BeanDelegate) MethodDelegate.create(bean,
				"getValue", BeanDelegate.class);
		assertEquals("Hello cglib!", delegate.getValue());
	}

	/**
	 * 可以代理多个对象 被代理的对象需要实现一个只有一个方法的对象。
	 * 
	 * @throws Exception
	 */
	@Test
	public void testMulticastDelegate() throws Exception {
		MulticastDelegate multicastDelegate = MulticastDelegate
				.create(DelegatationProvider.class);
		SimpleMulticastBean first = new SimpleMulticastBean();
		SimpleMulticastBean second = new SimpleMulticastBean();
		// 链式编程
		multicastDelegate = multicastDelegate.add(first).add(second);

		DelegatationProvider provider = (DelegatationProvider) multicastDelegate;
		// 代理first和second
		provider.setValue("Hello world!");

		assertEquals("Hello world!", first.getValue());
		assertEquals("Hello world!", second.getValue());
	}
	/**
	 * 构造方法代理,需要有一个newInstance方法,并且该方法返回object的接口
	 * @throws Exception
	 */
	@Test
	public void testConstructorDelegate() throws Exception {
		SampleBeanConstructorDelegate constructorDelegate = (SampleBeanConstructorDelegate) ConstructorDelegate
				.create(SampleClass.class, SampleBeanConstructorDelegate.class);
		//通过接口的newInstance返回实例
		SampleClass bean = (SampleClass) constructorDelegate.newInstance();
		assertEquals(true, SampleClass.class.isAssignableFrom(bean.getClass()));
	}
	/**
	 * 排序器,声称比jdk的默认排序器速度快
	 * @throws Exception
	 */
	@Test
	public void testParallelSorter() throws Exception {
	  Integer[][] value = {
	    {4, 3, 9, 0},
	    {2, 1, 6, 0}
	  };
	  ParallelSorter.create(value).mergeSort(0);
	  for(Integer[] row : value) {
	    int former = -1;
	    for(int val : row) {
	      assertEquals(true, former < val);
	      former = val;
	    }
	  }
	}
	/**
	 * Fastclass声称比jdk原始的反射速度快,目前不推荐使用
	 * @throws Exception
	 */
	@Test
	public void testFastClass() throws Exception {
	  FastClass fastClass = FastClass.create(SampleClass.class);
	  FastMethod fastMethod = fastClass.getMethod(SampleClass.class.getMethod("getValue"));
	  SampleClass myBean = new SampleClass();
	  myBean.setValue("Hello cglib!");
	  assertEquals("Hello cglib!", fastMethod.invoke(myBean, new Object[0]));
	}
}
cglib基于ASM做了一层封装使得开发变得简单,但是性能上肯定是比asm差一些的,asm的api全是基于字节码层面的,如果对jvm的字节码不熟悉很难去使用。

cglib的简单案例

标签:

原文地址:http://blog.csdn.net/tangyongzhe/article/details/44888171

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!