您的位置:首页 > 其它

CGLIB 实现代理对象

2015-05-31 16:03 232 查看
CGLIB 编程步骤:

1. 加入库cglib库

cglib-2.2.jar

asm库(cglib 需要asm库,如果没有加入asm的jar文件,就会报asm错误)

asm-3.1.jar
2. 定义CGLIB操作类package com.machome.cglibtest;

import java.lang.reflect.Method;

import com.machome.model.StuService;

import net.sf.cglib.proxy.Enhancer;

import net.sf.cglib.proxy.MethodInterceptor;

import net.sf.cglib.proxy.MethodProxy;

public class CGlibProxyFactory implements MethodInterceptor {

private Object targetObject;



public Object createProxyInstance(Object targetObject){

this.targetObject = targetObject; //传入用户类



Enhancer enhancer = new Enhancer(); //Enhancer是cglib的核心类



// 将用户类设为 Enhancer对象的superclass属性,,即设为 Enhancer对象的父类

enhancer.setSuperclass(this.targetObject.getClass());

// 设 Enhancer对象的Callbacks属性,要求必须是Callback接口类型

enhancer.setCallback(this);



return enhancer.create(); //生成代理对象

}





@Override

public Object intercept(Object arg0, Method arg1, Object[] arg2,

MethodProxy arg3) throws Throwable {

StuService bean = (StuService)this.targetObject;

Object result = null;

if(!arg1.getName().equals("save")&&(bean.findAll().size()==0))

{ // 如果方法名不是save(即是get,update,delete方法),而同时实例的列表为空,就不执行方法,而是告警

System.out.println("list is null,method is stoped");

}else{

//执行代理方法,传入实例和方法参数

result = arg3.invoke(targetObject, arg2);

}

return result;

}

}
3.测试代码测试代码:

CGlibProxyFactory factory = new CGlibProxyFactory();

StuService bean = (StuService)factory.createProxyInstance(

new StuService());



List<Stu> stuList = bean.findAll();

if(stuList!=null){

for(Stu temp:stuList)

System.out.println(temp.getId()+":"+temp.getName());

System.out.println("finished");

执行结果:

list is null,method is stoped //bean.findAll()下边的语句都没执行)
cglib 执行intercept()的原理:

自定义类应该实现MethodInterceptor接口,,覆写 intercept()方法

public interface MethodInterceptor extends Callback

{

public abstract Object intercept(Object obj, Method method, Object aobj[], MethodProxy methodproxy)

throws Throwable;

}
Enhancer对象设其Callback对象(实际是Callbacks对象,一个数组,但我们经常只设一个)

enhancer.setCallback(Callback callback);
这样当Enhancer对象建立代理对象的时候,就会在执行用户调用的方法前,先执行intercept()方法

常见的两种不同的实现MethodInterceptor接口的cglib编程

1.自定义类直接实现MethodInterceptor接口,覆写 intercept()方法

public class CGlibProxyFactory implements MethodInterceptor {

public Object createProxyInstance(Object targetObject){

...

enhancer.setCallback(this);

...

}



@Override

public Object intercept(Object arg0, Method arg1, Object[] arg2,

MethodProxy arg3) throws Throwable {

...

}

}
2.另一种方式,定义一个内部类,该类实现MethodInterceptor接口,覆写intercept()方法

public class CGlibProxyFactory1 {

public Object createProxyInstance(Object targetObject){

...

enhancer.setCallback(new MethodInterceptorImpl());

...

}

private class MethodInterceptorImpl implements MethodInterceptor {

@Override

public Object intercept(Object obj, Method method, Object[] aobj,

MethodProxy methodproxy) throws Throwable {

...

}

}

}
注意 public Object intercept(Object
obj, Method method, Object[] aobj,MethodProxy methodproxy)方法的第一个参数obj有很大问题


intercept方法里的主要动作是执行invoke方法

有两种执行方法:

法1:将参数obj传入invokeSuper()方法:

return methodproxy.invokeSuper(obj, aobj);

obj应该是传入Enhancer 对象的用户对象

(即上边enhancer.setSuperclass(this.targetObject.getClass()))
法2:或者将传入Enhancer对象前的原始用户对象传入invoke()方法:

return methodproxy.invoke(targetObject, aobj);
实际工作中发现,参数obj不态好用. 如果你想intercept()方法中调用对象执行一些方法的话,obj会出stackOverflow这样的异常

如下面的例子:

public Object intercept(Object obj, Method method, Object[] aobj,

MethodProxy methodproxy) throws Throwable {

StuService bean = (StuService)obj;

Object result = null;

if(!method.getName().equals("save")&&(bean.findAll().size()==0))

{ // 如果方法名不是save,而实例的列表为空,就不执行方法,而是告警

System.out.println("list is null,method is stoped");

}else{

result = methodproxy.invokeSuper(obj, aobj);

}

return result;

}
执行时会出线面的异常:

Exception in thread "main" java.lang.StackOverflowError
改成下面就好了:

public Object intercept(Object obj, Method method, Object[] aobj,

MethodProxy methodproxy) throws Throwable {

StuService bean = (StuService)this.targetObject; //从外部传入的原始用户实例

Object result = null;

if(!method.getName().equals("save")&&(bean.findAll().size()==0))

{ // 如果方法名不是save,而实例的列表为空,就不执行方法,而是告警

System.out.println("list is null,method is stoped");

}else{

result = methodproxy.invoke(targetObject,
aobj);

}

return result;

}
cglib 在 spring,hibernate中的应用

Hibernate主要是利用cglib生成pojo的子类并override get方法来实现lazy loading机制

Spring则是利用cglib来实现动态代理。

spring,hibernate同时支持proxy类动态代理和cglib,二者的区别

proxy动态代理只能对实现了接口的类生成代理,而不能针对类

CGLIB是针对类生成代理,主要是对用户类生成一个子类

spring 下缺省是支持proxy 动态代理,如何强制使用CGLIB生成代理?

spring 主要在两个地方使用代理

AOP:

<aop:aspectj-autoproxy proxy-target-class="true"/>
Transaction:

<tx:annotation-driven transaction-manager="txManager" proxy-target-class="true"/>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: