文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Spring之AOP两种代理机制对比分析(JDK和CGLib动态代理)

2023-05-19 08:57

关注

Spring AOP两种代理机制对比

Spirng的AOP的动态代理实现机制有两种,分别是:

JDK动态代理

具体实现原理:

1、通过实现InvocationHandlet接口创建自己的调用处理器

2、通过为Proxy类指定ClassLoader对象和一组interface来创建动态代理

3、通过反射机制获取动态代理类的构造函数,其唯一参数类型就是调用处理器接口类型

4、通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数参入

JDK动态代理是面向接口的代理模式,如果被代理目标没有接口那么Spring也无能为力,

Spring通过java的反射机制生产被代理接口的新的匿名实现类,重写了其中AOP的增强方法。

CGLib动态代理

CGLib是一个强大、高性能的Code生产类库,可以实现运行期动态扩展java类,Spring在运行期间通过 CGlib继承要被动态代理的类,重写父类的方法,实现AOP面向切面编程呢。

两者对比:

JDK动态代理是面向接口,在创建代理实现类时比CGLib要快,创建代理速度快。

CGLib动态代理是通过字节码底层继承要代理类来实现(如果被代理类被final关键字所修饰,那么抱歉会失败),在创建代理这一块没有JDK动态代理快,但是运行速度比JDK动态代理要快。

使用注意:

如果要被代理的对象是个实现类,那么Spring会使用JDK动态代理来完成操作(Spirng默认采用JDK动态代理实现机制)

如果要被代理的对象不是个实现类那么,Spring会强制使用CGLib来实现动态代理。

那么如何选择的使用代理机制了?

通过配置Spring的中<aop:config>标签来显示的指定使用动态代理机制 proxy-target-class=true表示使用CGLib代理,如果为false就是默认使用JDK动态代理

SpringAOP两种代理原理

  

SpringAOP代理

spingAOP代理有两种:

JDK动态代理

JDK为什么一定要目标类实现一个接口呢,这其实就得看看JDK动态代理的原理了,其实JDK动态代理它是先生成一个代理类然后他也是实现了目标类实现的接口里面的方法,只是他还是调用的是目标类的方法。

下面我们来自定义实现一下

//创建一个接口
public interface StudentBiz {
    int add(String name);
    void update(String name);
    void find (String name);
}
//创建一个类实现那个接口
public class StudentBizimpl implements StudentBiz{
    @Override
    public int add(String name) {
        System.out.println("调用了studentBizimpl中的add"+name);
        return 100;
    }
    @Override
    public void update(String name) {
        System.out.println("调用了studentBizimpl中的update"+name);
    }
    @Override
    public void find(String name) {
        System.out.println("调用了studentBizimpl中的find"+name);
    }
}
//jdk动态代理三大重点
// 1.有目标类的引用
// 2.有一个创建代理实例的方法createProxy()里面有Proxy.newProxyInstance()方法来创建代理实例
// 3.有一个回调方法invoke
public class LogAspect implements InvocationHandler {
    private Object target;//目标类的对象
    public LogAspect(Object target){
        this.target=target;
    }
    public Object createProxy(){
        //新建一个代理实例
        //                           第一个参数是类加载器                        第二个是得获取到目标类实现的接口       第三个是代理类对象
        return Proxy.newProxyInstance(this.target.getClass().getClassLoader(),this.target.getClass().getInterfaces(),this);
    }
    @Override//回调方法   当jvm调用代理对象的被代理的方法时,会由jvm自动调用这个invoke
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("代理类对象:"+proxy.getClass());
        System.out.println("目标的方法:"+method);
        System.out.println("方法的参数:"+args);
        log();//这里就可以加增强    具体哪些方法加得看切入点表达式来判断
        Object o=method.invoke(this.target,args);//激活目标类方法
        return o;
    }
    private void log(){
        System.out.println("前置增强");
    }
}

下面我们再来做一个测试类:

public class Test {
    public static void main(String[] args) throws IllegalAccessException, InstantiationException {
        StudentBiz sbm=new StudentBizimpl();
        LogAspect la=new LogAspect(sbm);//放目标类对象
        Object o=la.createProxy();//创建一个代理类
        if (o instanceof StudentBiz){
            StudentBiz sb=(StudentBiz)o;
            sb.add("张三");//这里就会自动回调invoke方法
        }
    }
}

得到以下结果:

CGLIB代理

CGLib是一个强大、高性能的Code生产类库,可以实现运行期动态扩展java类,Spring在运行期间通过 CGlib继承要被动态代理的类,重写父类的方法,实现AOP面向切面编程呢。

CGLIB代理其实也就是生成一个代理对象他也继承了目标类的父类中的方法,再通过回调自身引用目标类的方法完成代理.

下面来简单地自定义实现一下

//做一个cglib代理类
public class LogAspectcglib implements MethodInterceptor {
    private Object target;
    public LogAspectcglib(Object target){
        this.target=target;
    }
    public Object createProxy(){
        Enhancer enhancer=new Enhancer();//用于生成代理对象
        enhancer.setSuperclass(this.target.getClass());//设置父类
        enhancer.setCallback(this);//设置回调用对象为本身
        return enhancer.create();//创建代理对象
    }
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("代理类对象"+o.getClass());
        System.out.println("目标类的方法"+method);
        System.out.println("目标方法参数"+objects);
        System.out.println("要代理的方法"+methodProxy);
       Object returnvalue= method.invoke(this.target,objects);
        return returnvalue;
    }
}

测试类:

public class Test {
    public static void main(String[] args) throws IllegalAccessException, InstantiationException {
        StudentBizimpl sbm=new StudentBizimpl();
        LogAspectcglib lac=new LogAspectcglib(sbm);
        Object o=lac.createProxy();
        if (o instanceof StudentBizimpl){
            StudentBizimpl sb=(StudentBizimpl) o;
            sb.add("张三");
        }
    }
}

得到结果:

两者对比

使用注意

如果要被代理的对象是个实现类,那么Spring会使用JDK动态代理来完成操作(Spirng默认采用JDK动态代理实现机制)

如果要被代理的对象不是个实现类那么,Spring会强制使用CGLib来实现动态代理。

如果要强制使用CGLIB代理则需在xml中配置如下:

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

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程网。

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯