Java-JDK动态代理(AOP)使用及实现原理分析

news2024/9/20 19:34:17

Java-JDK动态代理(AOP)使用及实现原理分析

第一章:代理的介绍

介绍:我们需要掌握的程度

动态代理(理解) 基于反射机制

掌握的程度:

1.什么是动态代理?

2.动态代理能够做什么?

后面我们在用Spirng和Mybatis的时候,要理解怎么使用的.

1.什么是代理?

代理,在我们日常生活之中就有体现,代购,中介,换ip,商家等等.

比如有一家美国的大学,可以对全世界招生.留学中介(代理 )

留学中介(代理):帮助这家美国的学校招生,中介是学校的代理中介是代替学校完成招生功能
代理特点

  1. 中介和代理他们要做的事情是一致的:招生
  2. 中介是学校代理,学校是目标
  3. 家长-------->中介(学校介绍,办理入学手续)---------->美国学校
  4. 中介是代理,收取费用

2.为什么要找中介

为什么要找中介?
1.中介是专业的,方便.
2.家长现在不能自己去找学校。家长没有能力访问学校.或者美国学校不接收个人来访

买东西都是商家卖, 商家是某个商品的代理, 你个人买东西,肯定不会让你接触到厂家的.

第二章:静态代理

2.1 使用代理模式的作用

  1. 功能增强:在你原有的功能上,增加了额外的功能.新增加的功能,叫做功能增强
  2. 控制访问:代理类不让你访问目标,例如商家不让用户访问厂家

2.2 实现代理的方式

1.静态代理:

1)代理类是自己手工实现的,自己创建一个java类,表示代理类

2)同时你所要代理的目标

特点:1)实现简单2)容易理解。
模拟一个用户购买u盘的行为。
用户是客户端类
商家:代理,代理某个品牌的u盘。
厂家:目标类。
三者的关系:用户(客户端)-—-商家(代理)-—-厂家(目标)
商家和厂家都是卖u盘的,他们完成的功能是一致的,都是卖u盘。

实现步骤:

实现步骤
1.创建一个接口,定义卖u盘的方法,表示你的厂家和商家做的事情
2.创建厂家类,实现1步骤的接口
3.创建商家,就是代理,也需要实现1步骤中的接口
4.创建客户端类,调用商家的方法买一个u盘

2.3 具体实现

实现步骤
1.创建一个接口,定义卖u盘的方法,表示你的厂家和商家做的事情

package com.rango.service;
public interface usbSell {
    /**
     * 定义一个方法 参数 amount:表示一次购买的数量,暂时不用
     * 返回值表示一个u盘的价格
     * @param amount
     * @return
     */
    float sell(int amount);
}

2.创建厂家类,实现1步骤的接口

package com.rango.factory;

import com.rango.service.usbSell;
//目标类:金士顿厂家,不接受用户的单独购买
public class UsbKingFactory implements usbSell {
/**
* 定义一个方法 参数 amount:表示一次购买的数量,暂时不用
* 返回值表示一个u盘的价格
*
* @param amount
* @return
*/

@Override
//一个128G的U盘是85元.
// 后期根据amount,可以实现不同的价格,例如10000个,单击是80,50000个75
public float sell(int amount) {
return 85.0f*amount;
}
}

3.创建商家,就是代理,也需要实现1步骤中的接口

package com.rango.business;

import com.rango.factory.UsbKingFactory;
import com.rango.service.usbSell;

//淘宝是一个商家,代理金士顿U盘的销售
public class TaoBao implements usbSell {
// 声明 商家代理的厂家具体是谁
private UsbKingFactory factory =new UsbKingFactory();

@Override
// 实现销售U盘功能
public float sell(int amount) {
// 向厂家发送订单,告诉厂家,我买了U盘,厂家发货
// 发送给工厂,我需要的订单,返回报价
float price = factory.sell(amount);
// 商家需要加价也就是代理要增加价格
​ price = price + 25;
//在目标类的方法调用后,你做的其他功能,都是增强的意思
​ System.out.println(“淘宝再给你返回一个优惠券,或者红包”);
// 增加的价格
return price;
​ }
}

4.创建客户端类,调用商家的方法买一个u盘

import com.rango.business.TaoBao;

public class shopMain {
public static void main(String[] args){
// 创建代理的商家淘宝对象
TaoBao taoBao = new TaoBao();
// 我只向淘宝买一件产品,得到报价
float price = taoBao.sell(2);
System.out.println("购买一件产品.淘宝的报价为: "+price);
}
}

所以我们再次总结代理类完成的功能:

  1. 目标类中方法的调用
  2. 功能增强

所属我们只有一个代理商,我们实际上可以写多个代理商,

2.4 静态代理的优缺点

我们再次总结一下静态代理的优缺点

优点:

  1. 实现简单
  2. 容易简单

确定:当你的项目中,目标类的代理类很多的时候,有一下的缺点

  1. 当目标类增加了,代理类可能也需要成倍的增加
  2. 当你的接口中功能在增加了,或者修改了,会影响众多的实现类,厂家类,代理都需要修改,影响比较多.

所以我们继续学习动态代理

第三章 动态代理

本章,我们所掌握的是

1)什么是动态代理?

​ 使用jdk的反射机制,创建对象的能力,创建的是代理类的的对象.而不用我们创建类文件,不用写java文件, 什么叫动态?在程序执行时,调用jdk提供的方法才能创建代理类的对象

2)知道动态代理能做什么?

2.1 静态代理和动态代理模式的对比

在静态代理中目标很多的时候,可以使用动态代理,避免静态代理的缺点

在静态代理中目标类很多时候,可以使用动态代理,避免静态代理的缺点。
动态代理中目标类即使很多,

  1. 代理类数量可以很少,

  2. 当你修改了接口中的方法时,不会影响代理类。

动态代理:在程序执行过程中,使用jdk的反射机制,创建代理类对象,并动态的指定要代理目标类。
换句话说:动态代理是一种创建java象的能力,让你不用创建 TaoBao类就能创建代理类对象,除去了中间商

在java中,要想创建对象

  1. 创建类文件,java 文件编译为class
  2. 使用构造方法,创建类的对象

2.1 动态代理的介绍

  1. 动态代理是指代理类对象在程序运行时由JVM根据反射机制动态生成的。动态代理不需要定义代理类的,java源文件。
  2. 动态代理其实就是jdk运行期间,动态创建class字节码并加载到JVM。
  3. 动态代理的实现方式常用的有两种:使用JDK代理,与通过CGLlB动态代理。

动态代理的实现:

  1. jdk动态代理(理解):使用java反射包中的类和接口实现动态代理的功能,反射包java.lang.reflect,里面有三个类:InvocationHandler,Method,Proxy
  2. cglib动态代理(了解): cglib是第三方的工具库,创建代理对象
    1. cglib的原理是继承,cglib通过继承目标类,创建它的子类,在子类中
      重写父类中同名的方法,实现功能的修改。
    2. 因为cglib是继承,重写方法,所以要求目标类不能是fina1的,方法也不能是final的。cglib的要求目标类比较宽松,只要能继承就可以了。cglib在很多的框架中使用,
      比如mybatis,spring框架中都有使用。
package Test;

import com.rango.Impl.HelloServiceImpl;
import com.rango.service.HelloService;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class TestApp {
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
// HelloService service = new HelloServiceImpl();
// service.sayhello(“张三”);
// 以上是常规方法执行sayhello
// 下面我们使用反射机制进行创建sayhello方法,核心Method(类中的方法)
HelloServiceImpl target = new HelloServiceImpl();
// 获取sayhello名称对应的Method类对象
// public Method getM ethod(String name, Class<?>… parameterTypes)
// 加入,该方法的参数有多个该怎么办?
// parameterTypes参数是一个类对象数组,按声明的顺序标识方法的形式参数类型。
Method method = HelloService.class.getMethod(“sayhello”, String.class);
// 通过Metho可以执行sayhello方法的调用
/*
* public Object invoke(Object obj, Object… args)
* 表示执行方法的调用
* 参数:
* 1.Object,表示对象,要执行这个对象的方法
* 2.Object…args,方法执行时的参数值
* 返回值:
* Object:方法执行后的返回值
* */

Object ret = method.invoke(target, “李四”);
}
}

2.2 回顾反射 Method类

Method类的结构图

  • Class Method
    • java.lang.Object
      • java.lang.reflect.AccessibleObject
        • java.lang.reflect.Executable
          • java.lang.reflect.Method

2.2.1 class.getMethod

Method method = HelloService.class.getMethod("sayhello", String.class,Integer.class);

提出问题?

    public Method getMethod(String name, Class<?>... parameterTypes)

加入,该方法的参数有多个该怎么办?
parameterTypes参数是一个类对象数组,按声明的顺序标识方法的形式参数类型。

2.2.2 Method.invoke

public Object invoke(Object obj,Object... args)

*  public Object invoke(Object obj, Object... args)
*       表示执行方法的调用
*   参数:
*       1.Object,表示对象,要执行这个对象的方法
*       2.Object...args,方法执行时的参数值
* 返回值:
*       Object:方法执行后的返回值
* 

2.3 JDK动态代理

实现步骤
1.创建一个接口,定义卖u盘的方法,表示你的厂家和商家做的事情

package com.rango.service;
public interface usbSell {
    /**
     * 定义一个方法 参数 amount:表示一次购买的数量,暂时不用
     * 返回值表示一个u盘的价格
     * @param amount
     * @return
     */
    float sell(int amount);
}

2.创建厂家类,实现1步骤的接口

package com.rango.factory;

import com.rango.service.usbSell;
//目标类:金士顿厂家,不接受用户的单独购买
public class UsbKingFactory implements usbSell {
/**
* 定义一个方法 参数 amount:表示一次购买的数量,暂时不用
* 返回值表示一个u盘的价格
*
* @param amount
* @return
*/

@Override
//一个128G的U盘是85元.
// 后期根据amount,可以实现不同的价格,例如10000个,单击是80,50000个75
public float sell(int amount) {
return 85.0f*amount;
}
}

3.创建商家,就是代理,也需要实现1步骤中的接口

package com.rango.business;

import com.rango.factory.UsbKingFactory;
import com.rango.service.usbSell;

//淘宝是一个商家,代理金士顿U盘的销售
public class TaoBao implements usbSell {
// 声明 商家代理的厂家具体是谁
private UsbKingFactory factory =new UsbKingFactory();

@Override
// 实现销售U盘功能
public float sell(int amount) {
// 向厂家发送订单,告诉厂家,我买了U盘,厂家发货
// 发送给工厂,我需要的订单,返回报价
float price = factory.sell(amount);
// 商家需要加价也就是代理要增加价格
​ price = price + 25;
//在目标类的方法调用后,你做的其他功能,都是增强的意思
​ System.out.println(“淘宝再给你返回一个优惠券,或者红包”);
// 增加的价格
return price;
​ }
}

4.创建客户端类,调用商家的方法买一个u盘

import com.rango.business.TaoBao;

public class shopMain {
public static void main(String[] args){
// 创建代理的商家淘宝对象
TaoBao taoBao = new TaoBao();
// 我只向淘宝买一件产品,得到报价
float price = taoBao.sell(2);
System.out.println("购买一件产品.淘宝的报价为: "+price);
}
}

所以我们再次总结代理类完成的功能:

  1. 目标类中方法的调用
  2. 功能增强

所属我们只有一个代理商,我们实际上可以写多个代理商,

2.4 静态代理的优缺点

我们再次总结一下静态代理的优缺点

优点:

  1. 实现简单
  2. 容易简单

确定:当你的项目中,目标类的代理类很多的时候,有一下的缺点

  1. 当目标类增加了,代理类可能也需要成倍的增加
  2. 当你的接口中功能在增加了,或者修改了,会影响众多的实现类,厂家类,代理都需要修改,影响比较多.

所以我们继续学习动态代理

第三章 动态代理

本章,我们所掌握的是

1)什么是动态代理?

​ 使用jdk的反射机制,创建对象的能力,创建的是代理类的的对象.而不用我们创建类文件,不用写java文件, 什么叫动态?在程序执行时,调用jdk提供的方法才能创建代理类的对象

2)知道动态代理能做什么?

2.1 静态代理和动态代理模式的对比

在静态代理中目标很多的时候,可以使用动态代理,避免静态代理的缺点

在静态代理中目标类很多时候,可以使用动态代理,避免静态代理的缺点。
动态代理中目标类即使很多,

  1. 代理类数量可以很少,

  2. 当你修改了接口中的方法时,不会影响代理类。

动态代理:在程序执行过程中,使用jdk的反射机制,创建代理类对象,并动态的指定要代理目标类。
换句话说:动态代理是一种创建java象的能力,让你不用创建 TaoBao类就能创建代理类对象,除去了中间商

在java中,要想创建对象

  1. 创建类文件,java 文件编译为class
  2. 使用构造方法,创建类的对象

2.1 动态代理的介绍

  1. 动态代理是指代理类对象在程序运行时由JVM根据反射机制动态生成的。动态代理不需要定义代理类的,java源文件。
  2. 动态代理其实就是jdk运行期间,动态创建class字节码并加载到JVM。
  3. 动态代理的实现方式常用的有两种:使用JDK代理,与通过CGLlB动态代理。

动态代理的实现:

  1. jdk动态代理(理解):使用java反射包中的类和接口实现动态代理的功能,反射包java.lang.reflect,里面有三个类:InvocationHandler,Method,Proxy
  2. cglib动态代理(了解): cglib是第三方的工具库,创建代理对象
    1. cglib的原理是继承,cglib通过继承目标类,创建它的子类,在子类中
      重写父类中同名的方法,实现功能的修改。
    2. 因为cglib是继承,重写方法,所以要求目标类不能是fina1的,方法也不能是final的。cglib的要求目标类比较宽松,只要能继承就可以了。cglib在很多的框架中使用,
      比如mybatis,spring框架中都有使用。
package Test;

import com.rango.Impl.HelloServiceImpl;
import com.rango.service.HelloService;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class TestApp {
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
// HelloService service = new HelloServiceImpl();
// service.sayhello(“张三”);
// 以上是常规方法执行sayhello
// 下面我们使用反射机制进行创建sayhello方法,核心Method(类中的方法)
HelloServiceImpl target = new HelloServiceImpl();
// 获取sayhello名称对应的Method类对象
// public Method getM ethod(String name, Class<?>… parameterTypes)
// 加入,该方法的参数有多个该怎么办?
// parameterTypes参数是一个类对象数组,按声明的顺序标识方法的形式参数类型。
Method method = HelloService.class.getMethod(“sayhello”, String.class);
// 通过Metho可以执行sayhello方法的调用
/*
* public Object invoke(Object obj, Object… args)
* 表示执行方法的调用
* 参数:
* 1.Object,表示对象,要执行这个对象的方法
* 2.Object…args,方法执行时的参数值
* 返回值:
* Object:方法执行后的返回值
* */

Object ret = method.invoke(target, “李四”);
}
}

2.2 回顾反射 Method类

Method类的结构图

  • Class Method
    • java.lang.Object
      • java.lang.reflect.AccessibleObject
        • java.lang.reflect.Executable
          • java.lang.reflect.Method

2.2.1 class.getMethod

Method method = HelloService.class.getMethod("sayhello", String.class,Integer.class);

提出问题?

    public Method getMethod(String name, Class<?>... parameterTypes)

加入,该方法的参数有多个该怎么办?
parameterTypes参数是一个类对象数组,按声明的顺序标识方法的形式参数类型。

2.2.2 Method.invoke

public Object invoke(Object obj,Object... args)

*  public Object invoke(Object obj, Object... args)
*       表示执行方法的调用
*   参数:
*       1.Object,表示对象,要执行这个对象的方法
*       2.Object...args,方法执行时的参数值
* 返回值:
*       Object:方法执行后的返回值
* 

2.3 JDK动态代理

jdk动态代理:
1.反射, Method类,表示方法。类中的方法。通过Method可以执行某个方法

2.jdk动态代理的实现
反射包java.lang. reflect,里面有三个类:InvocationHandler,Method,Proxy

2.3.1 Interface InvocationHandler

public interface InvocationHandler

InvocationHandler是由代理实例的调用处理程序实现的接口 。
每个代理实例都有一个关联的调用处理程序。 当在代理实例上调用方法时,方法调用将被编码并分派到其调用处理程序的invoke方法。

​ 1)InvocationHandler接口(调用处理器):就一个方法 invoke()
​ invoke():表示代理对象要执行的功能代码。你的代理类要完成的功能就写在
​ invoke()方法中。

代理类完成的功能
    1.调用目标方法,执行目标方法的功能
    2.功能增强,在目标方法调用时,增加功能

方法原型:

参数:object proxy:jdk创建的代理对象,无需赋值。
                Method method:目标类中的方法,jdk提供method对象的
                object[]args:目标类中方法的参数,jdk提供的。
Object invoke(Object proxy,方法 method,Object[] args)throws 

​ Throwable处理代理实例上的方法调用并返回结果。

2.3.2 Method

2)Method类:表示方法的,确切的说就是目标类中的方法。
作用:通过 Method可以执行某个目标类的方法, Method. invoke();
method. invoke(目标对象,方法的参数)

object ret= method. invoke(service22,"李四")

说明:method.invoke()就是为了用来执行目标方法的,等同于静态代理中的

   //        向厂家发送订单,告诉厂家,我买了U盘,厂家发货
    //        发送给工厂,我需要的订单,返回报价
            float price = factory.sell(amount);

2.3.3 Proxy类

3)proxy类:核心的对象,创建代理对象。之前创建对象都是new类的构造方法()
现在我们是使用proxy类的方法,代替new的使用。
方法:静态方法 newProxyInstance()
作用是:创建代理对象,等同于静态代理中的TaoBao taoBao=new TaoBao()

我们来观察方法原型

    public static Object newProxyInstance( ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)   throws IllegalArgumentException

参数:

  1. ClassLoader loader 类加载器,负责向内存中加载对象的,使用反射机制获取对象的classLoader,

如何获取? 类 a, a.getCalss().getClassLoader(),目标对象的类加载器

这里我们细分:每一个类都继承Object类,在Object中有一个getClass方法,表示 类对象的运行时类的Class对象。 而Class类里面有一个public ClassLoader getClassLoader()方法

  1. Class<?>[] interfaces: 接口,目标对象实现的接口,也是反射获取的
  2. InvocationHandler h : 我们自己写的,代理类要完成的功能

返回值也就是代理对象

第四章 实现动态代理的步骤

  1. 创建接口,定义目标类要完成的功能
  2. 创建目标类实现接口
  3. 创建InvocationHandler接口的实现类,在invoke方法中完成代理类的功能
    1. 调用目标方法
    2. 增强功能
  4. 使用Proxy类的静态方法,创建代理对象,并把返回值转换成接口类型

第一步:创建接口,定义目标所需功能

public interface UsbSell {
    float sell(int amount);
}

第二步:创建目标类实现接口

public class UsbKingFactory implements UsbSell {
    @Override
    public float sell(int amount) {
        System.out.println("目标类中,执行了sell目标方法");
        return 85.02f;

​ }
}

我们写了接口类,定义了功能,写了代理类,实现了接口功能,按照以前的操作,现在就需要写一个真正的代理类,创建对象.

第三步: 创建Invocationhandler实现类.在invoke()方法中完成代理类的对象

​ 1.调用目标的方法

​ 2.增强功能

public class MyHandle implements InvocationHandler {
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        return null;
    }
}

我们就在以前代理类的实现方法上进行修改

//之前的代理类
  public class TaoBao implements usbSell {
    //      声明 商家代理的厂家具体是谁
        private UsbKingFactory factory =new UsbKingFactory();

@Override
// 实现销售U盘功能
public float sell(int amount) {
// 向厂家发送订单,告诉厂家,我买了U盘,厂家发货
// 发送给工厂,我需要的订单,返回报价
float price = factory.sell(amount);
// 商家需要加价也就是代理要增加价格
​ price = price + 25;
//在目标类的方法调用后,你做的其他功能,都是增强的意思
​ System.out.println(“淘宝再给你返回一个优惠券,或者红包”);
// 增加的价格
return price;
​ }
​ }

调用目标的方法

//传入是谁的对象,就给谁创建代理
    public MyHandle(Object target) {
        this.target = target;
    }
invoke里面的设置
                Object res =null;
            //        向厂家发送订单,告诉厂家,我买了U盘,厂家发货
            //        发送给工厂,我需要的订单,返回报价
//            float price = factory.sell(amount);
            res = method.invoke(target,args);       //待执行目标方法,执行后返回值

第四步: 使用Proxy类的静态方法,创建代理对象,并把返回值转换成接口类型

创建一个MainShop类.

public class MainShop {
    public static void main(String[] args){ 
//            1.创建对象,使用Proxy
//            2.创建目标对象
        UsbSell factory = new UsbKingFactory();
//        3.创建Invocationhandler对象
        InvocationHandler myHandle = new MyHandle(factory);

// 4.创建代理对象
UsbSell proxy = (UsbSell) Proxy.newProxyInstance(factory.getClass().getClassLoader(),
factory.getClass().getInterfaces(),
myHandle);
// 通过代理执行方法
float price = proxy.sell(1);
System.out.println(“通过动态代理对象,调用方法:” +price);
}
}

执行成功.和之前动态代理模式一样

第五 JDK动态代理执行流程

我们先复习一下,Proxy类,实现动态代理的流程,使用返回指定接口的代理类实例,

我们此时debug一下程序,在invok实现类中打一个断点

此时我们再观察,代理对象MyHandler里面的invoke方法的参数

第六章 静态代理项目中的应用

我们需要知道代理能做什么?

在不改变原来目标方法功能的前提下,可以在代理中增强自己的功能代码,程序开发中的意思,

比如:你所在的项目,有一个功能是其他人(公司其他部门,其他小组的人)写好的,你可以使用

//比如,同事开发一个GoNong类
GoNong.class ,
GoNong gn=new GoNong()
    //我们需要增加一个print方法

我们发现这个功能现在还存在缺点,不能完全满足我项目的需要,我需要在print()执行过后,需要自己再增加代理,使用什么方法那,肯定是代理,因为别人不会让我们看源文件

执行步骤:

  1. 我们先建立一个接口功能,很简单的一个功能
public interface HelloService {
    /**
     * 打印报表,报表
     * @param name
     * @return
     */
    int print (String name);
}

  1. 我们再加个接口实现类
public class GoNeng implements HelloService {
    @Override
    public int print(String name) {
        System.out.println("其他人写好的这个方法!");
        return 2;
    }
}
  1. 我们如果相对上述功能进行修改,我们不可能直接去在原方法上进行修改

我们设置一个类来使用这个接口

public class MyApp {
    public static void main(String[] args){
        GoNeng gn = new GoNeng();
        int i = gn.print("nihao1");
        System.out.println("num" +i);

​ }
}

问题是如果我们想修改这个功能改怎么办?在不修改源代码的基础上,我们可以创建一个代理类,来增强这个类方法,

  1. 设置一个代理类实现功能的增强和代理
public class MyInvocationHandler implements InvocationHandler {
    private Object target=null;

public MyInvocationHandler(Object target) {
this.target = target;
​ }

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 调用目标方法,执行print()得到2
Object res = method.invoke(target,args); //返回为2的结果
//我们可以把结果再乘以2
if (res!=null)
​ {
Integer num = (Integer) res;
​ res = num*2;
​ }

return null;
​ }
}

  1. 我们仍回到主方法里面进行测试
public class MyApp {
    public static void main(String[] args){
//        GoNeng gn = new GoNeng();
//        int i = gn.print("nihao1");
//        System.out.println("num" +i);
        GoNeng goNeng = new GoNeng();
        InvocationHandler handler = new MyInvocationHandler(goNeng);
        HelloService proxy = (HelloService) Proxy.newProxyInstance(goNeng.getClass().getClassLoader(), goNeng.getClass().getInterfaces(),
                handler);
        int num = proxy.print("市场");
        System.out.println("我们期望得到的 num =="+num);
    }
}

测试System.out.println("动态代理类参数接口"+goNeng.getClass().getInterfaces()[0].getName());

动态代理类参数接口com.rango.service.HelloService
其他人写好的这个方法!
我们期望得到的 num ==4

完结

动态代理,必须要有接口出现,如果没有,我们可以使用cglib实现

分类: Java基础
标签: AOP , 动态代理 , 设计模式
好文要顶 关注我 收藏该文
刺客伍六七
粉丝 - 22 关注 - 20
19
0
<div class="clear"></div>
<div id="post_next_prev">

​ « 上一篇: 唯品会Java开发手册》1.0.2版阅读


​ » 下一篇: 从零开始编写IntelliJ IDEA插件

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

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

相关文章

PID循迹机器人及整定

如何对线路循迹机器人进行编程 如何对线路循迹机器人进行编程 (robotresearchlab.com)PID调谐文章&#xff1a;http://robotresearchlab.com/2019/02/16/pid-line-follower-tuning/ 介绍人们选择对循迹机器人进行线路编程的两种主要方式&#xff0c;并比较两者。将详细比较“…

绘声绘影2023简体中文版新功能介绍

会声会影是一款专业的数字音频工作站软件,它提供强大的音频编辑和制作功能,被广泛应用于音乐创作、录音棚录制以及现场演出等领域。会声会影的最新版本会声会影2023将于2022年底发布,主要功能和新功能详述如下: 会声会影2023主要功能: 1. 直观易用的界面:会声会影采用简洁而不…

C语言入门篇——数组篇

目录 1、数组 2、一维数组的创建和初始化 2.1数组的创建方式&#xff1a; 2.2数组的初始化 2.3一维数组的使用 ​2.4一维数组在内存中的存储 3、二维数组的创建和初始化 3.1二维数组的创建 3.2二维数组的初始化 3.3二维数组的使用 3.4二维数组在内存中的存储 4、数组…

SpringBoot中一个注解优雅实现重试Retry框架

目录: 1、简介2、实现步骤 1、简介 重试&#xff0c;在项目需求中是非常常见的&#xff0c;例如遇到网络波动等&#xff0c;要求某个接口或者是方法可以最多/最少调用几次&#xff1b;实现重试机制&#xff0c;非得用Retry这个重试框架吗&#xff1f;那肯定不是&#xff0c;相信…

【云计算•云原生】2.云计算环境下的新趋势—云原生

文章目录 1.什么是云原生2.云原生概述2.1 微服务2.2 容器云2.3 serverless无服务器2.4 DevOps2.5 持续集成和持续交付2.6 openStack 1.什么是云原生 按照自己的理解&#xff0c;可以将云原生拆分成云原生&#xff0c;云就是上一节中的云计算的云&#xff1b;原生即为诞生的环境…

Visual Studio C# WinForm开发入门(3):各种控件介绍

1、窗体 窗口就是打开程序我们所面对的一个面板&#xff0c;里面可以添加各种控件&#xff0c;如下图所示&#xff0c;我们可以在属性栏设置其标题名称、图标、大小等。 双击标题框&#xff0c;会生成Load函数&#xff0c;也可以到事件里面去找 Load函数是窗口生成后需要…

Spring Doc OpenAPI3.0 抛弃SpringFox拥抱SpringDoc

Spring Doc 1 简介 SpringDoc是SpringBoot 的API文档工具。官网&#xff1a;https://springdoc.org/ 在使用SpringBoot 2.6以前去创建API文档工具一般会采用SpringFox提供的Swagger库&#xff0c;但是由于SpringBoot版本的不断升级和SpringFox摆烂不更新&#xff0c;导致了S…

springboot项目需要读取非application.yml/properties 的配置文件

目录&#xff1a; 1、操作步骤2、总结3、扩展4、第二种方法获取配置文件bean 1、操作步骤 1.新建配置文件&#xff1a; 2.编辑配置文件&#xff1a; test-serverrd-dev02.jr.rong360.com3.新建Config类&#xff1a; Component PropertySource(value "kirara.properti…

销量破亿,董洁直播间凭何出圈?

近期&#xff0c;“没有五位数走不出”的董洁直播间火了…… 纵观这几年各大平台直播带货&#xff0c;火已不是什么新鲜事&#xff0c;而为何董洁的直播能火上热搜呢&#xff1f;本期&#xff0c;千瓜将解析董洁直播&#xff0c;同品牌方聊聊小红书直播的那些事儿。董洁「种草式…

Win10分辨率怎么看?2种必须学会的方法!

案例&#xff1a;win10分辨率 【为了方便办公&#xff0c;最近我的电脑连接了2个显示屏&#xff0c;但感觉电脑显示怪怪的&#xff0c;可能是分辨率设置不对&#xff0c;大家知道应该怎么查看电脑的分辨率吗&#xff1f;感谢感谢&#xff01;】 我们的win10系统支持多种分辨率…

ChatGPT的未来:人工智能技术的新发展趋势

第一章&#xff1a;人工智能技术的新发展趋势 近年来&#xff0c;随着人工智能技术的不断发展和应用&#xff0c;ChatGPT这样的大型自然语言处理模型已经成为人工智能技术的重要组成部分。未来&#xff0c;人工智能技术的发展将更加快速&#xff0c;我们可以看到以下几个方面的…

制造型企业为何需要MES管理系统,企业怎样选择合适的MES

MES管理系统是专门针对制造型企业而设计的&#xff0c;能实现对生产车间、工厂信息化管理&#xff0c;帮助制造型企业提高生产效率&#xff0c;加快数字化转型。目前针对制造型企业生产效率、企业竞争力和生产管理状况的需求&#xff0c;MES管理系统已经成为实现生产经营目标的…

MySQL创建用户并赋权限

MySQL创建用户并赋权限 省流1.创建mysql用户1.1 新建用户1.2 查询用户信息 2. 授权用户2.1 指定数据库和表赋权2.2 赋予全部权限2.3 查看用户权限2.4 回收用户权限 3. 修改用户密码4. 删除用户5. 刷新权限(务必执行) 省流 如果只是希望新建一个用户并且赋予全部执行权限&#…

android react native报错

1.报错图片 解决方案&#xff1a; android下的build.gradle文件 修改 如图 报错 E:/androidData/caches/transforms-2/files-2.1/399126eae79af6235d7a4ae871926a31/jetified-kotlin-stdlib-1.6.10.jar!/META-INF/kotlin-stdlib.kotlin_module: Module was compiled with an i…

华为云 HCIP云迁移 学习课程提供的考试样题提交之后没有反馈正确答案的问题

最近在考HCIP的云迁移&#xff0c;但是他提供的考试样题昨晚发现没有正确答案&#xff0c;只会告诉你对错&#xff0c;判断题还好解决&#xff0c;但是多选题就麻烦了。这边研究了一下&#xff0c;share一下&#xff0c;方便大家学习和验证自己的学习成果 这边去看了他的 api r…

杰理-OTA升级电量限制

杰理-OTA升级电量限制 获取升级异常状态标志位&#xff08;升级过程中断开重新连接&#xff0c;不做电量限制&#xff09;

【观察】华为:运力算力存力“协同”,推动数字生产力“跃升”

可以看到&#xff0c;过去几年数字化转型已经席卷全球&#xff0c;随着新技术的广泛应用&#xff0c;新的机会和价值正在不断被发现和创造。从某种程度上说&#xff0c;数字化转型不再是“可选项”&#xff0c;而变成了“必选项”。 确实如此&#xff0c;目前已经有超过170多个…

基于JS简单甘特图(IT枫斗者)

基于JS简单甘特图 基于JS简单甘特图 先来看一下效果吧&#xff0c;这里的需求是从早上的5点为开始时间&#xff0c;到第二天到凌晨5点 前期准备 其实网上有很多甘特图的实现方式&#xff0c;但是他们都只能具象到天&#xff0c;不能具体到某个时间点&#xff0c;而且每一个…

ESD/EMI防护设计

内容摘取自<Rockchip_RK3568_Hardware_Design_Guide_V1.0_CN.pdf> 1.1概述 本章对于RK3568产品设计中的ESD/EMI防护设计给出了建议&#xff0c;帮助客户更好的提高产品的抗静电、抗电 磁干扰水平。 1.2 术语解释 本章中的术语解释如下&#xff1a;  ESD&#xff08;E…

直播预告丨打破 Python 束缚:Level 2 因子的脚本优化实践

有人说&#xff0c;DolphinDB 是一个时序数据库&#xff1b; 也有人说&#xff0c;DolphinDB 就是 Python 加数据库的结合&#xff1b;还有人说&#xff0c;DolphinDB 是一个支持流数据处理的实时计算软件…… 我们经常会听到类似的理解&#xff0c;其实很多小伙伴都会有好奇…