cglib的简单案例

本文的例子全部来自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的字节码不熟悉很难去使用。

时间: 2024-08-25 14:22:01

cglib的简单案例的相关文章

keepalived简单案例

---------------------------------- 一.前言 二.环境 三.Keepalived体系架构 四.安装Keepalived 五.案例配置 ---------------------------------- 一.前言 keepalived是一个类似于layer3,4&5交换机制的软件,也就是我们平时说的第3层.第4层和第5层交换.Keepalived的作用是检测web服务器的状态,如果有一台web服务器死机,或工作出现故障,Keepalived将检测到,并将有故障的

[Design Pattern] Mediator Pattern 简单案例

Meditor Pattern,即调解模式,用一个调解类类处理所有的沟通事件,使得降低多对象之间的沟通难度,属于行为类的设计模式.为了方便理解记忆,我也称其为,沟通模式. 下面是一个调解模式的简单案例. ChatRoom 提供公用发送短信的方法.User 全部通过 ChatRoom 类发送信息进行沟通.MediatorPatternDemo 演示调解模式. 代码实现 ChatRoom 提供发送信息的方法 public class ChatRoom { public static void sho

[Design Pattern] Iterator Pattern 简单案例

Iterator Pattern,即迭代时模式,按照顺序依次遍历集合内的每一个元素,而不用了解集合的底层实现,属于行为类的设计模式.为了方便理解记忆,我也会称其为遍历模式. 下面是一个迭代器模式的简单案例. Iterator 定义了迭代接口, 仅 hasNext 和 next 两个方法.Container 定义了集合的接口,必须包含一个返回迭代器类 Iterator 的方法.NameRepository 是容器的具体类,实现 Container 接口,并拥有一个内部类 NameIterator

[Design Pattern] Observer Pattern 简单案例

Observer Pattern,即观察者模式,当存在一对多关系,例如一个对象一有变动,就要自动通知被依赖的全部对象得场景,属于行为类的设计模式. 下面是一个观察者模式的简单案例. Observer 定义观察者的接口,定义需要观察的对象,已经被通知的接口.BinaryObserver, OctalObserver, HexaObserver 各自实现了 Observer 接口. Subject 是被观察的对象,记录了观察该对象的观察者列表,自身有变动,即可通知观察者列表中的各个观察者. 代码实现

[Design Pattern] Command Pattern 简单案例

Command Pattern, 即命令模式,把一个命令包裹在一个对象里面,将命令对象传递给命令的执行方,属于行为类的设计模式 下面是命令模式的一个简单案例. Stock 代表被操作的对象.Order 定义命令的接口,BuyStock, SellStock 是具体类,实现 Order 接口.Broker 是命令的执行方.CommandPatternDemo 演示命令模式. 代码实现 Order, 命令接口 public interface Order { public void execute(

[Design Pattern] Proxy Pattern 简单案例

Proxy Pattern, 即代理模式,用一个类代表另一个类的功能,用于隐藏.解耦真正提供功能的类,属于结构类的设计模式. 下面是 代理模式的一个简单案例. Image 定义接口,RealImage, ProxyImage 都实现该接口.RealImage 具有真正显示功能,ProxyImage 作为代表,暴露给客户端使用. 代码实现: public interface Image { public void display(); } RealImage 的实现,提供真正的功能 public

[Design Pattern] Facde Pattern 简单案例

Facade Pattern, 即外观模式,用于隐藏复杂的系统内部逻辑,提供简洁的接口给客户端调用,属于结构类的设计模式.我会将其名字理解为,门户模式. 下面是 Facade Pattern 的一个简单案例. Shape 定义一个接口,Circle, rectangle, Square 分别实现 Shape 接口,代表系统内部的一个功能.ShapeMaker 作为一个对外类,提供简洁的接口给外部调用. 代码实现: Shape 接口 public interface Shape { public

[Design Pattern] Flywight Pattern 简单案例

Flywight Pattern, 即享元模式,用于减少对象的创建,降低内存的占用,属于结构类的设计模式.根据名字,我也将其会理解为 轻量模式. 下面是享元模式的一个简单案例. 享元模式,主要是重用已有的对象,通过修改部分属性重新使用,避免申请大量内存. 本模式需要主要两个点: 1. 对象的 key 应该是不可变得,本例中 color 作为 key,所以我在 color 前添加了 final 的修饰符. 2. 并非线程安全,多个线程同时获取一个对象,并同时修改其属性,会导致无法预计的结果. 代码

[源码]Condition的原理,简单案例(ArrayBlockingQueue),复杂案例(LinkedBlockingQueue).

源代码解析 Re'entrantLock lock = new ReentrantLock(fair); Condition   notEmpty = lock.newCondition(); //返回内部类 AbstractQueuedSyncronizer.ConditionObject 各自维护了两个队列.一个是阻塞同步队列 syncQueue 双向队列,一个是条件等待队列. Condition.await两个作用.1.放入同步队列 park 2.realse锁,3等待别人获取锁acqui