CGLIB 实现代理对象API


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"/>
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值