【Spring】Bean作用域, 工厂模式, Bean的获取方式等重点知识汇总

1. 单例和多例(Bean的作用域):

  • Spring默认情况下是如何管理这个Bean的:

  • 默认情况下Bean是单例的 (单例: singleton)

  • 在Spring上下文初始化的时候实例化

  • 每一调用getBean()方法的时候, 都返回那个单例的对象

// xml
// scope默认情况下就是singleton单例的
<bean id="dog" class="com.powernode.bean.Dog"></bean>

// @Test
public void test(){
    ApplicationContext ctx = new ClassPathXmlApplicationContext("set-DI.xml");
    Dog dog1 = ctx.getBean("dog", Dog.class);
    System.out.println(dog1);// com.powernode.bean.Dog@4e41089d

    Dog dog2 = ctx.getBean("dog", Dog.class);
    System.out.println(dog2);// com.powernode.bean.Dog@4e41089d

    Dog dog3 = ctx.getBean("dog", Dog.class);
    System.out.println(dog3);// com.powernode.bean.Dog@4e41089d
}
  • 当将bean的scope属性设置为prototype

  • bean是多例的

  • spring上下文初始化的时候, 并不会初始化这些prototype的bean

  • 每一次调用getBean()方法的时候, 实例化该bean对象

  • prototype翻译为: 原型

// xml
<bean id="dog" class="com.powernode.bean.Dog" scope="prototype"></bean>
      
// @Test
public void test(){
    ApplicationContext ctx = new ClassPathXmlApplicationContext("set-DI.xml");
    Dog dog1 = ctx.getBean("dog", Dog.class);
    // 构造方法执行!
	// com.powernode.bean.Dog@4e41089d
    System.out.println(dog1);

    Dog dog2 = ctx.getBean("dog", Dog.class);
    // 构造方法执行!
	// com.powernode.bean.Dog@32a068d1
    System.out.println(dog2);

    Dog dog3 = ctx.getBean("dog", Dog.class);
    // 构造方法执行!
	// com.powernode.bean.Dog@33cb5951
    System.out.println(dog3);
}
  • scope属性的值:

  • singleton: 单例

  • prototype: 原型/多例

引入springMVC框架之后:

  • request: 一次请求当中一个bean, 仅限于在WEB应用中使用

  • session: 一次会话中只有一个bean, 仅限于在WEB应用中使用

2. GoF之工厂模式:

  • 设计模式: 一种可以被重复利用的解决方案

2.1 工厂模式的三种形态:

  • 简单工厂模式: 不属于23种设计模式之一, 又叫做静态工厂方法模式, 简单工厂模式是工厂方法模式的一种特殊实现

  • 工厂方法模式: 是23种设计模式之一

  • 抽象工厂模式: 是23 种设计模式之一

2.2 简单工厂模式:

  • 简单工厂模式是工厂方法模式的一种特殊实现, 又被称为: 静态工厂方法模式

  • 简单工厂模式解决什么问题?

  • 客户端程序不需要关心对象的创建细节, 需要哪个对象时, 只需要向工厂索要即可, 初步实现了责任的分离, 客户端只负责消费, 工厂负责生产, 生产和消费分离开来.

  • 简单工厂模式中的角色:

  • 抽象产品角色 Weapon

  • 具体产品角色 Gun

  • 工厂类角色 WeaponFactory

  • 简单工厂模式的缺点:

  • 缺点1: 工厂类集中了所有产品的创造逻辑, 形成了一个无所不知的全能类, 工厂类非常关键, 不能出问题, 一旦出了问题, 整个系统就会瘫痪

  • 缺点2: 不符合OCP开闭原则, 在进行系统功能扩展的时候, 需要修改工厂类

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

// 抽象产品
public abstract class Weapon {
    // 所有的武器都可以攻击
    public abstract void attack();
}

// 具体产品
public class Dagger extends Weapon{
    @Override
    public void attack() {
        System.out.println("砍他!!!");
    }
}
public class Fighter extends Weapon{
    @Override
    public void attack() {
        System.out.println("战斗机丢炸弹!!!");
    }
}
public class Tank extends Weapon{
    @Override
    public void attack() {
        System.out.println("坦克开炮!!!");
    }
}

// 工厂类
public class WeaponFactory {
    /**
     * 静态方法: 要获取什么产品? 就看你传什么参数
     * 简单工厂模式中有一个静态方法, 所以被称为: 静态工厂方法模式
     */
    public static Weapon get(String weaponType){
        if("TANK".equals(weaponType)){
            return new Tank();
        } else if("DAGGER".equals(weaponType)){
            return new Dagger();
        } else if("FIGHTER".equals(weaponType)){
            return new Fighter();
        } else {
            throw new RuntimeException("不支持该武器的生产!");
        }
    }
}

// 客户端程序
public class Test {
    public static void main(String[] args) {
        // 需要坦克
        // 对于我客户端来说, 坦克的生产细节, 我不需要关心, 我只需要向工厂索要就行
        // 简单工厂模式达到了什么呢? 职责分离, 客户端不需要关心产品的生产细节
        // 客户端只负责消费, 工厂类负责生产, 一个负责生产, 一个负责消费, 生产者和消费者分离, 者就是简单工厂的作用
        Weapon tank = WeaponFactory.get("TANK");
        tank.attack();
        Weapon fighter = WeaponFactory.get("FIGHTER");
        fighter.attack();
        Weapon dagger = WeaponFactory.get("DAGGER");
        dagger.attack();

        Tank tank1 = new Tank();
        tank1.attack();
    }
}

2.3 工厂方法模式:

  • 工厂方法模式既保留了简单工厂模式的优点, 同时又解决了简单工厂模式的缺点

  • 工厂方法模式中的优点:

  • 当你扩展一个产品的时候, 符合OCP原则, 因为只需要俩个类, 一个类是具体产品类, 一个类是具体工厂类, 都是添加类, 没有修改之前的代码, 所以符合OCP

  • 一个调用者想创建一个对象, 只要知道其名称就可以了

  • 屏蔽产品的具体实现, 调用者只关心产品的接口

  • 工厂方法模式的缺点:

  • 每次增加一个产品的话, 都需要增加一个具体类和对象实现工厂, 使得系统中类的个数成倍增加

  • 在一定程度上增加了系统的复杂度, 同时也增加了系统具体类的依赖, 这并不是好事.

  • 工厂方法模式的角色包括:

  • 抽象产品角色 Weapon

  • 具体产品角色 Dagger Gun

  • 抽象工厂角色 WeaponFactory

  • 具体工厂角色 DaggerFactory GunFactory

  • 一个产品一个工厂

// 抽象产品角色
public abstract class Weapon {
    // 所有的武器都可以攻击
    public abstract void attack();
}

// 具体产品角色:
public class Tank extends Weapon {
    @Override
    public void attack() {
        System.out.println("坦克开炮!!!");
    }
}
public class Fighter extends Weapon {
    @Override
    public void attack() {
        System.out.println("战斗机丢炸弹!!!");
    }
}

// 具体工厂角色:
public class TankFactory extends WeaponFactory{
    @Override
    public Weapon get() {
        return new Tank();
    }
}
public class FighterFactory extends WeaponFactory{
    @Override
    public Weapon get() {
        return new Fighter();
    }
}

// 抽象工厂角色
abstract public class WeaponFactory {

     // 这个方法不是静态的, 是实例方法
     public abstract Weapon get();
}

// 这是客户端程序
public class Test {
    public static void main(String[] args) {
        WeaponFactory weaponFactory = new TankFactory();
        Weapon tank = weaponFactory.get();
        tank.attack();

        WeaponFactory weaponFactory1 = new FighterFactory();
        Weapon fighter = weaponFactory1.get();
        fighter.attack();
    }
}

3. Bean的获取方式(4种):

  • Spring为Bean提供了多种实例化方式, 通常包括4种方式, 也就是说在spring中为Bean对象的创建准备了多种方案, 目的是: 更加灵活

  • 第一种方法: 通过构造方法实例化

// xml
// 直接在spring配置文件中配置类全路径
// Spring会自动的调用该类的无参数构造方法来实例化bean
<bean id="dog" class="com.powernode.bean.Dog"></bean>

// @Test
public void setEmpty(){
    ApplicationContext ctx = new ClassPathXmlApplicationContext("set-DI.xml");
    Dog dog = ctx.getBean("dog", Dog.class);
    System.out.println(dog);
}
  • 第二种方式: 通过简单工厂模式实例化

  • 通过简单工厂模式, 你需要在spring配置文件中告诉spring框架, 调用哪个类的哪个方法获取Bean

  • factory-method 属性指定的是工厂类当中的静态方法, 也就是告诉Spring框架, 调用这个方法可以获取Bean

// 类
public class Start {
    public Start() {
        System.out.println("大明星");
    }
}

// 简单工厂模式中的工厂类角色
public class StartFactory {
    // 工厂类中有一个静态方法
    // 简单工厂模式, 又叫做: 静态工厂方法模式
    public static Start get(){
        return new Start();
    }
}

// xml
// Spring提供的实例化方式第二种, 通过简单工厂模式, 你需要在spring配置文件中告诉spring框架, 调用哪个类的哪个方法获取Bean
// factory-method 属性指定的是工厂类当中的静态方法, 也就是告诉Spring框架, 调用这个方法可以获取Bean
<bean id="stars" class="com.powernode.xxxx.StartFactory" factory-method="get"/>
    
// @Test
public void conStars(){
    ApplicationContext ctx = new ClassPathXmlApplicationContext("set-DI.xml");
    Start strs = ctx.getBean("stars", Start.class);
    System.out.println(strs);
}
  • 第三种方式: 通过factory-bean实例化

  • 通过工厂方法模式, 通过factory-bean属性+factory-method属性共同完成, 告诉spring框架, 调用哪个对象的哪个方法来获取bean

  • factory-bean属性告诉spring调用哪个对象, factory-method告诉spring调用该对象的哪个方法

// 工厂方法模式中的具体产品角色
public class Gun {
    public Gun() {
        System.out.println("开枪!!");
    }
}

// 工厂方法模式中的具体工厂角色
public class GunFactory {
    // 工厂模式中的具体工厂角色中的方法是: 实例方法
    public Gun get(){
        return new Gun();
    }
}

// xml
// Spring提供的实例化方式第三种, 通过工厂方法模式, 通过factory-bean属性+factory-method属性共同完成, 告诉spring框架, 调用哪个对象的哪个方法来获取bean
<bean id="gunFactory" class="com.powernode.xxxx.GunFactory"/>
// factory-bean属性告诉spring调用哪个对象, factory-method告诉spring调用该对象的哪个方法
<bean id="gun" factory-bean="gunFactory" factory-method="get"/>

// @Test
public void conGun(){
    ApplicationContext ctx = new ClassPathXmlApplicationContext("set-DI.xml");
    Gun gun = ctx.getBean("gun", Gun.class);
    System.out.println(gun);
}
  • 第四种方式: 通过FactoryBean接口实例化

  • 上述的第三种方式中, factory-bean是我们自己定义的, factory-method也是我们自己定义的

  • 当你编写的类直接实现了FactoryBean接口之后, factory-bean不需要指定了, factory-method也不需要指定了

  • factory-bean会自动指向实现FactoryBean接口的类, factory-method会自动指向getObject()方法

// 普通的bean
public class Person {
    public Person() {
        System.out.println("蚂蚁");
    }
}

// PersonFactory也是一个bean, 只不过这个bean有点特殊, 叫做工厂bean
// 通过工厂Bean这个特殊的Bean可以获取一个普通的Bean
public class PersonFactory implements FactoryBean {
    @Override
    public Object getObject() throws Exception {
        return new Person();
    }

    @Override
    public Class<?> getObjectType() {
        return null;
    }

    // 这个方法在接口当中默认实现的
    // 默认返回true, 表示单例的
    // 如果想多例, 直接修改为return false即可
    @Override
    public boolean isSingleton() {
        return true;
    }
}

// xml
// 这种方式实际上就是第三种方式的简化, 由于你编写的类实现了BeanFactory接口, 所有不需要手动指定factory-bean factory-method
// 通过FactoryBean这个工厂Bean主要是想对普通Bean进行加工处理
<bean id="person" class="com.powernode.xxxx.PersonFactory"/>
    
// @Test
public void conPerson(){
    ApplicationContext ctx = new ClassPathXmlApplicationContext("set-DI.xml");
    Person person = ctx.getBean("person", Person.class);
    System.out.println(person);
}

4. BeanFactory和FactoryBean的区别:

  • BeanFactory

  • Spring IoC容器的顶级接口, BeanFactory翻译为"Bean工厂", 在Spring IoC容器中, Bean工厂负责Bean对象的创建

  • BeanFactory是工厂

  • FactoryBean

  • 是一个工厂Bean, 是一个能够辅助Spring实例化其他Bean对象的一个Bean

  • 在Spring中, Bean可以分为俩类:

  1. 普通Bean

  1. 工厂Bean (工厂Bean也是一种Bean, 只不过这种Bean比较特殊, 它可以辅助Spring实例化其他Bean对象)

5. ApplicationContext和BeanFactory的区别:

  • 相同点:

  • 都可以得到Spring上下文对象

  • 都是来自Spring的顶级接口

  • 不同点:

  • 继承关系和功能: ApplicationContext属于BeanFactory的子类, BeanFactory只有简单的访问Bean的能力, 而ApplicationContext除了拥有BeanFactory功能之外, 还包含了更多的功能(国际化支持, 资源访问, 事件传播)

  • 性能: ApplicationContext加载方式是将Bean对象一次性加载, 所以再后面访问Bean对象时会很快, BeanFactory需要某个Bean时, 采取加载Bean对象, 所以它在执行Bean获取时, 比较慢.

猜你喜欢

转载自blog.csdn.net/qq_68993495/article/details/128925987
今日推荐