【深入浅出Spring6】第三期——作用域和工厂模式

news2025/7/15 21:02:17

一、Bean 的作用域

  • 作用域以下用 scope 代替,在不同的应用情景下可以使用的参数值下是不同的
  • 我们以普通 Java 工程为例:可选的参数值有两个 singleton、prototype

$ singleton

  • 默认情况下,scope 的属性值就为 singleton,当然我们也可以显式的定义为 singleton
  • 需求:我们想测试以前之前创建的bean对象是单例还是多例的

编写我们待测试的BeanSpringBean.java

package com.powernode.spring6.bean;

/**
 * @author Bonbons
 * @version 1.0
 */
public class SpringBean {
    public SpringBean(){
        System.out.println("调用了无参构造方法");
    }
}

我们之前就知道,Spring创建对象是在初始化上下文的时候进行的,而且调用了无参构造方法,此处我们直接给出无参构造方法,方便更好的说明问题

编写我们的 spring 配置文件 spring-scope.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!--声明我们的bean-->
    <bean id="sb" class="com.powernode.spring6.bean.SpringBean"/>
</beans>

编写测试方法,利用getBean方法多次获取我们的Bean对象

@Test
    public void testBeanScope(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-scope.xml");
        SpringBean sb = applicationContext.getBean("sb", SpringBean.class);
        System.out.println(sb);

        SpringBean sb2 = applicationContext.getBean("sb", SpringBean.class);
        System.out.println(sb2);

        SpringBean sb3 = applicationContext.getBean("sb", SpringBean.class);
        System.out.println(sb3);

        /**
         * 测试结果,输出的三个bean是一个对象
         * 原因:
         *    在我们解析XML配置文件的时候,对象就已经调用无参构造方法创建结束了
         *    在我们调用getBean的时候得到的就是已经创建好的对象,默认情况下是单例模式的
         */
    }

在这里插入图片描述

  • 通过测试结果我们可以发现,无参构造方法只被调用一次,而且通过getBean方法获取到的对象都是同一个实例
  • 得出结论:默认情况下我们创建的Bean对象的单例的
  • Bean对象的创建是在初始化Spring上下文的时候就完成的。
  • 那么如果我们想通过getBean获得不同的对象,我们应该怎么做呢?

$ prototype

  • 单词的含义为原型、多例,我们可以将scope的属性值定义为 prototype 来解决上面的问题
  • 我们修改一下配置文件的那条bean定义语句,并再次运行测试文件
<bean id="sb" class="com.powernode.spring6.bean.SpringBean" scope="prototype"/>

在这里插入图片描述

  • 我们可以发现,调用了三次无参构造方法,我们获得的是三个不同的Bean的对象

  • 我们在使用默认的作用域时,无论是否调用getBean方法,都会调用我们Bean类的无参构造方法,但是当我们将作用域定义为 prototype 的时候,如果没有调用getBean方法就不会去调用无参构造方法

$ 其他 scope

  • 其实我们Bean 的作用域并不是只有两个,但是有些作用域只有在特定的情景下才会有效

  • 那么Bean的作用域都包括哪些呢?
    在这里插入图片描述

  • 尽管自定义的 scope 很少使用,但是我们还是给出如果来自定义 scope

  • 需求:我们先测试一下,不同线程创建的Bean是单例的还是多列的?

还是利用我们上面的文件,只是在测试方法处创建新的线程进而再获得实例 【scope采用默认值】

 @Test
    public void testThreadScope(){
        // 获得一个SpringBean的实例
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-scope.xml");
        SpringBean sb1 = applicationContext.getBean("sb", SpringBean.class);
        System.out.println(sb1);

        SpringBean sb2 = applicationContext.getBean("sb", SpringBean.class);
        System.out.println(sb2);
        // 创建一个新的线程
        new Thread(new Runnable() {
            @Override
            public void run() {
                SpringBean sb3 = applicationContext.getBean("sb", SpringBean.class);
                System.out.println(sb3);
            }
        }).start();
    }

经过前面在 singleton 部分的测试我们知道,sb1和sb2一定是同一个对象,那么到底不同线程的bean是单例的还是多例的呢?

在这里插入图片描述

  • 很显然,不同线程获得的Bean仍然是单例的
  • 我们想自定义一个scope,实现不同线程获得的是不同的Bean的实例

(1)我们自定义一个Scope类,实现Scope接口

  • spring内置了线程范围的类:org.springframework.context.support.SimpleThreadScope,可以直接用

(2)将我们自定义的Scope注册到Spring容器中 【此处我们直接就定义到了上面的 spring-scope.xml中】

<!--配置我们自定义的scope-->
    <bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
        <property name="scopes">
            <map>
                <entry key="threadScope">
                    <bean class="org.springframework.context.support.SimpleThreadScope" />
                </entry>
            </map>
        </property>
    </bean>

(3)想要使用我们的这个scope只需在声明bean的时候将scope属性的值设置为我们自定义的scope即可

<!-使用我们自定义的scope-->
<bean id="sb" class="com.powernode.spring6.bean.SpringBean" scope="threadScope"/>

(4)再次测试我们上面那个不同线程获得的bean对象是否为同一个

@Test
    public void testThreadScope(){
        // 获得一个SpringBean的实例
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-scope.xml");
        SpringBean sb1 = applicationContext.getBean("sb", SpringBean.class);
        System.out.println(sb1);

        SpringBean sb2 = applicationContext.getBean("sb", SpringBean.class);
        System.out.println(sb2);
        // 创建一个新的线程
        new Thread(new Runnable() {
            @Override
            public void run() {
                SpringBean sb3 = applicationContext.getBean("sb", SpringBean.class);
                System.out.println(sb3);
            }
        }).start();
    }

在这里插入图片描述
通过结果我们可以看到,已经实现了不同线程通过getBean方法获得的bean的对象不是同一个


二、GoF 工厂模式

  • GoF 的中文含义代表四人组(指的是编写设计模式的四个作者)

  • 设计模式:可以重复利用的一种解决问题的方案,该书中包含 23 种设计模式,当然也存在其他的设计模式

  • GoF 23种设计模式可以分为三大类:

    • 创建型:解决对象创建问题
      • 单例模式
      • 工厂方法模式
      • 抽象工厂模式
      • 建造者模式
      • 原型模式
    • 结构型:一些类或对象组合在一起的经典结构
      • 代理模式
      • 装饰模式
      • 适配器模式
      • 组合模式
      • 享元模式
      • 外观模式
      • 桥接模式
    • 行为型:解决类或对象之间的交互问题
      • 策略模式
      • 模板方法模式
      • 责任链模式
      • 观察者模式
      • 迭代子模式
      • 命名模式
      • 备忘录模式
      • 状态模式
      • 访问者模式
      • 中介者模式
      • 解释器模式
  • 因为Spring容器使用了大量的工厂模式,所以接下来我们对工厂模式展开论述

$ 工厂模式的三种形态

  • 简单工厂模式(静态工厂模式):是工厂方法模式的一种特殊形式
  • 工厂方法模式:GoF 设计模式的一种
  • 抽象工厂模式:GoF 设计模式的一种

$ 简单工厂模式

  • 简单工厂模式的角色有三个:
    • 抽象产品角色
    • 具体产品角色
    • 工厂类角色
  • 需求:我们通过编写对应角色的文件,来演示简单工厂模式究竟是怎样的?

编写抽象产品角色,抽象类 + 抽象方法 Weapon.java

package com.powernode.simple.factory;

/**
 * 抽象产品角色
 * @author Bonbons
 * @version 1.0
 */
public abstract class Weapon {
    // 定义一个抽象的攻击方法,具体内容由其子类去实现
    public abstract void attack();
}

编写具体产品角色,此处我们就给两个 Tank.java、Dagger.java 要继承我们的抽象产品角色并实现抽象方法

package com.powernode.simple.factory;

/**
 * 具体产品角色
 * @author Bonbons
 * @version 1.0
 */
public class Tank extends Weapon{
    @Override
    public void attack() {
        System.out.println("向我开炮!!!");
    }
}
package com.powernode.simple.factory;

/**
 * 具体产品角色
 * @author Bonbons
 * @version 1.0
 */
public class Dagger extends Weapon{
    @Override
    public void attack() {
        System.out.println("偷袭!!!");
    }
}

编写工厂类角色,WeaponFactory 类提供一个静态方法,根据我们客户端传递的参数,来决定生成哪个具体的产品角色对象

package com.powernode.simple.factory;

/**
 * 工厂类角色
 * @author Bonbons
 * @version 1.0
 */
public class WeaponFactory {
    /**
     * 简单工厂模式我们又称之为静态工厂模式:
     * 通过一个静态方法,根据我们的参数生成对应的具体产品角色的对象
     */

    public static Weapon get(String weapon){
        // 通过if条件判断去匹配对应的角色
        if("TANK".equals(weapon)){
            return new Tank();
        }else if("FIGHTER".equals(weapon)){
            return new Fighter();
        }else if("DAGGER".equals(weapon)){
            return new Dagger();
        }else{
            throw new RuntimeException("无法识别该类型!!!");
        }
    }
}

编写Test测试方法:

package com.powernode.simple.factory;

/**
 * @author Bonbons
 * @version 1.0
 */
public class Test {
    public static void main(String[] args) {

        // 如果我们需要坦克
        Weapon tank = WeaponFactory.get("TANK");
        tank.attack();

        // 如果我们需要偷袭
        Weapon dagger = WeaponFactory.get("DAGGER");
        dagger.attack();
    }
}

在这里插入图片描述

  • Spring 中的BeanFactory就采用了简单工厂模式

  • 简单工厂模式的优点:

    • 实现了责任的分离,工厂负责生产,客户端负责消费
    • 客户端程序不必关系对象创建的细节,想要创建哪个对象就传入对应的参数即可
  • 简单工厂模式的缺点:

    • 需要扩展新产品时,需要修改WeaponFactory类,违背了OCP开闭原则
    • 工厂类负责生产所有的产品,一旦出现问题就会导致全盘崩溃

$ 工厂方法模式

  • 工厂方法模式的角色对象有四个:【改变就是让一个具体的工厂去生产一种具体的产品】
    • 抽象产品角色
    • 具体产品角色
    • 抽象工厂角色
    • 具体工厂角色
  • 需求:我们创建一个新的模块还是通过实践演示工厂方法模式的原理是怎样的

创建一个新模块 factory-method 并不需要添加依赖什么的,因为这部分的内容用不到

编写我们的抽象产品角色 >> Weapon

package com.powernode.factory.method;

/**
 * 抽象产品角色
 * @author Bonbons
 * @version 1.0
 */
abstract public class Weapon {
    public abstract void attack();
}

编写我们的具体产品角色 >> Gun、Dagger

package com.powernode.factory.method;

/**
 * 具体产品角色
 * @author Bonbons
 * @version 1.0
 */
public class Gun extends Weapon{

    @Override
    public void attack() {
        System.out.println("开枪射击!!!");
    }
}
package com.powernode.factory.method;

/**
 * 具体产品角色
 * @author Bonbons
 * @version 1.0
 */
public class Dagger extends Weapon{

    @Override
    public void attack() {
        System.out.println("给你一刀!!!");
    }
}

编写我们的抽象工厂 >> WeaponFactory

package com.powernode.factory.method;

/**
 * 抽象工厂角色
 * @author Bonbons
 * @version 1.0
 */
abstract public class WeaponFactory {
    // 给出获得工厂对象的get方法,具体获得哪个工厂的对象由实现它的工厂决定
    public abstract Weapon get();
}

编写我们的具体工厂角色 >> GunFactory、DaggerFactory

package com.powernode.factory.method;

/**
 * 具体工厂角色
 * @author Bonbons
 * @version 1.0
 */
public class GunFactory extends WeaponFactory{
    @Override
    public Weapon get() {
        return new Gun();
    }
}
package com.powernode.factory.method;

/**
 * 具体工厂角色
 * @author Bonbons
 * @version 1.0
 */
public class DaggerFactory extends WeaponFactory{
    @Override
    public Weapon get() {
        return new Dagger();
    }
}

编写我们的测试方法

package com.powernode.factory.method;

/**
 * @author Bonbons
 * @version 1.0
 */
public class Test {
    public static void main(String[] args) {
        // 我们先获得想要的工厂
        WeaponFactory daggerFactory = new DaggerFactory();
        // 调用工厂的get方法,就可以获得对应工厂的产品
        Weapon dagger = daggerFactory.get();
        // 然后我们调用我们产品的方法
        dagger.attack();

        WeaponFactory gunFactory = new GunFactory();
        Weapon gun = gunFactory.get();
        gun.attack();
    }
}

在这里插入图片描述

  • 工厂方法模式的优点:

    • 如果想扩展一个新的产品,只要新增一个产品类,再新增一个该产品对应的工厂即可,解决了简单工厂模式的OCP问题
    • 扩展性高,为用户提供接口,屏蔽了产品的具体实现
  • 工厂方法模式的缺点:

    • 我们添加一个新产品就要添加具体的产品角色和具体的工厂角色,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。

$ 抽象工厂模式

  • 如何理解抽象工厂模式?

    • 工厂方法模式对应一个系列,抽象工厂模式就对应多个系列
    • 工厂方法模式针对的是一个产品等级结构;而抽象工厂模式针对的是多个产品等级结果
    • 抽象工厂模式可以向客户端提供一个接口,使客户端在不必指定产品的具体的情况下,创建多个产品族中的产品对象
  • 抽象工厂模式的组成:

    • 抽象工厂角色
    • 具体工厂角色
    • 抽象产品角色
    • 具体产品角色
  • 需求:我们写一个案例,包含两个系列——武器系列和水果系列

编写武器产品系列: 一个抽象产品角色、两个具体产品角色

package com.powernode.product;

/**
 * 武器产品族
 * @author 动力节点
 * @version 1.0
 * @className Weapon
 * @since 1.0
 **/
public abstract class Weapon {
    public abstract void attack();
}
package com.powernode.product;

/**
 * 武器产品族中的产品等级1
 * @author 动力节点
 * @version 1.0
 * @className Gun
 * @since 1.0
 **/
public class Gun extends Weapon{
    @Override
    public void attack() {
        System.out.println("开枪射击!");
    }
}
package com.powernode.product;

/**
 * 武器产品族中的产品等级2
 * @author 动力节点
 * @version 1.0
 * @className Dagger
 * @since 1.0
 **/
public class Dagger extends Weapon{
    @Override
    public void attack() {
        System.out.println("砍丫的!");
    }
}

编写水果产品系列: 一个抽象产品角色、两个具体产品角色

package com.powernode.product;

/**
 * 水果产品族
 * @author 动力节点
 * @version 1.0
 * @className Fruit
 * @since 1.0
 **/
public abstract class Fruit {
    /**
     * 所有果实都有一个成熟周期。
     */
    public abstract void ripeCycle();
}
package com.powernode.product;

/**
 * 水果产品族中的产品等级1
 * @author 动力节点
 * @version 1.0
 * @className Orange
 * @since 1.0
 **/
public class Orange extends Fruit{
    @Override
    public void ripeCycle() {
        System.out.println("橘子的成熟周期是10个月");
    }
}
package com.powernode.product;

/**
 * 水果产品族中的产品等级2
 * @author 动力节点
 * @version 1.0
 * @className Apple
 * @since 1.0
 **/
public class Apple extends Fruit{
    @Override
    public void ripeCycle() {
        System.out.println("苹果的成熟周期是8个月");
    }
}

编写我们的抽象工厂角色

package com.powernode.factory;

import com.powernode.product.Fruit;
import com.powernode.product.Weapon;

/**
 * 抽象工厂
 * @author 动力节点
 * @version 1.0
 * @className AbstractFactory
 * @since 1.0
 **/
public abstract class AbstractFactory {
    public abstract Weapon getWeapon(String type);
    public abstract Fruit getFruit(String type);
}

编写我们的具体工厂角色 >> 采用简单工厂的方式实现的

package com.powernode.factory;

import com.powernode.product.Dagger;
import com.powernode.product.Fruit;
import com.powernode.product.Gun;
import com.powernode.product.Weapon;

/**
 * 武器族工厂
 * @author 动力节点
 * @version 1.0
 * @className WeaponFactory
 * @since 1.0
 **/
public class WeaponFactory extends AbstractFactory{

    public Weapon getWeapon(String type){
        if (type == null || type.trim().length() == 0) {
            return null;
        }
        if ("Gun".equals(type)) {
            return new Gun();
        } else if ("Dagger".equals(type)) {
            return new Dagger();
        } else {
            throw new RuntimeException("无法生产该武器");
        }
    }

    @Override
    public Fruit getFruit(String type) {
        return null;
    }
}
package com.powernode.factory;

import com.powernode.product.*;

/**
 * 水果族工厂
 * @author 动力节点
 * @version 1.0
 * @className FruitFactory
 * @since 1.0
 **/
public class FruitFactory extends AbstractFactory{
    @Override
    public Weapon getWeapon(String type) {
        return null;
    }

    public Fruit getFruit(String type){
        if (type == null || type.trim().length() == 0) {
            return null;
        }
        if ("Orange".equals(type)) {
            return new Orange();
        } else if ("Apple".equals(type)) {
            return new Apple();
        } else {
            throw new RuntimeException("我家果园不产这种水果");
        }
    }
}

编写我们的客户端测试程序:

package com.powernode.client;

import com.powernode.factory.AbstractFactory;
import com.powernode.factory.FruitFactory;
import com.powernode.factory.WeaponFactory;
import com.powernode.product.Fruit;
import com.powernode.product.Weapon;

/**
 * @author 动力节点
 * @version 1.0
 * @className Client
 * @since 1.0
 **/
public class Client {
    public static void main(String[] args) {
        // 客户端调用方法时只面向AbstractFactory调用方法。
        AbstractFactory factory = new WeaponFactory(); // 注意:这里的new WeaponFactory()可以采用 简单工厂模式 进行隐藏。
        Weapon gun = factory.getWeapon("Gun");
        Weapon dagger = factory.getWeapon("Dagger");

        gun.attack();
        dagger.attack();

        AbstractFactory factory1 = new FruitFactory(); // 注意:这里的new FruitFactory()可以采用 简单工厂模式 进行隐藏。
        Fruit orange = factory1.getFruit("Orange");
        Fruit apple = factory1.getFruit("Apple");

        orange.ripeCycle();
        apple.ripeCycle();
    }
}

抽象工厂模式的优缺点:

  • 优点:当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象。
  • 缺点:产品族扩展非常困难,要增加一个系列的某一产品,既要在AbstractFactory里加代码,又要在具体的里面加代码 【违背了OCP原则】

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

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

相关文章

一种清洁机器人设计及仿真

目 录 第1章 绪论 1 第2章 清洁机器人路径规划方法的分类及现状 5 2.1 基于事例的学习规划方法 5 2.2 基于环境模型的规划方法 6 2.3 基于行为的结构 7 第3章 清洁机器人的设计任务及方案分析 10 3.1 清洁机器人竞赛介绍 10 3.2 设计任务分解 11 3.3 清洁机器人任务分析及基于行…

Unity和UE4两大游戏引擎,你该如何选择?

目录 游戏引擎 2 ——> 难易区别 编程语言 3 ——> 游戏产品 UE4制作的游戏产品 Unity制作的游戏产品 产品类型 5 ——> 资源商店 6 ——> 人才需求 平均薪资 总结 游戏引擎 Unity和UE4都是游戏引擎&#xff0c;所谓游戏引擎就是集成了复杂功能的游戏…

短视频/直播+教育成为教育新常态

互联网时代&#xff0c;网络视听应用已经成为吸引新网民的主要力量&#xff0c;2020年&#xff0c;在新增的3625万网民中&#xff0c;有23.9%是为了使用网络视听应用而来。网络视听应用中&#xff0c;最受欢迎的当属短视频&#xff0c;已然成为新的国民级应用行业。 如今&…

Excel之数据透视NotePad之列编辑

在日常工作中&#xff0c;经常有数据处理的需求&#xff0c;要统计个数&#xff0c;这里就可以使用到工具的一些功能&#xff0c;如 Excel、Notepad&#xff0c;记录下来&#xff0c;分享功能。 一、Excel 软件 Excel 功能过于强大&#xff0c;下面只是简单分享下日常使用到的…

【附源码】计算机毕业设计JAVA大数据文章发布系统

【附源码】计算机毕业设计JAVA大数据文章发布系统 目运行 环境项配置&#xff1a; Jdk1.8 Tomcat8.5 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; JAVA …

C++ Reference: Standard C++ Library reference: Containers: deque: deque: begin

C官网参考链接&#xff1a;https://cplusplus.com/reference/deque/deque/begin/ 公有成员函数 <deque> std::deque::begin C98 iterator begin(); const_iterator begin() const; C11 iterator begin() noexcept; const_iterator begin() const noexcept;返回指向开始…

基于五等均分法和Bob Stone法衡量RFM顾客价值

最近学习了衡量RFM模型的两种顾客价值的方法&#xff0c;即五等均分法和Bob Stone法。仅以此博客记录我的学习过程&#xff0c;后序学习到了其他方法再来补充。关于RFM实战案例可参考我的其他文章大数据分析案例-基于RFM模型对电商客户价值分析 大数据分析案例-用RFM模型对客户…

p53 与铁死亡有关?Nature 解锁新机制

众所周知&#xff0c;p53 是一种肿瘤抑制基因&#xff0c;被广泛称为“基因组的守护者”。自 1979 年被发现至今&#xff0c;p53 基因一直是分子生物学和肿瘤学的研究热门。据 Elie Dolgin 在 Nature 上发表的 “The most popular genes in the human genome” 统计&#xff0c…

wpf Viewport3D 学习

呈现 Viewport3D 元素的 2-D 布局范围内包含的 3-D 内容。就是3D画布&#xff0c; 继承 Object DispatcherObject DependencyObject Visual UIElement FrameworkElement Viewport3D 从FrameworkElement继承&#xff0c;FrameworkElement继承自UIElement&#xff1b; 该 V…

(五)Spring之Bean的作用域

文章目录环境单例的&#xff08;singleton&#xff09;多例的&#xff08;prototype&#xff09;其它scope自定义scope上一篇&#xff1a;&#xff08;四&#xff09;Spring对IoC的实现 环境 spring6里程碑版本的仓库 依赖&#xff1a;spring context依赖、junit依赖、log4j2…

【单片机基础】单片机中断和定时

中断什么是中断&#xff1f;中断IE寄存器中断查询次序例程定时器/计数器实现定时的方法&#xff1f;定时计数的概念什么是单片机定时器/计数器&#xff1f;定时器/计数器内部结构定时器的相关寄存器51单片机定时器初值计算方法详解例程中断 什么是中断&#xff1f; 中断是为使…

VINS学习(二)IMU预积分原理与实现

VINS学习&#xff08;二&#xff09;IMU预积分原理与实现一、连续时间下的IMU积分二、连续时间下的IMU预积分三、离散时间下的IMU预积分1. 欧拉法2. 中值法四、连续时间下的IMU状态误差传递五、离散时间下的IMU状态误差传递六、预积分量关于零偏的雅克比七、VINS代码实践1.预积…

【文末福利】半导体封装率先国产化,400+封装厂商最新名单汇总

根据我国国民经济“九五”计划至“十四五”规划&#xff0c;可窥见多方政策都在积极支持我国集成电路的发展&#xff0c;近几年更是强调突破集成电路关键技术&#xff0c;集中力量发展集成电路。其中封测技术作为集成电路制造的后道工艺&#xff0c;在整个集成电路产业链中扮演…

熬夜整理的vue面试题

Vue-router 路由模式有几种 vue-router 有 3 种路由模式&#xff1a;hash、history、abstract&#xff0c;对应的源码如下所示 switch (mode) {case history:this.history new HTML5History(this, options.base)breakcase hash:this.history new HashHistory(this, options…

网络安全设备之防火墙技术详解

一、防火墙概述 1、网络防火墙简介 无论是大中型企业网络,还是小型家庭办公网络,对网络安全方面的要求一直保持上升趋势。微软公司的官方网站尚且难逃黑客的魔爪,普通的中小网络更是难以抵抗了。解决网络安全问题最常用的防护手段就是安装网络防火墙,对于大中型规模的企业…

css实现流星划过动画

背景 &#x1f44f;渐变伪元素实现流星&#xff0c;translateY实现划过动画&#xff0c;速速来Get吧~ &#x1f947;文末分享源代码。记得点赞关注收藏&#xff01; 1.实现效果 2.实现原理 translateY()&#xff1a; translateY() 在页面垂直移动元素。 translateY(ty) 对应 …

上海亚商投顾:沪指重返3100点

上海亚商投顾前言&#xff1a;无惧大盘大跌&#xff0c;解密龙虎榜资金&#xff0c;跟踪一线游资和机构资金动向&#xff0c;识别短期热点和强势个股。 市场情绪三大指数今日低开高走&#xff0c;沪指重返3100点上方&#xff0c;深成指、创业板指午后均涨超2%。半导体板块掀涨停…

Java并发编程学习13-任务取消(下)

任务取消&#xff08;下&#xff09; 《任务取消》由于篇幅较多&#xff0c;拆分了两篇来介绍各种实现取消和中断的机制&#xff0c;以及如何编写任务和服务&#xff0c;使它们能对取消请求做出响应。 1. 任务限时运行 我们知道许多任务可能永远也无法处理完成&#xff08;…

[go学习笔记.第十四章.协程和管道] 3.协程配合管道案例以及管道的注意事项和使用细节

案例一 请完成goroutine和channel协同工作的案例&#xff0c;具体要求&#xff1a; (1).开启一个writeData协程&#xff0c;向管道intChan中写入50个整数. (2).开启一个readData协程&#xff0c;从管道intChan中读取writeData写入的数据 (3).注意&#xff1a; writeData和readD…

阿里内部目前最完整“Spring全线笔记”,不止是全家桶,太完整了

前言 对于每一位Java开发人员来说&#xff0c;提起Spring定是不陌生的&#xff0c;实际上自Spring框架诞生以来&#xff0c;就备受开发者的青睐&#xff0c;基本上现在的互联网公司都要使用到Spring框架。Spring框架中又包含了SpringMVC、SpringBoot、SpringCloud等&#xff0…