iis服务器助手广告广告
返回顶部
首页 > 资讯 > 前端开发 > node.js >单例模式的介绍和用法
  • 345
分享到

单例模式的介绍和用法

2024-04-02 19:04:59 345人浏览 泡泡鱼
摘要

本篇内容主要讲解“单例模式的介绍和用法”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“单例模式的介绍和用法”吧!问题1、说说单例模式的特点?2、你知道单例模式的具

本篇内容主要讲解“单例模式的介绍和用法”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“单例模式的介绍和用法”吧!

问题

1、说说单例模式的特点?

2、你知道单例模式的具体使用场景吗?

3、单例模式常见写法有几种?

4、怎么样保证线程安全?

5、怎么不会被反射攻击?

6、怎样保证不会被序列化和反序列化的攻击?

7、枚举为什么会不会被序列化?

定义

单例模式(Singleton Pattern)是 Java  中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。

特点:

  • 1、单例类只能有一个实例。

  • 2、单例类必须自己创建自己的唯一实例。

  • 3、单例类必须给所有其他对象提供这一实例

  • 4、隐藏所有的构造方法

**目的:**保证一个类仅有一个实例,并提供一个访问它的全局访问点。

案例:一家企业只能有一个CEO,有多个了其实乱套了。

使用场景

需要确保任何情况下都绝对只有一个实例。

比如:ServletContext、ServletConfig、ApplicationContext、DBTool等,都使用到了单列模式。

单例模式的写法

  • 饿汉式

  • 懒汉式(包含双重检查、静态内部类)

  • 注册式(以枚举为例)

饿汉式

从名字上就能看出,饿汉:饿了就得先吃饱,所以,一开始就搞定了。

饿汉式主要是使用了static,饿汉式也有两种写法,但本质可以理解为是一样的。

public class HungrySingleton{      private static final HungrySingleton INSTANCE;     static {         INSTANCE=new HungrySingleton();     } //    private static final HungrySingleton INSTANCE=new HungrySingleton();     private HungrySingleton(){      }      public static HungrySingleton getInstance(){         return INSTANCE;     } }

饿汉式有个致命的缺点:浪费空间,不需要也实例化。如果是成千上万个,也这么玩,想想有多恐怖。

于是,就会想到,能不能在使用的时候在实例化,从而引出了懒汉式。

懒汉式

顾名思义,就是需要的时候再创建,因为懒,你不调用我方法,我是不会干活的。

下面是懒汉式的Java代码实现:

public class LazySingleton {      private static LazySingleton lazySingleton = null;      private LazySingleton() {     }      public static LazySingleton getInstance() {         if (lazySingleton == null) {//01             lazySingleton = new LazySingleton();//02         }         return lazySingleton;     }  }

进入getInstance方法,先判断lazySingleton是否为空,为空,则创建一个对象,然后返回此对象。

但是,问题来了:

两个线程同时进入getInstance方法,然后都去执行01这行代码,都是true,然后各自进去创建一个对象,然后返回自己创建的对象。

这岂不是不满足只有唯一 一个对象的了吗?所以这类存在线程安全的问题,那怎么解决呢?

第一印象肯定都是想到加锁。于是,就有了下面的线程安全的懒加载版本:

public class LazySingleton {      private static LazySingleton lazySingleton = null;      private LazySingleton() {     }      //简单粗暴的线程安全问题解决方案     //依然存在性能问题   public synchronized static LazySingleton getInstance() {         if (lazySingleton == null) {             lazySingleton = new LazySingleton();         }         return lazySingleton;     } }

给getInstance方法加锁同步锁标志synchronized,但是又涉及到锁的问题了,同步锁是对系统性能优影响的,尽管jdk1.6后,对其做了优化,但它毕竟还是涉及到锁的开销。

每个线程调用getInstance方法时候,都会涉及到锁,所以又对此进行了优化成为了大家耳熟能详的双重检查锁。

双重检查锁

代码实现如下:

public class LazyDoubleCheckSingleton {      private static LazyDoubleCheckSingleton lazyDoubleCheckSingleton = null;      private LazyDoubleCheckSingleton() {     }      public static LazyDoubleCheckSingleton getInstance() {         if (lazyDoubleCheckSingleton == null) {//01             synchronized (LazyDoubleCheckSingleton.class) {                 if (lazyDoubleCheckSingleton == null) {//02                     lazyDoubleCheckSingleton = new LazyDoubleCheckSingleton();                 }             }         }         return lazyDoubleCheckSingleton;     }  }

这段代码中,在01行,如果不为空,就直接返回,这是第一次检查。如果为空,则进入同步代码块,02行又进行一次检查。

双重检查就是现实if判断、获取类对象锁、if判断。

上面这段代码,看似没问题,其实还是有问题的,比如:指令重排序(需要有JVM知识垫底哈)

指令重排是什么意思呢?

比如java中简单的一句

lazyDoubleCheckSingleton = new LazyDoubleCheckSingleton();

会被编译器编译成如下JVM指令:

memory =allocate(); //1:分配对象的内存空间

ctorInstance(memory); //2:初始化对象

instance =memory; //3:设置instance指向刚分配的内存地址

但是这些指令顺序并非一成不变,有可能会经过JVM和CPU的优化,指令重排成下面的顺序:

memory =allocate(); //1:分配对象的内存空间

instance =memory; //3:设置instance指向刚分配的内存地址

ctorInstance(memory); //2:初始化对象

为了防止指令重排序,所以,我们可以使用volatile来做文章(注意:volatile能防止指令重排序和线程可见性)。

于是,更好的版本就出来了。

public class LazyDoubleCheckSingleton {     //使用volatile修饰     private volatile static LazyDoubleCheckSingleton lazyDoubleCheckSingleton = null;      private LazyDoubleCheckSingleton() {     }      public static LazyDoubleCheckSingleton getInstance() {         if (lazyDoubleCheckSingleton == null) {             synchronized (LazyDoubleCheckSingleton.class) {                 if (lazyDoubleCheckSingleton == null) {                     lazyDoubleCheckSingleton = new LazyDoubleCheckSingleton();                 }             }         }         return lazyDoubleCheckSingleton;     } }

尽管相比前面的版本,确实改进了很多,但依然有同步锁,还是会影响性能问题。于是,又进行优化为静态内部类方式:

静态内部类

下面是静态内部类的代码实现:

利用了内部类的特性,在JVM底层,能完美的规避了线程安全的问题,这种方式也是目前很多项目里喜欢使用的方式。

但是,还是会存在潜在的风险,什么风险呢?

可以使用 反射 暴力的串改,同样也会出现创建多个实例:

反射代码实现如下:

import java.lang.reflect.Constructor;  public class LazyStaticSingletonTest {     public static void main(String[] args) {         try {             Class<?> clazz = LazyStaticSingleton.class;             Constructor constructor = clazz.getDeclaredConstructor(null);             //强行访问             constructor.setAccessible(true);             Object object = constructor.newInstance();              Object object1 = LazyStaticSingleton.getInstance();              System.out.println(object == object1);         } catch (Exception ex) {             ex.printStackTrace();         }     } }

这段代码运行结果为false。

所以,上面说的双重检查锁的方式,通过反射,还是会存在潜在的风险。怎么办呢?

在《Effect java 》这本书中,作者推荐使用枚举来实现单例模式,因为枚举不能被反射。

枚举

下面是枚举式的单例模式的代码实现:

public enum EnumSingleton {     INSTANCE;     private Object data;      public Object getData() {         return data;     }      public static EnumSingleton getInstance(){         return INSTANCE;     } }

我们把上面反射的那个代码,来测试这个枚举式单例模式。

public class EnumTest {     public static void main(String[] args) {         try {             Class<?> clazz = EnumSingleton.class;             Constructor constructor = clazz.getDeclaredConstructor(null);             //强行访问             constructor.setAccessible(true);             Object object = constructor.newInstance();              Object object1 = EnumSingleton.getInstance();              System.out.println(object == object1);         } catch (Exception ex) {             ex.printStackTrace();         }     } }

运行这段代码:

java.lang.NoSuchMethodException: com.tian.my_code.test.designpattern.singleton.EnumSingleton.<init>()  at java.lang.Class.getConstructor0(Class.java:3082)  at java.lang.Class.getDeclaredConstructor(Class.java:2178)  at com.tian.my_code.test.designpattern.singleton.EnumTest.main(EnumTest.java:41)

还真的不能用反射来搞。如果此时面试官,为什么枚举不能被反射呢?

为什么枚举不能被反射呢?

我们在反射的代码中

Constructor constructor = clazz.getDeclaredConstructor(null);

这行代码是获取他的无参构造方法。并且,从错误日志中,我们也可以看到,错误出现就是在getConstructor0方法中,并且,提示的是没有找到无参构造方法。

很奇怪,枚举也是类,不是说如果我们不给类显示定义构造方法时候,会默认给我们创建一个无参构造方法吗?

于是,我想到了一个办法,我们可以使用jad这个工具去反编译的我们的枚举式单例的.class文件。

找到我们的class文件所在目录,然后我们可以执行下面这个命令:

C:\Users\Administrator>jad D:\workspace\my_code\other-local-demo\target\classes com\tian\my_code\test\designpattern\singleton\EnumSingleton.class Parsing D:\workspace\my_code\other-local-demo\target\classes\com\tian\my_code\t st\designpattern\singleton\EnumSingleton.class... Generating EnumSingleton.jad

注意:class文件目录以及生成的jad文件所在的目录。

然后打开EnumSingleton.jad 文件:

单例模式的介绍和用法

于是,我就想到了,那我们使用有参构造方法来创建:

public class EnumTest {     public static void main(String[] args) {         try {             Class<?> clazz = EnumSingleton.class;              Constructor constructor = clazz.getDeclaredConstructor(String.class,int.class);             //强行访问             constructor.setAccessible(true);             Object object = constructor.newInstance("田维常",996);              Object object1 = EnumSingleton.getInstance();              System.out.println(object == object1);         } catch (Exception ex) {             ex.printStackTrace();         }     } }

再次运行这段代码,结果:

java.lang.IllegalArgumentException: Cannot reflectively create enum objects  at java.lang.reflect.Constructor.newInstance(Constructor.java:417)  at com.tian.my_code.test.designpattern.singleton.EnumTest.main(EnumTest.java:45)

提示很明显了,就是不让我们使用反射的方式创建枚举对象。

public T newInstance(Object ... initargs)      throws InstantiationException, IllegalAccessException,             IllegalArgumentException, InvocationTargetException  {      if (!override) {          if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {              Class<?> caller = Reflection.getCallerClass();              checkAccess(caller, clazz, null, modifiers);          }      }      //Modifier.ENUM就是用来判断是否为枚举的      if ((clazz.getModifiers() & Modifier.ENUM) != 0)          throw new IllegalArgumentException("Cannot reflectively create enum objects");      ConstructorAccessor ca = constructorAccessor;   // read volatile      if (ca == null) {          ca = acquireConstructorAccessor();      }      @SuppressWarnings("unchecked")      T inst = (T) ca.newInstance(initargs);      return inst;  }

所以,到此,我们才算真正的理清楚了,为什么枚举不让反射的原因。

序列化破坏

我们以非线程安全的饿汉式来演示一下,看看序列化是如何破坏到了模式的。

public class ReflectTest {      public static void main(String[] args) {         // 准备两个对象,singleton1接收从输入流中反序列化的实例         HungrySingleton singleton1 = null;         HungrySingleton singleton2 = HungrySingleton.getInstance();         try {             // 序列化             FileOutputStream fos = new FileOutputStream("HungrySingleton.txt");             ObjectOutputStream oos = new ObjectOutputStream(fos);             oos.writeObject(singleton2);             oos.flush();             oos.close();              // 反序列化             FileInputStream fis = new FileInputStream("HungrySingleton.txt");             ObjectInputStream ois = new ObjectInputStream(fis);             singleton1 = (HungrySingleton) ois.readObject();             ois.close();              System.out.println(singleton1);             System.out.println(singleton2);                          System.out.println(singleton1 == singleton2);          } catch (Exception e) {             e.printStackTrace();         }     } }

运行结果:

com.tian.my_code.test.designpattern.singleton.HungrySingleton@7e6cbb7a com.tian.my_code.test.designpattern.singleton.HungrySingleton@452b3a41 false

看到了吗?

使用序列化是可以破坏到了模式的,这种方式,可能很多人不是很清楚。

如何防止呢?

我们对非线程安全的饿汉式代码进行稍微修改:

public class HungrySingleton implements Serializable{      private static final HungrySingleton INSTANCE;     static {         INSTANCE=new HungrySingleton();     }      private HungrySingleton(){      }      public static HungrySingleton getInstance(){         return INSTANCE;     }     //添加了readResolve方法,并返回INSTANCE     private Object readResolve方法,并返回(){         return INSTANCE;     } }

再次运行上那段序列化测试的代码,其结果如下:

com.tian.my_code.test.designpattern.singleton.HungrySingleton@452b3a41 com.tian.my_code.test.designpattern.singleton.HungrySingleton@452b3a41 true

嘿嘿,这样我们是不是就避免了只创建了一个实例?

答案:否

在类ObjectInputStream的readObject()方法中调用了另外一个方法readObject0(false)方法。在readObject0(false)方法中调用了checkResolve(readOrdinaryObject(unshared))方法。

在readOrdinaryObject方法中有这么一段代码:

Object obj; try {       //是否有构造方法,有构造放就创建实例       obj = desc.isInstantiable() ? desc.newInstance() : null;  } catch (Exception ex) {  ...   } //判断单例类是否有readResolve方法 if (desc.hasReadResolveMethod()) {     Object rep = desc.invokeReadResolve(obj);  }  //invokeReadResolve方法中 if (readResolveMethod != null) {      //调用了我们单例类中的readResolve,并返回该方法返回的对象     //注意:是无参方法      return readResolveMethod.invoke(obj, (Object[]) null); }

绕了半天,原来他是这么玩的,上来就先创建一个实例,然后再去检查我们的单例类是否有readResolve无参方法,我们单例类中的readResolve方法

private Object readResolve(){         return INSTANCE; }

结论

我们重写了readResolve()无参方法,表面上看是只创建了一个实例,其实只创建了两个实例。

紧接着,面试官继续问:枚举式单例能不能被序列化破坏呢?

枚举式单例能不能被序列化破坏呢?

答案:不能被破坏,请看我慢慢给你道来。

don't talk ,show me the code。

我们先来验证一下是否真的不能被破坏,请看代码:

public class EnumTest {      public static void main(String[] args) {         // 准备两个对象,singleton1接收从输入流中反序列化的实例         EnumSingleton singleton1 = null;         EnumSingleton singleton2 = EnumSingleton.getInstance();         try {             // 序列化             FileOutputStream fos = new FileOutputStream("EnumSingleton.obj");             ObjectOutputStream oos = new ObjectOutputStream(fos);             oos.writeObject(singleton2);             oos.flush();             oos.close();              // 反序列化             FileInputStream fis = new FileInputStream("EnumSingleton.obj");             ObjectInputStream ois = new ObjectInputStream(fis);             singleton1 = (EnumSingleton) ois.readObject();             ois.close();              System.out.println(singleton1);             System.out.println(singleton2);              System.out.println(singleton1 == singleton2);          } catch (Exception e) {             e.printStackTrace();         }     } }

运行结果:

INSTANCE INSTANCE true

确实,枚举式单例是不会被序列化所破坏,那为什么呢?总得有个证件理由吧。

在类ObjectInputStream的readObject()方法中调用了另外一个方法readObject0(false)方法。在readObject0(false)方法中调用了checkResolve(readOrdinaryObject(unshared))方法。

case TC_ENUM:    return checkResolve(readEnum(unshared));

在readEnum方法中

private Enum<?> readEnum(boolean unshared) throws IOException {         if (bin.readByte() != TC_ENUM) {             throw new InternalError();         }         Class<?> cl = desc.forClass();         if (cl != null) {             try {                 @SuppressWarnings("unchecked")                 //重点                 Enum<?> en = Enum.valueOf((Class)cl, name);                 result = en;                 //...其他代码省略             }         } } public static <T extends Enum<T>> T valueOf(Class<T> enumType,                                                 String name) {        //enumType.enumConstantDirectory()返回的是一个HashMap        //通过HashMap的get方法获取         T result = enumType.enumConstantDirectory().get(name);         if (result != null)             return result;         if (name == null)             throw new NullPointerException("Name is null");         throw new IllegalArgumentException(             "No enum constant " + enumType.getCanonicalName() + "." + name); } //返回一个HashMap  Map<String, T> enumConstantDirectory() {         if (enumConstantDirectory == null) {             T[] universe = getEnumConstantsshared();             if (universe == null)                 throw new IllegalArgumentException(                     getName() + " is not an enum type");             //使用的是HashMap             Map<String, T> m = new HashMap<>(2 * universe.length);             for (T constant : universe)                 m.put(((Enum<?>)constant).name(), constant);             enumConstantDirectory = m;         }         return enumConstantDirectory; }

所以,枚举式单例模式是使用了Map

spring中也是有大量使用这种注册式单例模式,ioc容器就是典型的代表。

总结

本文讲述了单例模式的定义、单例模式常规写法。单例模式线程安全问题的解决,反射破坏、反序列化破坏等。

注意:不要为了套用设计模式,而使用设计模式。而是要,在业务上遇到问题时,很自然地联想单设计模式作为一种捷径方法。

单例模式的优缺点

优点

在内存中只有一个实例,减少内存开销。可以避免对资源的多重占用。设置全局访问点,严格控制访问。

缺点

没有借口,扩展性很差。如果要扩展单例对象,只有修改代码,没有其他途径。

单例模式是 不符合开闭原则的。

到此,相信大家对“单例模式的介绍和用法”有了更深的了解,不妨来实际操作一番吧!这里是编程网网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

--结束END--

本文标题: 单例模式的介绍和用法

本文链接: https://www.lsjlt.com/news/67317.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • 单例模式的介绍和用法
    本篇内容主要讲解“单例模式的介绍和用法”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“单例模式的介绍和用法”吧!问题1、说说单例模式的特点2、你知道单例模式的具体...
    99+
    2024-04-02
  • Java单例模式简单介绍
    一、概念单例模式是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例类的特殊类。通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的控制并节约系统资源。如果希望在系统中某个类的对象只能存在一个,...
    99+
    2023-05-31
    java 单例模式 ava
  • C#单例模式与多线程用法介绍
    一、单例模式 我们先来看看两种创建单例模式的示例代码。 1、饿汉式  饿汉式创建单例模式是在程序里面直接初始化了一个对象实例: class Good { /// &...
    99+
    2024-04-02
  • java设计模式中的单例模式简单介绍
    这篇文章主要介绍“java设计模式中的单例模式简单介绍”,在日常操作中,相信很多人在java设计模式中的单例模式简单介绍问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”java设计模式中的单例模式简单介绍”的疑...
    99+
    2023-06-02
  • Java详细介绍单例模式的应用
    目录一、什么是单例模式二、实现单例模式的几种方法1. 懒汉模式(线程不安全)2. 懒汉模式(线程安全)3. 饿汉模式一、什么是单例模式 单例模式(Singleton Pattern)...
    99+
    2024-04-02
  • Java实现单例模式的五种方法介绍
    目录饿汉式懒汉式双重检查锁静态内部类内部枚举类实现饿汉式 立即加载 防止new对象,构造私有,写一个公共的方法返回对象 占用空间,线程安全 public class Singleto...
    99+
    2023-01-31
    Java单例模式 Java单例模式实现方式
  • 设计模式和反模式简单介绍
    作为一个资深开发人员,大家都应该听说过设计模式(design pattern),但是不是所有的人都听说过反模式(anti-pattern)。今天我们就来谈谈后者,何为反模式。谈反模式之前当然先要谈谈何为设计模式,因为两者是紧密联系在一起的。...
    99+
    2023-06-03
  • C++单例模式基础内容介绍
    这篇文章主要介绍“C++单例模式基础内容介绍”,在日常操作中,相信很多人在C++单例模式基础内容介绍问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”C++单例模式基础内容介绍”的疑惑有所帮助!接下来,请跟着小编...
    99+
    2023-06-17
  • CentOS系统单用户模式介绍
    这篇文章主要介绍“CentOS系统单用户模式介绍”,在日常操作中,相信很多人在CentOS系统单用户模式介绍问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”CentOS系统单用户模式介绍”的疑惑有所帮助!接下来...
    99+
    2023-06-16
  • JavaScript组合模式的简单介绍
    这篇文章主要介绍“JavaScript组合模式的简单介绍”,在日常操作中,相信很多人在JavaScript组合模式的简单介绍问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Ja...
    99+
    2024-04-02
  • 工厂方法模式介绍
    韩敬海 设计模式(Java版) (一)定义 定义一个创建对象的接口,让子类决定实例化哪个类。工厂方法使一个类的实例化延迟到其子类。 工厂方法涉及的角色有: 1 .抽象工厂角色:工厂方法模式的核心,与应用系统无关,任何创建对象的工厂类必...
    99+
    2023-08-30
    工厂方法模式
  • Java设计模式之单例模式简介
    目录一、饿汉式(静态常量)二、饿汉式(静态代码块)三、懒汉式(线程不安全)四、懒汉式(线程安全,同步方法)五、懒汉式(线程不安全,同步代码块)六、双重检查( DCL )七、静态内部类...
    99+
    2024-04-02
  • MySQL的SQL模式介绍
    这篇文章主要讲解了“MySQL的SQL模式介绍”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“MySQL的SQL模式介绍”吧! M...
    99+
    2024-04-02
  • Windows7的上帝模式的介绍与开启使用方法介绍(图文)
    GodMode的字面释义是:上帝模式。能够以此冠名,想来定有其非常之处。   简单来说,上帝模式可以理解为一个快捷方式;能籍其实现对系统设定的集中控制,让操作变得更简洁;只需鼠标轻轻一点,几乎所有设置,都可在一个窗口中找...
    99+
    2023-05-26
    win7上帝模式 介绍 开启 模式 使用 方法
  • Vue路由模式中的hash和history模式详细介绍
    目录1. 路由概念2. hash模式3. history路由模式1. 路由概念 路由的本质就是一种对应关系,根据不同的URL请求,返回对应不同的资源。那么url地址和真实的资源之间就...
    99+
    2024-04-02
  • HBase的安装模式介绍
     单机模式 – HBase 不使用HDFS,仅使用本地文件系统 – ZooKeeper与Hbase运行在同一个JVM中  分布式模式 – 伪分布式模式 所有进程运行在同一个节点上,不同进程运行...
    99+
    2024-04-02
  • Win10开发人员模式在哪和使用方法介绍
    这篇文章主要讲解了“Win10开发人员模式在哪和使用方法介绍”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Win10开发人员模式在哪和使用方法介绍”吧!首先在电脑桌面中点击左下方的Windo...
    99+
    2023-06-10
  • Docker的网络模式介绍
    这篇文章主要介绍“Docker的网络模式介绍”,在日常操作中,相信很多人在Docker的网络模式介绍问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Docker的网络模式介绍”...
    99+
    2024-04-02
  • Java - JWT的简单介绍和使用
    Java - JWT的简单介绍和使用 前言一. JWT 基础知识1.1 session 案例测试1.2 JWT 结构1.2.1 Header1.2.2 Payload1.2.3 Signatu...
    99+
    2023-10-27
    java 开发语言 spring boot
  • CSS使用盒模型的实例介绍
    这篇文章主要讲解了“CSS使用盒模型的实例介绍”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“CSS使用盒模型的实例介绍”吧!1. 为元素应用内边距应用内边距...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作