【深入理解设计模式】代理设计模式

在这里插入图片描述

代理设计模式:

代理设计模式是一种结构型设计模式,它允许你提供一个替代物或占位符来控制对其他对象的访问。在代理模式中,一个类代表另一个类的功能。这种类型的设计模式属于结构型模式,因为该模式涉及类和对象的组合。

概述

由于某些原因需要给某对象提供一个代理以控制对该对象的访问。这时,访问对象不适合或者不能直接引用目标对象,代理对象作为访问对象和目标对象之间的中介。

Java中的代理按照代理类生成时机不同又分为静态代理动态代理静态代理代理类在编译期就生成,而动态代理代理类则是在Java运行时动态生成。动态代理又有JDK代理和CGLib代理两种。

结构

代理(Proxy)模式分为三种角色:

  • 抽象主题(Subject)类: 通过接口或抽象类声明真实主题和代理对象实现的业务方法。
  • 真实主题(Real Subject)类: 实现了抽象主题中的具体业务,是代理对象所代表的真实对象,是最终要引用的对象。
  • 代理(Proxy)类 : 提供了与真实主题相同的接口,其内部含有对真实主题的引用,它可以访问、控制或扩展真实主题的功能。

代理模式的一些常见用途包括:

  • 远程代理(Remote Proxy):在一个不同的地址空间中代表一个对象。这种方式可以隐藏对象存在于不同地址空间的事实。

  • 虚拟代理(Virtual Proxy):根据需要创建昂贵的对象。比如,当一个图像文件非常大时,可以使用虚拟代理来延迟加载(Lazy Loading)图像,只有当真正需要显示图像时才加载。

  • 保护代理(Protection Proxy):控制对对象的访问权限。这种方式可以根据调用者的身份来限制对某些方法的访问,比如检查调用者是否有足够的权限。

  • 缓存代理(Caching Proxy):为昂贵操作的结果提供缓存,以便在后续请求中直接使用缓存结果,提高性能。

静态代理

静态代理是代理模式的一种形式,它在编译时就已经确定了代理对象和真实对象的关系,即在程序运行前就已经确定了代理对象和真实对象的关系,因此称为静态代理。

在静态代理中,代理类和真实类通常实现同一个接口或继承同一个父类,并且代理类持有真实类的引用。代理类负责将调用转发给真实类,同时可以在调用前后执行一些额外的逻辑,如权限验证、日志记录、性能监控等。

// 抽象主题
interface Subject {
    void request();
}

// 真实主题
class RealSubject implements Subject {
    @Override
    public void request() {
        System.out.println("RealSubject: Handling request.");
    }
}

// 代理
class Proxy implements Subject {
    private RealSubject realSubject;

    public Proxy(RealSubject realSubject) {
        this.realSubject = realSubject;
    }

    @Override
    public void request() {
        // 在调用真实对象前后可以添加一些额外的逻辑
        System.out.println("Proxy: Before requesting.");
        realSubject.request();
        System.out.println("Proxy: After requesting.");
    }
}

// 客户端
public class Client {
    public static void main(String[] args) {
        RealSubject realSubject = new RealSubject();
        Proxy proxy = new Proxy(realSubject);
        
        // 通过代理对象调用真实对象的方法
        proxy.request();
    }
}

静态代理的优点在于:

  • 简单易理解:代理对象可以在不修改真实对象的情况下添加额外的功能,易于理解和实现。
  • 对真实对象的访问进行控制:代理对象可以控制对真实对象的访问权限。

但静态代理也存在一些缺点:

  • 静态代理每次新增功能都需要编写新的代理类,导致类的数量增加。
  • 在代理类中硬编码了对真实对象的引用,一旦真实对象发生变化,代理类也需要相应修改。

静态代理是代理模式的一种简单实现方式,适用于代理对象相对固定且功能不复杂的场景。

动态代理

JDK动态代理

动态代理是一种在运行时生成代理对象的机制,与静态代理不同,它不需要在编译时就确定代理对象和真实对象的关系,而是在程序运行时动态创建代理对象。Java 中的动态代理主要依赖于 java.lang.reflect.Proxy 类和 java.lang.reflect.InvocationHandler 接口。
以下是一个基于JDK的动态代理的示例:

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

// 定义接口
interface Subject {
    void request();
}

// 真实主题类
class RealSubject implements Subject {
    @Override
    public void request() {
        System.out.println("RealSubject: Handling request.");
    }
}

// 实现 InvocationHandler 接口
class DynamicProxy implements InvocationHandler {
    private Object target;

    public DynamicProxy(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 在调用真实对象的方法前后添加额外的逻辑
        System.out.println("DynamicProxy: Before requesting.");
        Object result = method.invoke(target, args);
        System.out.println("DynamicProxy: After requesting.");
        return result;
    }
}

// 客户端
public class Client {
    public static void main(String[] args) {
        // 创建真实对象
        RealSubject realSubject = new RealSubject();
        
        // 创建动态代理对象
        Subject proxy = (Subject) Proxy.newProxyInstance(
                realSubject.getClass().getClassLoader(),
                realSubject.getClass().getInterfaces(),
                new DynamicProxy(realSubject));
        
        // 通过代理对象调用真实对象的方法
        proxy.request();
    }
}

在上面的示例中,DynamicProxy 类实现了 InvocationHandler 接口,在 invoke 方法中实现了代理逻辑。通过 Proxy.newProxyInstance 方法创建了代理对象,并传入了 DynamicProxy 对象作为 InvocationHandler 的实现。最后,通过代理对象调用真实对象的方法。
示例二:

/**
 * @author OldGj 2024/02/22
 * @version v1.0
 * @apiNote 抽象主题 - 买票接口
 */
public interface SellTicket {
    void sell();
}
/**
 * @author OldGj 2024/02/22
 * @version v1.0
 * @apiNote 具体主题(被代理对象) - 火车站类
 */
public class TrainStation implements SellTicket {

    @Override
    public void sell() {
        System.out.println("火车站卖票");
    }
}
/**
 * @author OldGj 2024/02/22
 * @version v1.0
 * @apiNote 代理对象工厂,用来创建代理对象
 */
public class ProxyFactory {

    // 目标代理对象
    private Object target = new TrainStation();

    public ProxyFactory(Object target) {
        this.target = target;
    }

    public SellTicket getProxy() {
        /*
            newProxyInstance方法的三个参数:
            1.ClassLoader loader,  类加载器,用于加载代理类,使用真实对象的类加载器即可
            2.Class<?>[] interfaces,真实对象所实现的接口,代理模式真实对象和代理对象实现相同的接口
            3.InvocationHandler h  代理对象的调用处理程序
         */
        //使用Proxy方法获取代理对象
        return (SellTicket) Proxy.newProxyInstance(
                target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                new InvocationHandler() {
                    /*
                        InvocationHandler中invoke方法参数说明:
                            proxy : 代理对象
                            method : 对应于在代理对象上调用的接口方法的 Method 实例
                            args : 代理对象调用接口方法时传递的实际参数
                     */
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        System.out.println("DynamicProxy: Before requesting.");
                        Object result = method.invoke(target, args);
                        System.out.println("DynamicProxy: After requesting.");
                        return result;
                    }
                }
        );
    }
}
/**
 * @author OldGj 2024/02/22
 * @version v1.0
 * @apiNote 客户端 - 测试类
 */
public class Client {
    public static void main(String[] args) {
        // 创建目标代理对象
        TrainStation station = new TrainStation();
        // 将目标代理对象传入代理工厂,获取代理工厂对象
        ProxyFactory proxyFactory = new ProxyFactory(station);
        // 根据代理工厂对象获取代理对象
        SellTicket proxy = proxyFactory.getProxy();
        // 使用代理对象对原方法进行扩展和增强
        proxy.sell();
    }
}

使用了动态代理,我们思考下面问题:

  • ProxyFactory是代理类吗?

    ProxyFactory不是代理模式中所说的代理类,而代理类是程序在运行过程中动态的在内存中生成的类。通过阿里巴巴开源的 Java 诊断工具(Arthas【阿尔萨斯】)查看代理类的结构:

    package com.sun.proxy;
    
    import com.itheima.proxy.dynamic.jdk.SellTickets;
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    import java.lang.reflect.UndeclaredThrowableException;
    
    public final class $Proxy0 extends Proxy implements SellTickets {
        private static Method m1;
        private static Method m2;
        private static Method m3;
        private static Method m0;
    
        public $Proxy0(InvocationHandler invocationHandler) {
            super(invocationHandler);
        }
    
        static {
            try {
                m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
                m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
                m3 = Class.forName("com.itheima.proxy.dynamic.jdk.SellTickets").getMethod("sell", new Class[0]);
                m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
                return;
            }
            catch (NoSuchMethodException noSuchMethodException) {
                throw new NoSuchMethodError(noSuchMethodException.getMessage());
            }
            catch (ClassNotFoundException classNotFoundException) {
                throw new NoClassDefFoundError(classNotFoundException.getMessage());
            }
        }
    
        public final boolean equals(Object object) {
            try {
                return (Boolean)this.h.invoke(this, m1, new Object[]{object});
            }
            catch (Error | RuntimeException throwable) {
                throw throwable;
            }
            catch (Throwable throwable) {
                throw new UndeclaredThrowableException(throwable);
            }
        }
    
        public final String toString() {
            try {
                return (String)this.h.invoke(this, m2, null);
            }
            catch (Error | RuntimeException throwable) {
                throw throwable;
            }
            catch (Throwable throwable) {
                throw new UndeclaredThrowableException(throwable);
            }
        }
    
        public final int hashCode() {
            try {
                return (Integer)this.h.invoke(this, m0, null);
            }
            catch (Error | RuntimeException throwable) {
                throw throwable;
            }
            catch (Throwable throwable) {
                throw new UndeclaredThrowableException(throwable);
            }
        }
    
        public final void sell() {
            try {
                this.h.invoke(this, m3, null);
                return;
            }
            catch (Error | RuntimeException throwable) {
                throw throwable;
            }
            catch (Throwable throwable) {
                throw new UndeclaredThrowableException(throwable);
            }
        }
    }
    

    从上面的类中,我们可以看到以下几个信息:

    • 代理类($Proxy0)实现了SellTickets。这也就印证了我们之前说的真实类和代理类实现同样的接口。
    • 代理类($Proxy0)将我们提供了的匿名内部类对象传递给了父类。
  • 动态代理的执行流程是什么样?

    下面是摘取的重点代码:

    //程序运行过程中动态生成的代理类
    public final class $Proxy0 extends Proxy implements SellTickets {
        private static Method m3;
    
        public $Proxy0(InvocationHandler invocationHandler) {
            super(invocationHandler);
        }
    
        static {
            m3 = Class.forName("com.itheima.proxy.dynamic.jdk.SellTickets").getMethod("sell", new Class[0]);
        }
    
        public final void sell() {
            this.h.invoke(this, m3, null);
        }
    }
    
    //Java提供的动态代理相关类
    public class Proxy implements java.io.Serializable {
    	protected InvocationHandler h;
    	 
    	protected Proxy(InvocationHandler h) {
            this.h = h;
        }
    }
    
    //代理工厂类
    public class ProxyFactory {
    
       	 // 目标代理对象
      	private Object target = new TrainStation();
    
     	 public ProxyFactory(Object target) {
        	  this.target = target;
    	  }
    
        public SellTickets getProxyObject() {
            SellTickets sellTickets = (SellTickets) Proxy.newProxyInstance(
                	station.getClass().getClassLoader(),
                    station.getClass().getInterfaces(),
                    new InvocationHandler() {
                        
                        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    
                            System.out.println("代理点收取一些服务费用(JDK动态代理方式)");
                            Object result = method.invoke(station, args);
                            return result;
                        }
                    });
            return sellTickets;
        }
    }
    
    
    //测试访问类
    public class Client {
        public static void main(String[] args) {
        	TrainStation station = new TrainStation();
            //获取代理对象
            ProxyFactory factory = new ProxyFactory(station );
            SellTickets proxyObject = factory.getProxyObject();
            proxyObject.sell();
        }
    }
    

执行流程如下:

  1. 在测试类中通过代理对象调用sell()方法
  2. 根据多态的特性,执行的是代理类($Proxy0)中的sell()方法
  3. 代理类($Proxy0)中的sell()方法中又调用了InvocationHandler接口的子实现类对象的invoke方法
  4. invoke方法通过反射执行了真实对象所属类(TrainStation)中的sell()方法
CGLIB动态代理

CGLIB(Code Generation Library)是一个强大的开源字节码生成类库,它可以在运行时动态生成指定类的子类,并覆盖其中的方法,从而实现动态代理。相比于基于接口的动态代理,CGLIB 动态代理不要求目标对象必须实现接口,因此更加灵活。

CGLIB 动态代理的核心思想是利用字节码生成技术,通过生成目标类的子类,并在子类中重写需要代理的方法,从而达到对目标类的代理控制。

CGLIB是第三方提供的包,所以需要引入jar包的坐标:

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

以下是一个使用 CGLIB 动态代理的简单示例:

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

// 目标类
class RealSubject {
    public void request() {
        System.out.println("RealSubject: Handling request.");
    }
}

// 实现 MethodInterceptor 接口
class DynamicProxy implements MethodInterceptor {
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        // 在调用真实对象的方法前后添加额外的逻辑
        System.out.println("DynamicProxy: Before requesting.");
        Object result = proxy.invokeSuper(obj, args);
        System.out.println("DynamicProxy: After requesting.");
        return result;
    }
}

// 客户端
public class Client {
    public static void main(String[] args) {
        // 创建 Enhancer 对象,用于生成代理类
        Enhancer enhancer = new Enhancer();
        
        // 设置目标类的父类,即需要代理的类
        enhancer.setSuperclass(RealSubject.class);
        
        // 设置回调对象,即实现 MethodInterceptor 接口的对象
        enhancer.setCallback(new DynamicProxy());
        
        // 创建代理对象
        RealSubject proxy = (RealSubject) enhancer.create();
        
        // 通过代理对象调用目标类的方法
        proxy.request();
    }
}

在上面的示例中,我们使用了 CGLIB 提供的 Enhancer 类来生成代理类。通过 setSuperclass 方法设置目标类的父类,即需要代理的类;通过 setCallback 方法设置回调对象,即实现了 MethodInterceptor接口的对象,用于在代理类中增加额外逻辑;最后通过 create 方法创建代理对象。

示例二:

/**
 * @author OldGj 2024/02/22
 * @version v1.0
 * @apiNote 具体主题(被代理对象) - 火车站类
 */
public class TrainStation {

    public void sell() {
        System.out.println("火车站卖票");
    }
}
/**
 * @author OldGj 2024/02/22
 * @version v1.0
 * @apiNote 生成代理对象
 */
public class ProxyFactory implements MethodInterceptor {

	private Object target;

    public ProxyFactory(Object target) {
        this.target = target;
    }
    
    public TrainStation getProxy(){
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(target.getClass());
        enhancer.setCallback(this);
        return (TrainStation) enhancer.create();
    }

    /**
     * intercept方法参数说明:
     * @param o 代理对象
     * @param method 真实对象中的方法的Method实例
     * @param objects 实际参数
     * @param methodProxy 代理对象中的方法的method实例
     * @return 真实对象中的方法的Method返回值
     */
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("DynamicProxy: Before requesting.");	
        Object object = methodProxy.invokeSuper(o, objects);
        System.out.println("DynamicProxy: After requesting.");
        return object;
    }
}
/**
 * @author OldGj 2024/02/22
 * @version v1.0
 * @apiNote 客户端  - 测试类
 */
public class Client {
   public static void main(String[] args) {
        TrainStation station = new TrainStation();
        //创建代理工厂对象
        ProxyFactory factory = new ProxyFactory(station);
        //获取代理对象
        TrainStation proxyObject = (TrainStation) factory.getProxy();

        proxyObject.sell();
    }
}

CGLIB 动态代理相比于基于接口的动态代理更加灵活,不要求目标类必须实现接口,因此更适合对没有实现接口的类进行代理。但是需要注意的是,CGLIB 动态代理生成的代理类是目标类的子类,如果目标类是 final 类,则无法生成子类,因此无法使用 CGLIB 动态代理。

三种代理的对比

  • jdk代理和CGLIB代理

    使用CGLib实现动态代理,CGLIB 动态代理的核心思想是利用字节码生成技术,通过生成目标类的子类,并在子类中重写需要代理的方法,从而达到对目标类的代理控制。,在JDK1.6之前比使用Java反射效率要高。唯一需要注意的是,CGLib不能对声明为final的类或者方法进行代理,因为CGLib原理是动态生成被代理类的子类。

    在JDK1.6、JDK1.7、JDK1.8逐步对JDK动态代理优化之后,在调用次数较少的情况下,JDK代理效率高于CGLib代理效率,只有当进行大量调用的时候,JDK1.6和JDK1.7比CGLib代理效率低一点,但是到JDK1.8的时候,JDK代理效率高于CGLib代理。所以如果(目标类)被代理类有接口使用JDK动态代理,如果没有接口使用CGLIB代理。

  • 动态代理和静态代理

    动态代理与静态代理相比较,最大的好处是接口中声明的所有方法都被转移到调用处理器一个集中的方法中处理(InvocationHandler.invoke)。这样,在接口方法数量比较多的时候,我们可以进行灵活处理,而不需要像静态代理那样每一个方法进行中转。

    如果接口增加一个方法,静态代理模式除了所有实现类需要实现这个方法外,所有代理类也需要实现此方法。增加了代码维护的复杂度。而动态代理不会出现该问题

代理模式的一些常见用途包括:

远程代理(Remote Proxy):在一个不同的地址空间中代表一个对象。这种方式可以隐藏对象存在于不同地址空间的事实。

虚拟代理(Virtual Proxy):根据需要创建昂贵的对象。比如,当一个图像文件非常大时,可以使用虚拟代理来延迟加载(Lazy Loading)图像,只有当真正需要显示图像时才加载。

保护代理(Protection Proxy):控制对对象的访问权限。这种方式可以根据调用者的身份来限制对某些方法的访问,比如检查调用者是否有足够的权限。

缓存代理(Caching Proxy):为昂贵操作的结果提供缓存,以便在后续请求中直接使用缓存结果,提高性能。

优缺点

优点:

  • 代理模式在客户端与目标对象之间起到一个中介作用和保护目标对象的作用;
  • 代理对象可以扩展目标对象的功能;
  • 代理模式能将客户端与目标对象分离,在一定程度上降低了系统的耦合度;

缺点:

  • 增加了系统的复杂度;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/409889.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

外包干了3个月,技术倒退明显...

先说情况&#xff0c;大专毕业&#xff0c;18年通过校招进入湖南某软件公司&#xff0c;干了接近6年的功能测试&#xff0c;今年年初&#xff0c;感觉自己不能够在这样下去了&#xff0c;长时间呆在一个舒适的环境会让一个人堕落!而我已经在一个企业干了四年的功能测试&#xf…

笔记本hp6930p安装Android-x86避坑日记

一、序言 农历癸卯年前大扫除&#xff0c;翻出老机hp6930p&#xff0c;闲来无事&#xff0c;便安装Android-x86玩玩&#xff0c;期间多次入坑&#xff0c;随手记之以避坑。 笔记本配置&#xff1a;T9600,4G内存&#xff0c;120G固态160G机械硬盘 二、Android-x86系统简介 官…

【QT+QGIS跨平台编译】之五十二:【QGIS_CORE跨平台编译】—【qgsexpressionlexer.cpp生成】

文章目录 一、Flex二、生成来源三、构建过程一、Flex Flex (fast lexical analyser generator) 是 Lex 的另一个替代品。它经常和自由软件 Bison 语法分析器生成器 一起使用。Flex 最初由 Vern Paxson 于 1987 年用 C 语言写成。 “flex 是一个生成扫描器的工具,能够识别文本中…

Vue + Echarts页面内存占用高问题解决

Vue Echarts页面内存占用高问题解决 1.问题描述 目前使用的是Vue2 Echarts4.x的组合&#xff0c;页面如下所示。 就是一个类似于神策的数据看板页面&#xff0c;左侧是一个导航栏&#xff0c;右侧看板页面中包含很多个报表图片&#xff0c;其中报表页面中对Echarts图表进…

前端工程化面试题 | 18.精选前端工程化高频面试题

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

【AIGC大模型】跑通wonder3D (windows)

论文链接&#xff1a;https://arxiv.org/pdf/2310.15008.pdf windows10系统 显卡&#xff1a;NVIDIA rtx 2060 一、安装anaconda 二、安装CUDA 11.7 (CUDA Toolkit 11.7 Downloads | NVIDIA Developer) 和 cudnn 8.9.7(cuDNN Archive | NVIDIA Developer)库 CUDA选择自定…

人工智能 — 立体视觉、双目系统

目录 一、立体视觉1、定义2、应用领域3、原理 二、单目系统和双目系统1、单目系统2、双目系统 三、视差 一、立体视觉 1、定义 立体视觉是一种计算机视觉技术&#xff0c;其目的是从两幅或两幅以上的图像中推理出图像中每个像素点的深度信息。 2、应用领域 机器人、辅助驾驶…

《低功耗方法学》翻译——第十四章:电源切换网络设计

第十四章&#xff1a;电源切换网络设计 功率门控是在待机或休眠模式下降低漏电功率最有效的方法&#xff0c;但这种方法存在诸如休眠晶体管占用的硅面积、永久和虚拟电源网络的布线资源以及复杂的功率门控设计和实现过程等开销&#xff0c;影响设计风险和进度。 除了开销外&a…

万界星空科技商业开源MES

一、万界星空科技商业开源MES系统概述&#xff1a; 万界星空科技免费MES、开源MES、商业开源MES、市面上最好的开源MES、MES源代码、适合二开的开源MES。 1.万界星空开源MES制造执行系统的Java开源版本。 开源mes系统包括系统管理&#xff0c;车间基础数据管理&#xff0c;计…

第三节:kafka sarama 遇到Bug?

文章目录 前言一、先上结果二、刨根问底总结 前言 前面两节&#xff0c;我们已经简单应用了sarama的两个类型Client和ClusterAdmin&#xff0c;其中有一个案例是获取集群的ControllerId&#xff0c;但是在后面的测试过程过程中&#xff0c;发现一个问题&#xff0c;返回的Cont…

【基于Ubuntu20.04的Autoware.universe安装过程】方案二:双系统 | 详细记录 | 全过程图文 by.Akaxi

目录 一、Autoware.universe背景 Part-1&#xff1a;安装双系统教程 二、查看Windows引导方式 三、制作安装盘 四、设置电脑配置 1.关闭bitlocker 2.压缩硬盘分区 3.关闭Secure Boot 4.关闭intel RST 5.BIOS设置U盘引导 五、安装Ubuntu20.04 1.ventoy引导 2.安装配…

matlab悬臂梁有限元分析

1、内容简介 略 47-可以交流、咨询、答疑 2、内容说明 略 建模说明 设计一个长方体的悬臂梁&#xff0c;长宽高分别为100m、10m和15m&#xff0c;材料特性为杨氏模量2e5&#xff0c;泊松比0.3&#xff0c; Matlab有限元分析&#xff08;截图&#xff09; 上图为悬臂梁的扰度…

Redis高并发缓存架构性能优化实战

Redis高并发缓存架构性能优化实战 场景1: 中小型公司Redis缓存架构以及线上问题实战 线程A在master获取锁之后&#xff0c;master在同步数据到slave时&#xff0c;master突然宕机(此时数据还没有同步到slave)&#xff0c;然后slave会自动选举成为新的master&#xff0c;此时线…

K8S安装部署

常见的K8S安装部署方式 Minikube Minikube是一个工具&#xff0c;可以在本地快速运行一个单节点微型K8S&#xff0c;仅用于学习、预览K8S的一些特性使用。 部署地址&#xff1a;Install Tools | Kubernetes Kubeadm Kubeadm也是一个工具&#xff0c;提供kubeadm init和kube…

Spring Cloud Alibaba - 利用Nacos实现高效动态线程池管理

文章目录 引言概述什么是动态线程池Nacos简介如何利用Nacos实现动态线程池管理应用场景Code版本说明POM配置文件Nacos Config配置文件加载顺序1. bootstrap.yml的加载2. application.yml的加载注意事项示例 nacos配置Data IdNacos中Data ID的命名格式解释${spring.application.…

【openGL教程08】基于C++的着色器(02)

LearnOpenGL - Shaders 一、说明 着色器是openGL渲染的重要内容&#xff0c;客户如果想自我实现渲染灵活性&#xff0c;可以用着色器进行编程&#xff0c;这种程序小脚本被传送到GPU的显卡内部&#xff0c;起到动态灵活的着色作用。 二、着色器简述 正如“Hello Triangle”一章…

NXP实战笔记(十):S32K3xx基于RTD-SDK在S32DS上配置CAN通信

目录 1、概述 2、SDK配置 2.1、配置目标 2.2、CAN配置 3、代码实现 4、测试结果 1、概述 S32K3xx的FlexCan与之前的S32K1xx很相似,Can的中断掩码寄存器(IMASK3)与中断标志位寄存器(IFLAG3)依赖于邮箱数。 FlexCan配置实例如下 FlexCan的整体图示如下 Protocol Engine…

AI论文速读 | 【综述】(LLM4TS)大语言模型用于时间序列

题目&#xff1a;Large Language Models for Time Series: A Survey 作者&#xff1a;Xiyuan Zhang , Ranak Roy Chowdhury , Rajesh K. Gupta and Jingbo Shang 机构&#xff1a;加州大学圣地亚哥分校&#xff08;UCSD&#xff09; 网址&#xff1a;https://arxiv.org/abs/…

OPENSSL-PKCS7入门知识介绍

1 PKCS7数据结构说明 p7包括6种数据内容&#xff1a;数据(data),签名数据&#xff08;sign&#xff09;&#xff0c;数字信封数据&#xff08;enveloped&#xff09;&#xff0c;签名数字信封数据&#xff08;signed_and_enveloped&#xff09;&#xff0c;摘要数据&#xff08…

Zookeeper客户端命令、JAVA API、监听原理、写数据原理以及案例

1. Zookeeper节点信息 指定服务端&#xff0c;启动客户端命令&#xff1a; bin/zkCli.sh -server 服务端主机名:端口号 1&#xff09;ls / 查看根节点下面的子节点 ls -s / 查看根节点下面的子节点以及根节点详细信息 其中&#xff0c;cZxid是创建节点的事务id&#xff0c…