java之动态代理

news2024/10/5 16:22:41

1 代理模式

  • 代理模式提供了对目标对象额外的访问方式,即通过代理对象访问目标对象,这样可以在不修改原目标对象的前提下,提供额外的功能操作扩展目标对象的功能。简言之,代理模式就是设置一个中间代理来控制访问原目标对象,以达到增强原对象的功能和简化访问方式。但是对于真正的调用来说, 实际上并不关心这个代理对象, 只要能够实现相应的业务逻辑就好。

  • 举个例子,我们生活中经常到火车站去买车票,但是人一多的话,就会非常拥挤,于是就有了代售点,我们能从代售点买车票了,这就是代理模式的体现,代售点代理了火车站售票对象,提供购买车票的方法。

1.1 代理模式

1.1.1 定义

(1)UML类图

  • Subject --- 抽象主题类,定义了代理对象真实对象的共同接口方法,可以理解为定义了某一种业务需求的实现规范。既可以是接口也可以是抽象类,其中声明了需要被实现的方法。

  • RealSubject --- 真实主题类,该类可以被称为被委托类或被代理类,该类定义了代理对象所表示的真实对象,实现了Subject接口方法。

  • Proxy --- 代理类,该类也被称为委托类或代理类,该类中持有一个真实主题类的引用,同样实现了Subject接口。在其实现的接口方法中调用代理类中相应的接口方法,在此基础上附加其他动作。Client端通过代理类间接调用的真实主题类中的方法,由其执行真正的业务逻辑。

  • Client --- 客户端。

要求:代理类和被代理类应该共同实现一个接口,或者是共同继承某个类。

例如:电影公司委托电影院播放电影,电影院想要在播放电影的时候,加一些广告或服务项目赚取收

益。(使用代码来模拟)

(1)静态代理服务接口: MovieService

  • 通用的接口是代理模式实现的基础。 MovieService接口代表电影播放服务

(2)静态代理服务实现类: MovieServiceImpl

  • MovieService 接口的实现类,可以当作电影公司,作为接口实现类,要求必须定义接口中声明的所有方法。

(3)服务的代理类: MovieProxy

  • MovieService 服务的代理类,就是电影服务的代理对象,当作电影院,代理了电影公司提供的电影播放服务。方法实现时,主要调用服务实现类提供的方法,并在其执行前后添加附加功能。

1.1.2相关案例

案例1:静态代理-实操

静态代理服务接口MovieService

package com.StaticProxy;
​
/**
 * 定义一个通用的接口 MovieService,代表电影播放服务
 **/
public interface MovieService {
    void play();
​
​
}
​

静态代理服务实现类 MovieServiceImpl,

package com.StaticProxy;
​
/**
 * 静态代理服务实现类 MovieServiceImpl,
 **/
public class MovieServiceImpl implements MovieService{
    /**
     * 定义MovieService接口的类
     */
//    @Override
    public void play() {
        System.out.println("Showing a movie:Tom and Jerry....");
    }
​
}
​

服务的代理类 MovieProxy

package com.StaticProxy;
​
/**
 * 服务的代理类 MovieProxy
 **/
public class MovieProxy implements MovieService{
    MovieServiceImpl movieService;
​
    /*public static void main(String[] args) {
        test1();
    }*/
   /* public static void test1(){
        movieService.play();
    }*/
​
    public MovieProxy(MovieServiceImpl movieService) {
        super();
        this.movieService = movieService;
    }
​
    /**
     * 重写 play() 方法,调用MovieServiceImpl的play() 方法前后,附加广告提示
     */
//    @Override
    public void play() {
        advertise(true);
        movieService.play();
        advertise(false);
    }
​
    /**
     * 宣传方法
     * @param isStart
     */
    public void advertise(boolean isStart) {
        if(isStart == true){
            System.out.println("The movie starts.");
        }else{
            System.out.println("The movie is over.");
        }
    }
}
​

测试代码

package com.StaticProxy;
​
/**
 * 测试代码
 **/
public class Demo {
    public static void main(String[] args) {
        new MovieProxy(new MovieServiceImpl()).play();
    }
}

输出结果

案例2

package com.StaticProxy1;
/**
 * 静态代理 设计模式
 * 1、真实角色
 * 2、代理角色: 持有真实角色的引用
 * 3、二者 实现相同的接口
 *
 * @author Administrator
 *
 */
public class Demo01 {
    /**
     * @param args
     */
    public static void main(String[] args) {
        //创建真实角色
        Marry you =new You();
        //创建代理角色 +真实角色的引用
        WeddingCompany company =new WeddingCompany(you);
        //执行任务
        company.marry();
    }
​
}
//接口
interface Marry{
    public abstract void marry();
}
//真实角色
class You implements Marry{
​
    public void marry() {
        System.out.println("you and  嫦娥结婚了....");
    }
​
}
//代理角色
class WeddingCompany implements Marry{
    private Marry you;
    public WeddingCompany() {
    }
​
    public WeddingCompany(Marry you) {
        this.you = you;
    }
    private void before(){
        System.out.println("布置猪窝....");
​
    }
    private void after(){
        System.out.println("闹玉兔....");
    }
    public void marry() {
        before();
        you.marry();
        after();
    }
}
​

输出结果

1.1.3 静态代理缺陷

  1. 代理复杂,难于管理

    • 当需要代理的目标类数量较多时,需要为每个目标类手动编写一个代理类,这会导致代码量增加,且难以统一管理和维护。

  2. 代理类依赖目标类

    • 静态代理的代理类与目标类紧密耦合,当目标类发生变化时(如增加、删除或修改方法),代理类也需要进行相应的修改,这增加了维护的复杂性。

  3. 代理类过多

    • 对于每个目标类,都需要一个与之对应的代理类。当目标类数量较多时,会导致代理类数量过多,增加了系统的复杂度。

  4. 不灵活

    • 静态代理在编译时期就确定了代理对象和目标对象,无法动态地改变代理对象。如果需要改变代理对象,需要重新编译和部署代码。

  5. 代码冗余

    • 由于每个目标对象都需要对应一个代理类,这会导致代码的冗余。特别是当有多个目标对象时,会增加代码量和维护成本。

  6. 维护困难

    • 当目标对象发生变化时,代理类也需要同步更新,维护起来相对困难。特别是在有大量代理类时,更新代理类会带来一定的工作量。

  7. 性能考虑

    • 虽然静态代理在编译时期就确定了代理对象和目标对象,因此性能相对较高,但相对于直接调用目标对象的方法,静态代理仍然增加了一层调用开销。

静态代理 vs 动态代理:

  • 静态代理需要手动编写代码让代理类实现某接口。而动态代理则可以让程序在运行时自动在内存中创建一个实现某接口的代理,而不需要去手动定义代理类。

  • 静态代理在程序运行前,代理类的class文件(类字节码)就已经存在了。而动态代理是在运行时动态生成类字节码,并加载到 JVM 中的。

1.2 动态代理

  • 与静态代理相比,多了InvocationHandler角色和一个Proxy角色,InvocationHandler是java提供的一个接口,我们需要定义一个类实现InvocationHandler接口,这里就叫DynamicProxy角色;Proxy是java提供用于动态生成ProxySubject的一个类,它需要ProxySubject继承。

  • 我们看到DynamicProxy在ProxySubject和RealSubject之前起到了中间人的角色,ProxySubject会把事情委托给DynamicProxy来做,而DynamicProxy最终把事情委托给RealSubject来做

动态代理的实现方式有很多种,比如 JDK 动态代理、CGLIB 动态代理等等。

1.2.1 场景实现-JDK动态代理

JDK提供了java.lang.reflect.InvocationHandler接口和java.lang.reflect.Proxy类。

java.lang.reflect.InvocationHandler 接口中仅声明了一个方法invoke(),第一个参数 proxy一般是指代理类,method是被代理的方法,args为方法中声明的形参。

public interface InvocationHandler{
    public Object invode{
    Object proxy,Method method, Object[] args
    }
}

JDK 动态代理常用的API:

  • java.lang.reflect.Proxy 动态代理类中提供的 getProxyClass() 静态方法可以用来获取一个代理Class对象,其接受的参数为类加载器和目标类实现的接口。

  • public static Class<?> getProxyClass(ClassLoader loader, Class<?>... interfaces)Proxy类提供的另一个静态方法 newProxyInstance() 可以直接获取代理实例对象,连创建代理类对象的过程都封装起来了。

  • public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandlerh)loader是类加载器,interfaces 是代理要实现的服务接口,h是一个InvocationHandler对象,表示的是当动态代理对象调用方法的时候会关联到哪一个InvocationHandler对象上,并最终由其调用。

关注 Proxy.newProxyInstance() 方法

(1)判断传入的InvocationHandler实例对象是否为null,并对传入的接口进行克隆权限校验。获取系统安全接口(安全管理器),如果不为空,检查创建代理类所需的权限

(2)查找或生成指定的代理类对象,要求调用此函数之前必须调用checkProxyAccess方法执行权限检查。首先判断接口数量,过多则抛出异常。随后调用 proxyClassCache.get(loader, interfaces) 方法,参数接收类加载器和接口数组,从 proxyClassCache 缓存中获取代理类,如果找不到,则通过ProxyClassFactory创建代理类。

方法二:添加系统参数,将JDK动态代理生成的class文件保存到本地,默认保存路径为

com.sun.proxy

System.getProperties().setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");

随后反编译类文件即可。

JDK动态代理 – 源码浅析:

  • 继承了Proxy类,实现了代理的接口,由于java不能多继承,这里已经继承了Proxy类了,不能再继承其他的类,所以 JDK的动态代理不支持对实现类的代理,只支持接口的代理。

  • 提供了一个使用InvocationHandler作为参数的构造方法

  • 重写了Object类的equals、hashCode、toString,它们都只是简单的调用了InvocationHandler的invoke方法。

  • 生成静态代码块来初始化接口中方法的Method对象,以及Object类的equals、hashCode、toString方法。代理类实现代理接口的play()方法中,只是简单的调用了InvocationHandler的invoke方法,我们可以在invoke方法中进行一些特殊操作,甚至不调用实现的方法,直接返回。

1.2.2 场景实现-CGLib

CGLib(Code Generation Library)是一个第三方代码生成类库,运行时在内存中动态生成一个子类对象,从而实现对目标对象功能的扩展。

CGLIB作为一个开源项目,其代码托管在github,地址为:GitHub - cglib/cglib: cglib - Byte Code Generation Library is high level API to generate and transform Java byte code. It is used by AOP, testing, data access frameworks to generate dynamic proxy objects and intercept field access.

CGLib vs JDK动态代理:

  • 与动态代理不同的是,动态代理是基于Java 反射机制实现的,必须实现接口的业务类才能使用这种办法生成代理对象。而 CGLib 则是基于 ASM机制实现,通过生成业务类的子类作为代理类,它允许我们在运行时对字节码进行修改和动态生成

  • 与动态代理相比,JDK动态代理限制了只能基于接口设计,对于没有接口的情况,JDK方式无法解决,而 CGLib则可以解决这一问题,可以通过继承方式实现代理

CGLib – 常用API:

  • net.sf.cglib.proxy.Enhancer 类,(字节码)增强器,可以类比于JDK中的Proxy类,与之不同的是,Enhancer既能够代理普通的java类,也能够代理接口。 Enhancer.setSuperclass() 用来设置被代理的类。 Enhancer.create()方法是用来创建增强对象。

  • Callback,即回调,它是一个标识接口(空接口,没有任何方法),它的回调时机是生成的代理类的方法被调用的时候,即生成的代理类的方法被调用的时候,Callback的实现逻辑就会被调用。Enhancer通过 setCallback() 和setCallbacks() 设置Callback,设置了多个Callback实例将会按照设置的顺序进行回调。

  • net.sf.cglib.proxy.MethodInterceptor 接口,即方法拦截器,设置了MethodInterceptor后,代理类的所有方法调用都会转而执行这个接口中的intercept方法而不是原方法。如果需要在intercept方法中执行原方法可以使用参数method基于代理实例obj进行反射调用。

例如1:

(1) 创建服务实现类:MovieServiceImpl即需要被代理的类,不需要实现顶层接口。

package com.CGLibTest;
/**
 * 需要被代理的服务类 MovieServiceImpl,不需要实现顶层接口
 **/
public class MovieServiceImpl{
    /**
     * 定义服务方法
     */
    public void startMovie() {
        System.out.println("Start the movie....");
​
    }
​
    public void endMovie() {
        System.out.println("The movie is over");
    }
​
    public final void playFinal() {
        System.out.println("this is final!");
    }
}

(2) 创建拦截器:MyInterceptor,当我们调用被代理类中的某个方法时,实际首先调用的是拦截器的intercept方法,如果需要执行原来的方法,则调用 method.invoke(s, args);

package com.CGLibTest;
​
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
​
import java.lang.reflect.Method;
​
/**
 * 拦截器
 **/
public class MyInterceptor implements MethodInterceptor {
​
    private MovieServiceImpl service;
​
    public MyInterceptor(MovieServiceImpl service){
        this.service = service;
    }
​
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("=====================interceptor=====================");
        return method.invoke(service, args);
    }
}

(3)测试类

package com.CGLibTest;
​
import com.CGLibTest.fianlTest.FinalInterceptor;
import com.CGLibTest.fianlTest.FinalServiceImpl;
import net.sf.cglib.proxy.Enhancer;
​
/**
 * 测试方法
 **/
public class Demo {
    public static void test1(){
        // 通过CGLIB动态代理获取代理对象
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(MovieServiceImpl.class);
        enhancer.setCallback(new MyInterceptor(new MovieServiceImpl()));
        MovieServiceImpl helper = (MovieServiceImpl) enhancer.create();
        helper.startMovie();
        helper.endMovie();
        System.out.println();
        helper.playFinal();
    }
​
​
​
​
    public static void main(String[] args) {
        test1();
    }
}
​

每次在执行原来的方法之前,都会先执行拦截器中的扩展代码。被final修饰的方法没有被拦截,没有

执行扩展代码,仅仅执行了原来的方法。

输出结果:、

例如2:

(1)用final修饰需要被代理的服务类

package com.CGLibTest.fianlTest;
​
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
​
import java.lang.reflect.Method;
​
/**
 * 拦截器
 **/
public class FinalInterceptor implements MethodInterceptor {
​
    private FinalServiceImpl service;
​
    public FinalInterceptor(FinalServiceImpl service){
        this.service = service;
    }
​
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("=====================interceptor=====================");
        return method.invoke(service, args);
    }
}
package com.CGLibTest.fianlTest;
​
​
/**
 * 需要被代理的服务类 MovieServiceImpl,不需要实现顶层接口
 **/
public final class FinalServiceImpl {
    /**
     * 定义服务方法
     */
    public void startMovie() {
        System.out.println("Start the movie....");
​
    }
​
    public void endMovie() {
        System.out.println("The movie is over");
    }
​
    public final void playFinal() {
        System.out.println("this is final!");
    }
}
​
package com.CGLibTest;
​
import com.CGLibTest.fianlTest.FinalInterceptor;
import com.CGLibTest.fianlTest.FinalServiceImpl;
import net.sf.cglib.proxy.Enhancer;
​
/**
 * 测试方法
 **/
public class Demo {
    /*
     * 测试代理Final修饰的类
     */
    public static void test2(){
        // 通过CGLIB动态代理获取代理对象
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(FinalServiceImpl.class);
        enhancer.setCallback(new FinalInterceptor(new FinalServiceImpl()));
        FinalServiceImpl helper = (FinalServiceImpl) enhancer.create();
        helper.playFinal();
    }
​
​
    public static void main(String[] args) {
        test2();
    }
}

测试结果:

CGLIB缺点:由于CGLib是基于继承的方式实现类的动态代理,对于final方法和final类无法进行代理。

1.2.3 其他相关案例

例如:电影公司委托电影院播放电影,电影院想要在播放电影的时候,加一些广告或服务项目赚取收益。(使用代码来模拟)

服务接口: MovieService

服务实现类: MovieServiceImpl

动态代理类: MovieHandler

每个代理的实例都有一个与之关联的 InvocationHandler 接口实现类,这里实现了InvocationHandler接口,要求必须定义其声明的invoke()方法,用来反射调用执行方法。动态代理类构造器传入要代理的服务类,并使用成员变量接收,在invoke()方法中引用被代理的服务类,并调用其方法。

package com.DynamicProxy;
​
/**
 * 定义一个通用的接口 MovieService,代表电影播放服务
 **/
public interface MovieService {
    void play();
}
​
package com.DynamicProxy;
​
/**
 * 动态代理服务实现类 MovieServiceImpl
 **/
public class MovieServiceImpl implements MovieService {
    /**
     * 定义MovieService接口的类
     */
//    @Override
    public void play() {
        System.out.println("Showing a movie:Tom and Jerry....");
    }
}
​
package com.DynamicProxy;
​
/**
 * 动态代理服务实现类 MovieServiceImpl
 **/
public class MovieServiceImpl2 implements MovieService {
    /**
     * 定义MovieService接口的类
     */
//    @Override
    public void play() {
        System.out.println("Showing a movie:doraemon....");
    }
}
​
package com.DynamicProxy;
​
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
​
/**
 * 动态代理类 MovieHandler
 **/
public class MovieHandler implements InvocationHandler {
    private Object movieService;
​
    public MovieHandler(Object movieService) {
        this.movieService = movieService;   //成员变量接收目标对象的引用
    }
​
    /**
     * 宣传方法
     * @param isStart
     */
    public void advertise(boolean isStart) {
        if(isStart == true){
            System.out.println("The movie starts.");
        }else{
            System.out.println("The movie is over.");
        }
    }
​
//    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        advertise(true);
        method.invoke(movieService,args);
        advertise(false);
        return null;
    }
}
​
package com.DynamicProxy;
​
import sun.misc.ProxyGenerator;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;
​
/**
 * 测试代码
 **/
public class Demo {
​
    /**
     * 执行单个服务
     */
    public static void test1(){
        MovieService movieService = new MovieServiceImpl();
        InvocationHandler handler = new MovieHandler(movieService);
​
        MovieService dynamicProxy = (MovieService) Proxy.newProxyInstance(MovieService.class.getClassLoader(), MovieServiceImpl.class.getInterfaces(),handler);
        dynamicProxy.play();
    }
​
    /**
     * 执行多个服务
     */
    public static void test2(){
        List<MovieService> movieServices = new ArrayList<MovieService>();
        MovieService movieService = new MovieServiceImpl();
        MovieService movieService1 = new MovieServiceImpl2();
        movieServices.add(movieService);
        movieServices.add(movieService1);
        for (int i = 0; i < movieServices.size(); i++) {
            InvocationHandler handler = new MovieHandler(movieServices.get(i));
            MovieService dynamicProxy = (MovieService) Proxy.newProxyInstance(MovieService.class.getClassLoader(), MovieServiceImpl.class.getInterfaces(),handler);
            dynamicProxy.play();
        }
       /* MovieService movieService1 = new MovieServiceImpl();
        MovieService movieService2 = new MovieServiceImpl2();
        InvocationHandler handler1 = new MovieHandler(movieService1);
        InvocationHandler handler2 = new MovieHandler(movieService2);
​
        MovieService dynamicProxy1 = (MovieService) Proxy.newProxyInstance(MovieService.class.getClassLoader(), MovieServiceImpl.class.getInterfaces(),handler1);
        dynamicProxy1.play();
​
        MovieService dynamicProxy2 = (MovieService) Proxy.newProxyInstance(MovieService.class.getClassLoader(), MovieServiceImpl2.class.getInterfaces(),handler2);
        dynamicProxy2.play();*/
    }
​
    /**
     * 代理类写入本地
     */
    public static void test3() throws Exception {
        // 这里我们将jdk生成的代理类写入本地文件
        FileOutputStream out = null;
        try {
            byte[] classFile = ProxyGenerator.generateProxyClass("$Proxy", new Class[]{InvocationHandler.class});
            out = new FileOutputStream("E:\\java_project\\java_code_4\\code\\DynamicProxy\\target\\classes\\com\\Proxy3.class");//自行修改路径
            out.write(classFile);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (out != null) {
                    out.flush();
                    out.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
​
        }
    }
​
​
​
    public static void main(String[] args) throws Exception {
        System.getProperties().setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
        test3();
//        test2();
    }
}
​

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

普通集群与镜像集群配置

一. 环境准备 关闭防火墙和selinux&#xff0c;进行时间同步 主机名系统IP服务rabbitmq-1 Rocky_linux9.4 192.168.226.22RabbitMQ&#xff0c;MySQLrabbitmq-2Rocky_linux9.4192.168.226.23RabbitMQrabbitmq-3Rocky_linux9.4192.168.226.24RabbitMQ 修改主机名#192.168.226…

机械硬盘故障分析及损坏处理(坏道屏蔽)

机械硬盘故障分析&#xff1a; 1、加电后没有声音就是电机不转&#xff0c;是电路问题&#xff0c;更换电路板解决。 2、加电后电机转&#xff0c;有连续敲击声音&#xff0c;或有异响&#xff0c;磁头损坏或机械故障。 3、加电后电机转&#xff0c;运行正常&#xff0c;BIOS无…

docker pull 镜像的时候遇到Pulling fs layer问题

最近遇到一个很奇怪的问题,docker pull 镜像的时候,总是出现Pulling fs layer问题,导致镜像拉取不成功,以前是安装好docker,正常拉取镜像都是没什么问题的,在这里记录一下这个问题的解决方法,当然,可能并不通用。 1、进入阿里云容器服务 地址:https://cr.console.aliy…

【反者道之动,弱者道之用】统计学中的哲理——回归均值 Regression to the mean

&#x1f4a1;&#x1f4a1;在统计学中&#xff0c;回归均值(Regression toward the Mean/Regression to the Mean) 指的是如果变量在其第一次测量时是极端的&#xff0c;则在第二次测量时会趋向于接近平均值的现象。   在金融学中&#xff0c; 回归均值是指股票价格无论高于…

【计算机组成原理实验】——运算器组成实验

计组TEC4实验——运算器组成实验 1. 实验目的 (1&#xff09;掌握算术逻辑运算加、减、乘、与的工作原理。 (2) 熟悉简单运算器的数据传送通路。 (3) 验证实验台运算器的8位加、减、与、直通功能。 (4) 验证实验台的4位乘4位功能。 (5) 按给定数据&#xff0c;完成几种指…

JS乌龟吃鸡游戏

代码&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>乌龟游戏</title><script type"text/javascript">function move(obj){//乌龟图片高度var wuGui_height 67;…

HarmonyOS Next开发学习手册——创建轮播 (Swiper)

Swiper 组件提供滑动轮播显示的能力。Swiper本身是一个容器组件&#xff0c;当设置了多个子组件后&#xff0c;可以对这些子组件进行轮播显示。通常&#xff0c;在一些应用首页显示推荐的内容时&#xff0c;需要用到轮播显示的能力。 针对复杂页面场景&#xff0c;可以使用 Sw…

MySQL1(初始数据库 概念 DDL建库建表 数据库的三大范式 表约束)

目录 一、初始数据库 二、概念 三、DDL建库建表 1. 数据库结构 2. SQL语句分类 3. DDL语句操作数据库 注释&#xff1a; 查看数据库&#xff1a; ​编辑创建数据库&#xff1a; 删除数据库&#xff1a; 选择数据库&#xff1a; 4. 数据库表的字段类型 4.1 字符串…

JVM内存模型剖析与参数设置

目录 Java语言的跨平台特性 JVM 的主要组成部分及其作用是什么? JVM整体结构及内存模型 线程栈&#xff08;Machine Stack&#xff09; 局部变量表&#xff08;Local Variable Table&#xff09; 操作数栈&#xff08;Operand Stack&#xff09; 程序计数器&#xff08…

【Linux】已解决:Ubuntu虚拟机安装Java/JDK

文章目录 一、分析问题背景二、可能出错的原因三、错误代码示例四、正确代码示例五、注意事项结论 已解决&#xff1a;Ubuntu虚拟机安装Java/JDK 一、分析问题背景 在Ubuntu虚拟机上安装Java开发工具包&#xff08;JDK&#xff09;是许多开发者的常见任务。然而&#xff0c;在…

Pc端多功能视频混剪工具/便携版打开即用

PC便携版 视频批量剪辑大师&#xff0c;全自动剪辑神器&#xff0c;会打字就能做视频 多功能&#xff0c;视频混剪&#xff0c;视频配音&#xff0c;文字生成语音&#xff0c;图片合成视频&#xff0c;自动识别音频并生成字幕等功能 链接&#xff1a;https://pan.baidu.com/…

2007-2022年 省级-绿色农业合作社数量相关数据整理

绿色农业合作社作为一种推动农业可持续发展的组织形式&#xff0c;对于促进环境保护、提高农产品质量和增加农民收入等方面具有重要作用。以下是对省级绿色农业合作社数量相关数据的介绍&#xff1a; 数据简介 定义&#xff1a;绿色农业合作社是由农民、农业专家、企业家等组…

详细解释Redis的SET NX命令

详细解释Redis的SET NX命令 SET NX 命令是 Redis 中用于实现分布式锁的一个重要命令。它的语法和用法如下&#xff1a; SET key value NX [EX seconds | PX milliseconds]参数解释 key&#xff1a;要设置的键名。value&#xff1a;要设置的键值&#xff0c;通常用一个唯一标…

【小沐学AI】Python实现语音识别(whisper+HuggingFace)

文章目录 1、简介1.1 whisper 2、HuggingFace2.1 安装transformers2.2 Pipeline 简介2.3 Tasks 简介2.3.1 sentiment-analysis2.3.2 zero-shot-classification2.3.3 text-generation2.3.4 fill-mask2.3.5 ner2.3.6 question-answering2.3.7 summarization2.3.8 translation 3、…

SM2258XT量产工具,SM2258XT开卡三星SSV4颗粒成功分享,SM2259XT量产参考教程,威刚ADATA SP580开卡记录

前两天拆了笔记本上的威刚ADATA SP580 240GB&#xff0c;准备做移动硬盘用&#xff0c;装入移动硬盘盒之后接入电脑&#xff0c;发现系统可认盘&#xff0c;SMART显示正常&#xff0c;Windows的磁盘管理能显示正确容量&#xff0c;但处于未初始化状态&#xff0c;且始终无法初始…

鸿蒙系统——强大的分布式系统

鸿蒙相比较于传统安卓最最最主要的优势是微内核分布式操作系统&#xff0c;具有面向未来&#xff0c;跨设备无缝协作&#xff0c;数据共享的全场景体验。下面简单来感受一下鸿蒙系统的多端自由流转。 自由流转概述 场景介绍 随着全场景多设备的生活方式不断深入&#xff0c;…

SSM网上旅游信息管理系统-计算机毕业设计源码06975

目 录 摘要 1 绪论 1.1 研究背景 1.2 研究意义 1.3论文结构与章节安排 2 系统分析 2.1 可行性分析 2.2 系统流程分析 2.2.1 数据新增流程 2.2.2 数据删除流程 2.3 系统功能分析 2.3.1 功能性分析 2.3.2 非功能性分析 2.4 系统用例分析 2.5本章小结 3 系统总体设…

计算神经网络中梯度的核心机制 - 反向传播(backpropagation)算法(1)

计算神经网络中梯度的核心机制 - 反向传播&#xff08;backpropagation&#xff09;算法&#xff08;1&#xff09; flyfish 链式法则在深度学习中的主要应用是在反向传播&#xff08;backpropagation&#xff09;算法中。 从简单的开始 &#xff0c;文本说的就是链式法则 R …

酒店客房管理系统(Java+MySQL)

技术栈 Java: 作为主要编程语言。Swing GUI: 用于开发图形用户界面。MySQL: 作为数据库管理系统。JDBC: 用于连接和操作MySQL数据库。 功能要点 管理登录认证 系统提供管理员登录认证功能。通过用户名和密码验证身份&#xff0c;确保只有授权的用户可以访问和管理酒店客房信…

如何利用react框架快速创建一个electron项目

1、搭建electron项目 创建一个electron入门项目还是很容易的&#xff0c;基体方法可以参考&#xff1a;eletron入门教程 -- 快速写一个electron demo程序 但是如果要利用react框架搭建一个electron项目&#xff0c;但是有一点麻烦&#xff0c;不过可以利用工具包来进行创建&am…