【Java】中使用CGLIB动态代理详解

一、简介

Cglib是一个优秀的动态代理框架,它的底层使用ASM在内存中动态的生成被代理类的子类。使用CGLIB即使被代理类没 有实现任何接口也可以实现动态代理功能。CGLIB具有简单易用,它的运行速度要远远快于JDK的Proxy动态代理:

1. 使用CGLIB需要导入以下两个jar文件:

 	asm.jar – CGLIB的底层实现。
  	cglib.jar – CGLIB的核心jar包。

2. CGLIB的核心类:

net.sf.cglib.proxy.Enhancer – 主要的增强类 ;net.sf.cglib.proxy.MethodInterceptor – 主要的方法拦截类,它是Callback接口的子接口,需要用户实现
net.sf.cglib.proxy.MethodProxy – JDK的java.lang.reflect.Method类的代理类,可以方便的实现对源对 象方法的调用,
如使用: Object o = methodProxy.invokeSuper(proxy, args);//虽然第一个参数是被代理对象,也不会出现死循环的问题。

二、费话少说,上代码:

1. 以下测试代理一个没有实现任何接口的Person类:

	@Test 
	public void testProxy1() throws Exception { 
	
		final Person p1 = new Person(); //Person类没有实现任何接口
		
		Enhancer en = new Enhancer(); //声明增加类实例 
		
		en.setSuperclass(Person.class); //设置被代理类字节码,CGLIB根据字节码生成被代 理类的子类
		
		en.setCallback(new MethodInterceptor() { //设置回调函数,即一个方法拦截 
		
		public Object intercept(Object target, Method method, Object[] args, MethodProxy proxy) throws Throwable { 
			Object o = method.invoke(p1,args); //注意参数p1,仍然为外部声明的源对象, 且Method为JDK的Method反射 
			System.err.println("After..."); 
			return o; 
			} 
		}); 
		
		Person p = (Person) en.create(); //通过create方法返回Person类的代理 
		
		System.err.println(p.getClass());//被代理的对象 
		
		p.sayHi("Hello");
		
	} 

2. 以下测试代理一个拥有接口的类 (IAnimal是接口,Dog是实现类,具体代码如下:)

	@Test 
	public void testProxy2() throws Exception { 
	
		final Dog dog = new Dog(); //声明被代理对象 
		
		Enhancer en = new Enhancer(); //声明CGLIB增强类 
		
		en.setSuperclass(IAnimal.class); //设置接口类,也可以设置成dog实现类,会影响create返回 的对象 
		
		en.setCallback(new MethodInterceptor() { 
		
			public Object intercept(Object target, Method method, Object[] args, MethodProxy proxy) throws Throwable { 
			
				System.err.println("Before..."); 
				
				Object o = method.invoke(dog, args); 
				
				System.err.println("After..."); 
				
				return o;
			
			}
		}); 
		
		//Dog dog2 = (Dog) en.create();//必须转型为接口,否则抛出ClassCastException 
		
		IAnimal dog2 = (IAnimal)en.create(); 
		
		dog2.eat(); 
		
	}

- 说明:
由于上例中,设置了en.setSuperclass(IAnimal.class),所以en.create()方法,返回的对象,必须要 转换成IAnimal接口。如果转换成Dog则会抛出ClassCastException。

3. 将CGLIB再做一个简单的包装:

	class CglibProxy implements MethodInterceptor{ 

		private Object srcTarget; 
		
		private CglibProxy(Object o){ 
			this.srcTarget = o; 
		}
		
		@SuppressWarnings("unchecked") 
		public static <T>T proxyTarget(T t){ 
			Enhancer en = new Enhancer(); 
			en.setSuperclass(t.getClass()); 
			en.setCallback(new CglibProxy(t)); 
			T tt = (T) en.create(); 
			return tt; 
			
		}
		
		@Override 
		public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { 
			System.err.println("拦截前..."); 
			Object o = method.invoke(srcTarget, args); 
			System.err.println("拦截后...."); 
			return o;
		}		
	}
	
	***包装以后的调用代码如下,主要是快速的实现获取被代理类:***
	
	Person p = CglibProxy.proxyTarget(new Person()); 
	p.sayHi("HJello"); 
	IAnimal dog = CglibProxy.proxyTarget(new Dog()); 
	dog.eat();

4. 使用静态方法代理一个没有接口的对象

	@Test 
	public void test() throws Exception { 
	
		final Person src = new Person();
		
		//直接使用静态方法代理一个对象 
		Person p = (Person) Enhancer.create(Person.class,new MethodInterceptor(){ 
		
			public Object intercept(Object proxyedObj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
			
				System.err.println("Hello"); 
				
				//使用原生的方法调用,注意里面的src 
				//Object oo = method.invoke(src, args); 
				//使用MethodProxy调用父类的代码,同样有效 
				
				Object oo = proxy.invokeSuper(proxyedObj, args); 
					return oo; 
				} 
			}); 
			
			System.err.println(p.getClass()); 
			
			p.abc();
		
	}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Monika、

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值