java中的静态代理、jdk动态代理以及CGLIB 动态代理

这篇具有很好参考价值的文章主要介绍了java中的静态代理、jdk动态代理以及CGLIB 动态代理。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

代理模式是一种比较好理解的设计模式。简单来说就是 我们使用代理对象来代替对真实对象(real object)的访问,这样就可以在不修改原目标对象的前提下,提供额外的功能操作,扩展目标对象的功能
那以下文章主要谈三种代理模式,分别是静态代理,jdk的动态代理,cglib的动态代理

本文相关代码已提交至gitee仓库 链接放在了文末 有需要自取。

1.静态代理

简要描述

静态代理中,我们对目标对象的每个方法的增强都是手动完成的,非常不灵活(比如接口一旦新增加方法,目标对象和代理对象都要进行修改)且麻烦(需要对每个目标类都单独写一个代理类)

实现

1.创建一个接口

/**
 * @program: Blog-agency
 * @description:
 * @author: Daigl
 * @create: 2022-12-02 20:37
 **/
public interface SmsService {

    String send(String message);
}

2.创建一个实现类

该类实现上面的接口,并重写里面的send方法。即我们的目标方法

/**
 * @program: Blog-agency
 * @description:
 * @author: Daigl
 * @create: 2022-12-02 20:38
 **/
public class SmsServiceImpl implements SmsService{


    @Override
    public String send(String message) {
        System.out.println("目标方法:" + message);
        return message;
    }
}

3.创建一个代理类

/**
 * @program: Blog-agency
 * @description:
 * @author: Daigl
 * @create: 2022-12-02 20:39
 **/
public class SmsProxy implements SmsService{

    //定义一个smsService的字段
    private SmsService smsService;

    //在初始化该代理类的时候,带一个参数 smsService 给上面的字段赋值
    public SmsProxy(SmsService smsService){
        this.smsService = smsService;
    }

    //重写send方法,并对send方法做加强(前后新增输出)
    //这也是静态代理的麻烦之处 当我们代理的接口新增方法时,我们的代理类须同时修改
    @Override
    public String send(String message) {
        System.out.println("前置增强,可新增自己的业务代码");

        String targetMethod = smsService.send(message);

        System.out.println("后置增强,可新增自己的业务代码");

        return null;
    }
}

4.创建主函数

/**
 * @program: Blog-agency
 * @description:
 * @author: Daigl
 * @create: 2022-12-02 20:42
 **/
public class Main {

    public static void main(String[] args) {
        SmsServiceImpl smsService = new SmsServiceImpl();
        SmsProxy smsProxy = new SmsProxy(smsService);
        smsProxy.send("java");
    }

}

5.输出

前置增强,可新增自己的业务代码
目标方法:java
后置增强,可新增自己的业务代码

总结

静态代理很好的实现了在不修改原有代码的基础上进行业务拓展的功能,即我们上面的代码 实现的在目标方法执行前后 执行我们的业务代码

但是静态代理是代理类在创建的时候,接口以及代理类就已经确定了,因此一个静态代理类只能代理一个类,并且当目标类的方法新增后,静态代理类也得随之修改,造成代码的冗余。

2.jdk动态代理

简要描述

为了解决静态代理的不足(代码冗余以及代码写死的缺点),于是便有了动态代理

动态代理是指代理类在程序运行时进行创建的代理方式。这种情况下,代理类并不是在Java代码中定义的,而是在运行时根据Java代码动态生成的。(动态代理中的代理类并不要求在编译期就确定,而是可以在运行期动态生成,从而实现对目标对象的代理功能)
但他有一个致命的缺点,只能代理实现了接口的类

实现

1.创建一个接口

/**
 * @program: Blog-agency
 * @description:
 * @author: Daigl
 * @create: 2022-12-02 20:37
 **/
public interface SmsService {

    String send(String message);
}

2.创建一个实现类

public class SmsServiceImpl implements SmsService {
    @Override
    public String send(String message) {
        System.out.println("目标方法:" + message);
        return message;
    }
}

3.创建一个代理类

/**
 * @program: Blog-agency
 * @description:
 * @author: Daigl
 * @create: 2022-12-02 21:21
 **/
//代理类
public class DebugInvocationHandler{
        private SmsService smsService;

        //1.构造器 传入动态绑定的对象  接口的某一子类
        public DebugInvocationHandler(SmsService smsService){
            this.smsService = smsService;
        }

        /**
         * 2.得到一个代理的对象  通过这个方法 可以去调用方法
         * @return
         */
        public SmsService getProxy(){
            //a.凑第一个参数 类加载器
            ClassLoader classLoader = smsService.getClass().getClassLoader();

            //b.凑第二个参数 要代理的对象/被执行对象 的接口信息,底层是通过接口来完成调用
            Class<?>[] interfaces = smsService.getClass().getInterfaces();

            //c.凑第三个参数 InvocationHandler
            //使用了匿名内部类方法
            InvocationHandler invocationHandler = new InvocationHandler() {

                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    System.out.println("前置增强,可新增自己的业务代码");
                    // smsService 是 代理中的 真实对象
                    // args 是方法参数 比如我们调用的是send方法 传过来的参数是java 那这里就是一个数组 里面有一个值 java
                    Object result = method.invoke(smsService, args);
                    System.out.println("后置增强,可新增自己的业务代码 ");
                    return result;
                }
            };
        //最主要的是这个方法  给这个方法凑参数
        //Proxy.newProxyInstance 返回的是Object类型 我们可以给他强转为SmsService 此时他已经是一个单例的对象
        //用该对象去调用某一个方法时,会走到上面的invoke方法
        SmsService proxy = (SmsService) Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);
        return proxy;
    }
}

5.输出

/**
 * @program: Blog-agency
 * @description:
 * @author: Daigl
 * @create: 2022-12-02 21:23
 **/
public class Main {
    public static void main(String[] args) {
        //传入的时需要代理的实现类的对象
        DebugInvocationHandler debugInvocationHandler = new DebugInvocationHandler(new SmsServiceImpl());
        SmsService proxy = debugInvocationHandler.getProxy();
        proxy.send("java");
    }
}

3.CGLIB动态代理

简要描述

一个第三方代码生成类库,运行时在内存中动态生成一个子类对象从而实现对目标对象功能的扩展。 通过继承目标类,在子类中重写父类同名方法,实现功能修改(重写的方法不能是final)

和jdk动态代理形成互补。在java源码中,实现了接口的类的代理用jdk动态代理,没有实现的用cglib代理

实现

1. 创建需要代理的类。此时没有接口

/**
 * @program: Blog-agency
 * @description:
 * @author: Daigl
 * @create: 2022-12-02 21:55
 **/
public class AliSmsService {
    public String send(String message) {
        System.out.println("目标方法:" + message);
        return message;
    }
}

2.引入cglib依赖

       <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>3.3.0</version>
        </dependency>

3.创建代理类

/**
 * @program: Blog-agency
 * @description:
 * @author: Daigl
 * @create: 2022-12-02 21:56
 **/
public class CglibMethodInterceptor implements MethodInterceptor {


    /**
     * @param o           代理对象(增强的对象)
     * @param method      被拦截的方法(需要增强的方法)
     * @param args        方法入参
     * @param methodProxy 用于调用原始方法
     */
    @Override
    public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        //调用方法之前,我们可以添加自己的操作
        System.out.println("前置增强,可新增自己的业务代码");
        Object object = methodProxy.invokeSuper(o, args);
        //调用方法之后,我们同样可以添加自己的操作
        System.out.println("后置增强,可新增自己的业务代码");
        return object;
    }

}

4.创建获取代理对象的工厂类

/**
 * @program: Blog-agency
 * @description:
 * @author: Daigl
 * @create: 2022-12-02 21:58
 **/
public class CglibProxyFactory {

    public static Object getProxy(Class<?> clazz) {
        // 创建动态代理增强类
        Enhancer enhancer = new Enhancer();
        // 设置类加载器
        enhancer.setClassLoader(clazz.getClassLoader());
        // 设置被代理类
        enhancer.setSuperclass(clazz);
        // 设置我们自定定义的代理类(方法拦截器)
        enhancer.setCallback(new CglibMethodInterceptor());
        // 创建代理类
        return enhancer.create();
    }
}

5.创建主函数

/**
 * @program: Blog-agency
 * @description: ]
 * @author: Daigl
 * @create: 2022-12-02 21:58
 **/
public class Main {
    public static void main(String[] args) {
        
        Object object = CglibProxyFactory.getProxy(AliSmsService.class);
        AliSmsService aliSmsService = (AliSmsService) object;
        aliSmsService.send("java");

    }
}

6.输出

前置增强,可新增自己的业务代码
目标方法:java
后置增强,可新增自己的业务代码

谢谢大家看完。相关代码已经放在gitee:https://gitee.com/gaoludai/blog文章来源地址https://www.toymoban.com/news/detail-679764.html

到了这里,关于java中的静态代理、jdk动态代理以及CGLIB 动态代理的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 3_代理模式(动态代理JDK原生和CGLib)

    1.概念 代理模式(Proxy Pattern )是指 为其他对象提供一种代理,以控制对这个对象的访问 ,属于结构型模式。 在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。 使用代理模式主要有两个目的: 一是保护目标

    2024年01月17日
    浏览(41)
  • Spring Boot 中的 AOP,到底是 JDK 动态代理还是 Cglib 动态代理

    大家都知道,AOP 底层是动态代理,而 Java 中的动态代理有两种实现方式: 基于 JDK 的动态代理 基于 Cglib 的动态代理 这两者最大的区别在于基于 JDK 的动态代理需要被代理的对象有接口,而基于 Cglib 的动态代理并不需要被代理对象有接口。 那么,Spring 中的 AOP 是怎么实现的

    2024年02月12日
    浏览(36)
  • 动态代理JDK与cglib的区别之:如何处理被代理方法中的This调用

    关于 JDK 与 cglib 动态代理的使用不是本文关注的重点,如有不清楚的同学可以查询相关资料进行了解。本文主要是要讲一下在面对方法存在嵌套调用时 JDK 与 cglib 动态代理的区别以及原因。 先看下测试代码,注意下 TestProxyJDKImpl 的 test1 方法调用了 test2 方法即可。 为了更好说

    2024年02月09日
    浏览(36)
  • Java中的代理模式(二)JDK动态代理

    大家好👋,我是极客涛😎,上一篇中我们对代理模式有两大类,静态代理和动态代理,对于静态代理相信大家都信手拈来。对于动态代理还有两种实现,一种是java原生的Jdk代理,一种是Cglib方式。因为涉及到源码解读,所以我也将分两期完成,本期主要讲讲JDK动态代理的实

    2024年01月22日
    浏览(41)
  • 【面试精讲】Java动态代理是如何实现的?JDK Proxy 和 CGLib 有什么区别?

    Java动态代理是如何实现的?JDK Proxy 和 CGLib 有什么区别? 一、Java动态代理的实现 1、使用JDK Proxy实现动态代理 2、使用CGLib实现动态代理 二、JDK Proxy 与 CGLib 的区别 三、Spring中的动态代理 四、 Lombok代理原理 总结 本文深入探讨了Java动态代理的实现机制,分别介绍了使用JDK

    2024年03月14日
    浏览(46)
  • JDK动态代理和CGLIB动态代理

    JDK动态代理和CGLIB动态代理 ① JDK动态代理只提供接口的代理,不支持类的代理,要求被代理类实现接口。JDK动态代理的核心是InvocationHandler接口和Proxy类,在获取代理对象时,使用Proxy类来动态创建目标类的代理类(即最终真正的代理类,这个类继承自Proxy并实现了我们定义的

    2024年02月07日
    浏览(45)
  • 温故知新之:代理模式,静态代理和动态代理(JDK动态代理)

    代理模式可以在不修改被代理对象的基础上,通过扩展代理类,进行一些功能的附加与增强。 静态代理 是一种代理模式的实现方式,它在编译期间就已经确定了代理对象,需要为每一个被代理对象创建一个代理类。静态代理的实现比较简单,但是每个被代理对象都需要创建

    2024年02月11日
    浏览(48)
  • 【动态代理】JDK动态代理与cglib动态代理源码解析

    UserService ,接口类 UserServiceImpl ,实现类 使用代理,测试效果。 控制台输出: Proxy#newProxyInstance ,生成代理类的实例。 核心在于 getProxyClass0 ,生成代理类的类信息 使用自定义的InvocationHandler作为参数,调用构造函数获取代理类对象实例 WeakCache#get ProxyClassFactory#apply ,实现了

    2024年02月04日
    浏览(45)
  • cglib动态代理、jdk动态代理及spring动态代理使用

    NickelBeforeAdvice.java方法执行之前 NickelAfterReturningAdvice.java方法执行之后 NickelAroundadvice.java环绕方法 NickelThrowAdvice.java抛异常方法 UserService.java抛异常方法 SpringProxtFactoryTest.java测试方法 NickelStaticMethodMatherPointcut.java方法匹配的方法 NickelPointcutAdvisor.java切面方法 SpringProxtFactoryTest.j

    2024年02月15日
    浏览(50)
  • 【spring】jdk动态代理和cglib动态代理的区别

    一、说明 1.spring aop中的动态代理主要有两种方式,jdk动态代理和cglib动态代理 2.从实现接口、继承父类的角度讨论区别 3.从限制角度讨论区别 4.从性能上讨论区别 二、区别 1.jdk动态代理只提供接口类的代理,如果目标类不是接口,只能用cglib代理 2.jdk动态代理会在运行时为目

    2024年02月16日
    浏览(43)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包