Java * 的多种实现方式

作者:卡修斯 时间:2023-11-20 05:23:14 

目录
  • 一、 * 简介

  • 二、 * 的多种实现

    • 1. 基于JDK的实现

    • 2. 基于cglib的实现

  • 三、为什么要有基于cglib的实现

    • 四、两种方式的适用场景

      • JDK *

        • 优点

        • 缺点

        • 适用场景

      • cglib

        • 优点

        • 缺点

        • 适用场景

    一、 * 简介

    优势:在不修改源码的情况下,对目标方法进行相应的增强。

    作用:完成程序功能之间的松耦合。

    二、 * 的多种实现

    • JDK代理:基于接口的 * 技术(缺点,目标对象必须有接口,如果没有接口,则无法完成 * 的实现)

    • cglib代理:基于父类的 * 技术

    两者的区别如图所示:

    Java  * 的多种实现方式

    1. 基于JDK的实现

    目标接口类:


    public interface TargetInterface {
    public void save();

    public void print(String str);
    }

    目标类:


    public class Target implements TargetInterface{

    public void save() {
    System.out.println("save running...");
    }

    public void print(String str) {
    System.out.println(str);
    }

    }

    增强类:


    public class Advice {
    public void before() {
    System.out.println("前置增强");
    }

    public void after() {
    System.out.println("后置增强");
    }
    }

    测试类:


    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;

    public class ProxyTest {

    public static void main(String[] args) {

    //目标对象
    final Target target = new Target();

    //增强对象
    final Advice advice = new Advice();

    TargetInterface proxyInstance = (TargetInterface)Proxy.newProxyInstance(
    target.getClass().getClassLoader(), //目标对象类加载器
    target.getClass().getInterfaces(), //目标对象相同的接口字节码对象数组
    new InvocationHandler() {
    //调用代理对象的任何方法,实质执行的都是invoke方法
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{
    advice.before();//前置增强
    Object invoke = method.invoke(target, args);//执行目标方法
    advice.after();//后置增强
    System.out.println();
    return invoke;
    }
    });

    //代理对象的方法测试
    proxyInstance.save();

    proxyInstance.print("JDK * ");
    }

    }

    运行截图:

    Java  * 的多种实现方式

    2. 基于cglib的实现

    需要导入Jar包,如果是maven项目,则在pom.xml文件加入如下配置:


    <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>4.2.4.RELEASE</version>
    </dependency>

    目标类:


    public class Target {
    public void save() {
    System.out.println("save running...");
    }

    public void print(String str) {
    System.out.println(str);
    }
    }

    增强类:


    public class Advice {

    public void before() {
    System.out.println("前置增强");
    }

    public void after() {
    System.out.println("后置增强");
    }

    }

    测试类:


    import java.lang.reflect.Method;

    import org.springframework.cglib.proxy.Enhancer;
    import org.springframework.cglib.proxy.MethodInterceptor;
    import org.springframework.cglib.proxy.MethodProxy;

    public class ProxyTest {

    public static void main(String[] args) {
    final Target target = new Target();
    final Advice advice = new Advice();

    //返回值就是动态生成的代理对象,基于cglib
    //创建增强器
    Enhancer enhancer = new Enhancer();

    //设置父类(目标)
    enhancer.setSuperclass(Target.class);

    //设置回调
    enhancer.setCallback(new MethodInterceptor() {
    public Object intercept(Object o, Method method, Object[] obj, MethodProxy methodProxy) throws Throwable{
    advice.before();
    Object invoke = method.invoke(target, obj);
    advice.after();
    System.out.println();
    return invoke;
    }
    });

    //创建代理对象
    Target proxy = (Target)enhancer.create();

    //测试代理方法
    proxy.save();
    proxy.print("基于cglib实现动态规划");

    }

    }

    运行截图:

    Java  * 的多种实现方式

    三、为什么要有基于cglib的实现

    使用JDK * 实现时,最大限制是被增强对象必须实现接口,并且增强的方法只能是接口中声明的方法。但在实际的项目中,可能总是存在对不实现业务接口的对象进行增强的需求,这时JDK * 将无能为力。

    四、两种方式的适用场景

    JDK *

    优点

    • 不依赖第三方jar包, 使用方便

    • 随着JDK的升级,JDK * 的性能在稳步提升

    缺点

    • 只能代理实现了接口的类

    • 执行速度较慢

    适用场景

    • 如果你的程序需要频繁、反复地创建代理对象,则JDK * 在性能上更占优。

    cglib

    优点

    由于是动态生成字节码实现代理,因此代理对象的执行速度较快, 约为JDK * 的1.5 ~ 2倍
    可以代理没有实现接口的对象

    缺点

    • 不能代理final类

    • 动态生成字节码虽然执行较快,但是生成速度很慢,根据网上一些人的测试结果,cglib创建代理对象的速度要比JDK慢10 ~ 15倍。

    适用场景

    • 不需要频繁创建代理对象的应用,如Spring中默认的单例bean,只需要在容器启动时生成一次代理对象。

    来源:https://juejin.cn/post/6970512671368019981

    标签:Java, ,
    0
    投稿

    猜你喜欢

  • Android开发使用strings.xml多语言翻译解决方案

    2023-06-27 14:19:24
  • 极简的Resty服务端和客户端RESTful框架

    2022-01-19 19:51:00
  • java异步编程之一文看完其异步函数表

    2021-12-25 10:57:39
  • List集合多个复杂字段判断去重的案例

    2022-08-01 16:23:28
  • 快速解决android webview https图片不显示的问题

    2021-09-23 22:38:52
  • Android仿今日头条APP实现下拉导航选择菜单效果

    2023-09-15 07:21:05
  • springboot与mybatis整合实例详解(完美融合)

    2023-01-14 09:25:33
  • 解决Android WebView拦截url,视频播放加载失败的问题

    2023-10-24 02:22:25
  • spring boot 实现配置多个DispatcherServlet最简单方式

    2023-12-18 03:24:46
  • Java中ArrayList和LinkedList区别

    2023-09-06 20:43:09
  • C# 解析XML和反序列化的示例

    2023-02-20 01:16:52
  • Opencv图像处理之轮廓外背景颜色改变

    2022-02-17 01:33:34
  • C#通过html调用WinForm的方法

    2022-02-26 03:53:16
  • Java方法调用解析静态分派动态分派执行过程

    2023-05-03 04:32:40
  • android仿支付宝密码输入框效果

    2021-08-06 12:14:01
  • Android中AsyncTask与handler用法实例分析

    2023-12-04 00:01:52
  • Android实现二级列表购物车功能

    2022-08-28 09:26:28
  • Spring Boot + Mybatis 实现动态数据源案例分析

    2023-05-15 12:13:47
  • Java日期与时间类原理解析

    2021-07-20 14:00:36
  • Java中Optional的正确用法与争议点详解

    2023-11-12 03:50:21
  • asp之家 软件编程 m.aspxhome.com