动态代理jdk的Proxy与spring的CGlib

1. 为什么要使用动态代理?

动态代理:在不改变原有代码的情况下上进行对象功能增强 使用代理对象代替原来的对象完成功能 进而达到拓展功能的目的

2.JDK Proxy 动态代理面向接口的动态代理

特点:

  1. 一定要有接口和实现类的存在 代理对象增强的是实现类 在实现接口的方法重写的方法
  2. 生成的代理对象只能转换成 接口的不能转换成 被代理类
  3. 代理对象只能增强接口中定义的方法 实现类中其他和接口无关的方法是无法增强的
  4. 代理对象只能读取到接口中方法上的注解 不能读取到实现类方法上的注解
    使用方法:
public class Test1 {
    public static void main(String[] args) {
        Dinner dinner=new Person("张三");
        // 通过Porxy动态代理获得一个代理对象,在代理对象中,对某个方法进行增强
//        ClassLoader loader,被代理的对象的类加载器
        ClassLoader classLoader = dinner.getClass().getClassLoader();
//        Class[] interfaces,被代理对象所实现的所有接口
        Class[] interaces= dinner.getClass().getInterfaces();
//        InvocationHandler h,执行处理器对象,专门用于定义增强的规则
        InvocationHandler handler = new InvocationHandler(){
            // invoke 当我们让代理对象调用任何方法时,都会触发invoke方法的执行
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//                Object proxy, 代理对象
//                Method method,被代理的方法
//                Object[] args,被代理方法运行时的实参
                Object res=null;
               if(method.getName().equals("eat")){
                   System.out.println("饭前洗手");
                   // 让原有的eat的方法去运行
                   res =method.invoke(dinner, args);
                   System.out.println("饭后刷碗");
               }else{
                   // 如果是其他方法,那么正常执行就可以了
                   res =method.invoke(dinner, args);
               }
                return res;
            }
        };
        Dinner dinnerProxy =(Dinner) Proxy.newProxyInstance(classLoader,interaces,handler);
        //dinnerProxy.eat("包子");
        dinnerProxy.drink();
    }
}
interface Dinner{
    void eat(String foodName);
    void drink();
}
class Person implements Dinner{
    private String name;
    public Person(String name) {
        this.name = name;
    }
    @Override
    public void eat(String foodName) {
        System.out.println(name+"正在吃"+foodName);
    }
    @Override
    public void drink( ) {
        System.out.println(name+"正在喝茶");
    }
}
class Student implements Dinner{
    private String name;
    public Student(String name) {
        this.name = name;
    }
    @Override
    public void eat(String foodName) {
        System.out.println(name+"正在食堂吃"+foodName);
    }
    @Override
    public void drink( ) {
        System.out.println(name+"正在喝可乐");
    }
}

3.CGlib动态代理

cglib动态代理模式是面向父类

特点:

  1. 面向父类的和接口没有直接关系
    2.不仅可以增强接口中定义的方法还可以增强其他方法
    3.可以读取父类中方法上的所有注解
  2. 使用实例
public class Test1 {
    @Test
    public void testCglib(){
        Person person =new Person();
        // 获取一个Person的代理对象
        // 1 获得一个Enhancer对象
        Enhancer enhancer=new Enhancer();
        // 2 设置父类字节码
        enhancer.setSuperclass(person.getClass());
        // 3 获取MethodIntercepter对象 用于定义增强规则
        MethodInterceptor methodInterceptor=new MethodInterceptor() {
            @Override
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                /*Object o,  生成之后的代理对象 personProxy
                Method method,  父类中原本要执行的方法  Person>>> eat()
                Object[] objects, 方法在调用时传入的实参数组
                MethodProxy methodProxy  子类中重写父类的方法 personProxy >>> eat()
                */
                Object res =null;
                if(method.getName().equals("eat")){
                    // 如果是eat方法 则增强并运行
                    System.out.println("饭前洗手");
                    res=methodProxy.invokeSuper(o,objects);
                    System.out.println("饭后刷碗");
                }else{
                    // 如果是其他方法 不增强运行
                    res=methodProxy.invokeSuper(o,objects); // 子类对象方法在执行,默认会调用父类对应被重写的方法
                }
                return res;
            }
        };
        // 4 设置methodInterceptor
        enhancer.setCallback(methodInterceptor);
        // 5 获得代理对象
        Person personProxy = (Person)enhancer.create();
        // 6 使用代理对象完成功能
        personProxy.eat("包子");
    }
}
class Person  {
    public Person( ) {
    }
    public void eat(String foodName) {
        System.out.println("张三正在吃"+foodName);
    }
}

两个动态代理的区别

  1. JDK动态代理是面向接口的,只能增强实现类中接口中存在的方法。CGlib是面向父类的,可以增强父类的所有方法
  2. JDK得到的对象是JDK代理对象实例,而CGlib得到的对象是被代理对象的子类

生活虽然苦闷,但跑起来总是带风!

Original: https://www.cnblogs.com/threeAgePie/p/15832586.html
Author: 三只蛋黄派
Title: 动态代理jdk的Proxy与spring的CGlib

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/573322/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • 快速登陆linux服务器

    前言 本文适用于喜欢原生终端的用户,钟爱第三方ssh客户端的可以无视….客户端可以保存用户信息和密码,比较无脑。mac可以使用终端,win可以使用git的bash。 上…

    Java 2023年6月5日
    075
  • SpringBoot配置Swagger2接口未显示分析

    0.背景 项目A继承自项目B, SpringBoot为 1.5.16.RELEASE B com.**** ****-SNAPSHOT 1.配置信息 项目A中配置的 Swagger…

    Java 2023年6月5日
    087
  • 一文读懂并发与并行

    作者: 雅各布·詹科夫原文: http://tutorials.jenkov.com/java-concurrency/concurrency-vs-parallelism.htm…

    Java 2023年6月13日
    0134
  • Android自定义View学习(1)——基础知识介绍

    原文:Android自定义View学习(1)——基础知识介绍 – Stars-One的杂货小窝 准备学习自定义View,介绍一下先了解了下相关的前置基础知识,特此总结 …

    Java 2023年6月13日
    068
  • [Java学习笔记] Java异常机制(也许是全网最独特视角)

    throw 和 throws 关键字用于主动抛出异常。 两个关键字的区别是,throw用于抛出一个异常,而throws用于声明方法可能抛出的异常。 throw只能 抛出一个异常对象…

    Java 2023年6月6日
    061
  • ArrayList扩容机制

    写在前面 数据结构在面试中基本都是常问的,但是一般开发中基本上都是在使用没有去关心过怎么实现的。 在数据结构中,链表是一种线性存储结构,也就是常说的线性表。 概念:线性表,是数据结…

    Java 2023年6月5日
    078
  • 打造适合自己的知识库

    终生学习,终生教育。 对于知识工作者来说,知识库是持续支撑整个职业生涯的重要基础。程序员,算是半个知识工作者工种。 知识库可以看做是海量资源库的本地缓存。它的特点是:少而精要,重点…

    Java 2023年6月9日
    072
  • 跟着柴毛毛学Spring(3)——简化Bean的配置

    通过前面的学习。我们会感觉到对于一个有较多Bean的大项目,Spring的配置会比較复杂。 那么接下来我们就介绍怎样简化Spring的配置。 简化Spring的配置主要分为两类:1…

    Java 2023年5月30日
    053
  • MySQL 索引简介

    索引的含义和特点 索引有其明显的优势,也有不可避免的缺点: 创建和维护索引同样需要耗费时间,并随着数据量的增加而增加 索引也会占用一定的物理空间 增加、删除和修改数据时,要动态地维…

    Java 2023年6月8日
    073
  • SpringBoot定时任务-Spring自带的定时任务是如何实现的?有何注意点?

    通过前文我们基本梳理了定时任务体系:Timer和ScheduledExecutorService是JDK内置的定时任务方案,以及Netty内部基于时间轮实现的HashedWheel…

    Java 2023年6月6日
    082
  • 一文带你搞懂 JWT 常见概念 & 优缺点

    在 JWT 基本概念详解这篇文章中,我介绍了: 什么是 JWT? JWT 由哪些部分组成? 如何基于 JWT 进行身份验证? JWT 如何防止 Token 被篡改? 如何加强 JW…

    Java 2023年6月9日
    084
  • java基础篇 —— java创建对象有哪几种方法?

    java创建对象的方法 1.用new 语句创建对象,这是最常用的创建对象的方式。 2.运用反射机制,调用Java.lang.Class 或者java.lang.reflect.Co…

    Java 2023年6月5日
    090
  • 日常踩坑

    有人的地方就有江湖,有代码的地方就有坑 一。集合 List与Set继承自Collection。Collection提供定义了一个移除元素的接口 可以看出,在Collection中该…

    Java 2023年6月9日
    098
  • 重学Java(一):什么是对象

    本系列文章内容来自于《Thinking in Java》作者的最新续作《On Java》基础卷,作者根据最新 Java 8、11、17的内容,重讲了Java的编程思想,值得初学者阅…

    Java 2023年6月7日
    079
  • spring整合activemq发送MQ消息[queue模式]实例

    queue类型消息 pom依赖 junit junit 4.11 test org.apache.activemq activemq-all 5.11.1 org.springfr…

    Java 2023年5月30日
    078
  • Spring-Boot-Actuator

    1、Actuator 分布式导致部署服务的增多,运维人员压力倍增,传统的运维方法已经不适应相应的变化,需要对应的监控措施来确保衡量服务的运行情况。actuator为Spring B…

    Java 2023年6月8日
    078
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球