转载自 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"/>
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"/>

CGLIB 实现代理对象API相关推荐

  1. 使用cglib创建代理对象

    在上一篇文章中,我讨论了基于标准Java的代理对象. 当您要在实现接口的对象上具有方法调用处理程序时,可以使用这些方法. Java反射代理的创建要求您具有一个实现接口的对象. 我们要代理的对象已经失控 ...

  2. CGLIB动态代理对象执行流程分析

    前言 都说CGLIB动态代理对象执行方法的速度相较于JDK动态代理更快,那么为什么更快,实际是因为CGLIB中采用了FastClass机制,本篇文章将对CGLIB动态代理对象执行某一个方法的流程进行分 ...

  3. cglib创建代理对象(1)

    cglib创建代理对象 还是从一个的小demo开始 例子 被代理的类 public class Bean{public String sayHello(String name) {return &qu ...

  4. 使用djcproxy创建代理对象

    在过去的几周中,我展示了如何使用Java Reflection API和cglib创建代理对象. 在本文中,我将向您展示如何使用djcproxy做到这一点. 哦,不是,另一个代理实现! 除了我创建此代 ...

  5. Spring AOP 源码分析 - 创建代理对象

    1.简介 在上一篇文章中,我分析了 Spring 是如何为目标 bean 筛选合适的通知器的.现在通知器选好了,接下来就要通过代理的方式将通知器(Advisor)所持有的通知(Advice)织入到 b ...

  6. SpringAOP的CGLIB动态代理的底层原理实现

    欢迎加入java学习讨论群:725562382 CGLIB动态代理: CGLIB(Code Generation Library)是一个开源项目!是一个强大的,高性能,高质量的Code生成类库,它可以 ...

  7. Java 静态代理、Java动态代理、CGLIB动态代理

    为什么80%的码农都做不了架构师?>>>    Java 的代理就是客户类不再直接和委托类打交道, 而是通过一个中间层来访问, 这个中间层就是代理.为啥要这样呢, 是因为使用代理有 ...

  8. CGLIb 创建代理

    CGLIb 创建代理 创建回调 创建代理(通过增强器和回调接口) 设置回调 CGLib总结 代理对象通过继承目标对象来封装目标对象的实现 CGlib 拦截的实现--在执行目标方法前判断拦截器是否存在并 ...

  9. 谁与争锋,JDK动态代理大战CGLib动态代理

    文章目录 一.前言 二.基本概念 三.JDK 和 CGLib动态代理区别 3.1 JDK动态代理具体实现原理 3.2 CGLib动态代理 3.3 两者对比 3.4 使用注意 四.JDK 和 CGLib ...

最新文章

  1. 04-c#入门(类型转换)
  2. 该项研究降低了使用大脑信号控制机器人手臂的位置误差
  3. cocos2dx环境搭建(android平台)
  4. 数据中心气流管理的基础:密闭系统的比较
  5. Tensorflow模型的保存与恢复的细节
  6. 程序员面试金典 - 面试题 16.10. 生存人数(自定义优先队列)
  7. Hyper-V实战:高可用性-配置Hyper-V群集
  8. java学习笔记------ PrintStream
  9. psp模拟器完美字库_安卓PSP模拟器评测:讨鬼传
  10. BZOJ 2145 悄悄话
  11. 幼儿园小程序实战开发教程
  12. 超全面Figma,Pixso和Sketch工具盘点
  13. 破解Esxi服务器中Windows虚机密码(Esxi服务器Windows虚拟机忘记密码解决方案)
  14. 苹果cms新手入门安装配置教程
  15. 面对人工智能,我们应有的态度
  16. js 事件绑定传入自定义参数
  17. HTML设计网页之网页头部
  18. PostgreSQL入门之基本工具+常用psql命令+show语法
  19. Linux中./configure文件配置详解
  20. open /run/flannel/subnet.env: no such file or directory

热门文章

  1. php防止cc攻击代码,防cc攻击PHP防CC攻击实现代码
  2. 广州计算机专业王健,王健-计算机与信息工程学院
  3. 基于matlab的数字下变频器的设计与仿真应用,基于MATLAB的数字下变频器的没汁与仿真应用...
  4. python和qt哪个好_做个小的桌面用node还是QT比较好? - Web开发 - WebDev - 水木社区...
  5. 判别学习与生成学习的区别
  6. 相同类方法之间调用,注解失效的问题
  7. 利用Arthas排查NoSuchMethodError
  8. ABC 189 E - Rotate and Flip 矩阵转移
  9. CF1497E2 Square-free division (hard version)
  10. 牛客题霸 [没有重复项数字的所有排列] C++题解/答案