CGLIB 实现代理对象

来源:互联网 发布:java中的finally 编辑:程序博客网 时间:2024/06/04 20:01
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"/>
0 0
原创粉丝点击