Spring框架学习笔记,超详细!!(2)

Java小白开始学习Spring框架,一方面,跟着视频学习,并记录下学习笔记,方便以后复习回顾。另一方面,发布学习笔记来约束自己,学习路程还很遥远,继续加油坚持!!!希望能帮助到大家!

另外还有我的牛客Java专项练习笔记专栏也在同步更新,希望大家多多关注,一起学习!!!

本次更新了GoF之工厂模式、Bean的实例化方式、Bean的生命周期等相关知识点。

上期链接Spring框架学习笔记,超详细!!(1)

5. GoF之工厂模式

5.1 设计模式

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

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

  • 创建型:解决对象创建问题

  • 单例模式

  • 工厂方法模式

  • 抽象工厂模式

  • 建造者模式

  • 原型模式

  • 结构型:一些类或对象组合在一起的经典结构

  • 代理模式

  • 装饰模式

  • 适配器模式

  • 组合模式

  • 享元模式

  • 外观模式

  • 桥接模式

  • 行为型:解决类或者对象之间的交互问题

  • 策略模式

  • 模板方法模式

  • 责任链模式

  • 观察者模式

  • 迭代子模式

  • 命令模式

  • 备忘录模式

  • 状态模式

  • 访问者模式

  • 中介者模式

  • 解释器模式

5.2 工厂模式的三种形态

工厂模式通常有三种形态:

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

  • 工厂方法模式(Factory Method):是23种设计模式之一

  • 抽象工厂模式(Abstract Factory):是23种设计模式之一

5.3 简单工厂模式

简单工厂模式的角色包括三个:

  • 抽象产品角色

  • 具体产品角色

  • 工厂类角色

代码示例:

  • 抽象产品角色

/**
 * 武器(抽象产品角色)
 **/
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 Dagger extends Weapon{
    @Override
    public void attack() {
        System.out.println("砍他丫的!");
    }
}
  • 工厂类角色

/**
 * 工厂类角色
 **/
public class WeaponFactory {
    /**
     * 静态方法
     * 根据不同的武器类型生产武器
     * @param weaponType 武器类型
     * @return 武器对象
     */
    public static Weapon get(String weaponType){
        if (weaponType == null || weaponType.trim().length() == 0) {
            return null;
        }
        Weapon weapon = null;
        if ("TANK".equals(weaponType)) {
            weapon = new Tank();
        } else if ("FIGHTER".equals(weaponType)) {
            weapon = new Fighter();
        } else if ("DAGGER".equals(weaponType)) {
            weapon = new Dagger();
        } else {
            throw new RuntimeException("不支持该武器!");
        }
        return weapon;
    }
}
  • 测试代码

public class Client {
    public static void main(String[] args) {
        Weapon weapon1 = WeaponFactory.get("TANK");
        weapon1.attack();

        Weapon weapon2 = WeaponFactory.get("FIGHTER");
        weapon2.attack();

        Weapon weapon3 = WeaponFactory.get("DAGGER");
        weapon3.attack();
    }
}
  • 结果:

Spring框架学习笔记,超详细!!(2)_第1张图片

简单工厂模式的优点:

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

简单工厂模式的缺点:

  • 工厂类集中了所有产品的创造逻辑,形成一个无所不知的全能类,有人把它叫做上帝类。显然工厂类非常关键,不能出问题,一旦出问题,整个系统瘫痪

  • 不符合OCP开闭原则,再进行系统扩展时,需要修改工厂类

5.4 工厂方法模式

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

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

  • 抽象工厂角色

  • 具体工厂角色

  • 抽象产品角色

  • 具体产品角色

代码:

  • 抽象产品角色

/**
 * 武器类(抽象产品角色)
 **/
    //所有武器都有攻击行为
    public abstract void attack();
}
  • 具体产品角色

/**
 * 具体产品角色
 **/
public class Gun extends Weapon{
    @Override
    public void attack() {
        System.out.println("开枪射击!");
    }
}

/**
 * 具体产品角色
 **/
public class Fighter extends Weapon{
    @Override
    public void attack() {
        System.out.println("战斗机发射核弹!");
    }
}
  • 抽象工厂角色

/**
 * 武器工厂接口(抽象工厂角色)
 **/
public interface WeaponFactory {
    Weapon get();
}
  • 具体工厂角色

/**
 * 具体工厂角色
 **/
public class GunFactory implements WeaponFactory{
    @Override
    public Weapon get() {
        return new Gun();
    }
}

/**
 * 具体工厂角色
 **/
public class FighterFactory implements WeaponFactory{
    @Override
    public Weapon get() {
        return new Fighter();
    }
}
  • 测试程序

/**
 * @author 动力节点
 **/
public class Client {
    public static void main(String[] args) {
        WeaponFactory factory = new GunFactory();
        Weapon weapon = factory.get();
        weapon.attack();

        WeaponFactory factory1 = new FighterFactory();
        Weapon weapon1 = factory1.get();
        weapon1.attack();
    }
}
  • 结果

Spring框架学习笔记,超详细!!(2)_第2张图片

工厂方法模式优点:

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

  • 扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以

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

工厂方法模式缺点:

  • 每次增加一个产品是,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加可系统的复杂度,同时也增加了系统具体类的依赖。

6. Bean的实例化方式

Spring为Bean提供了多种的实例化方式,通常包括四种方式。

  • 通过构造方法实例化

  • 通过简单工厂模式实例化

  • 通过factory-bean实例化

  • 通过FactoryBean<>接口实例化

6.1 通过构造方法实例化

  • BookDaoImpl实现类

public class BookDaoImpl implements BookDao {
    public BookDaoImpl() {
        System.out.println("bookDao constructor is running ....");
    }
    public void save() {
        System.out.println("book dao save ...");
    }
}
  • applicationContext.xml配置


  • 测试类

public class AppForInstanceBook {
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");

        BookDao bookDao = (BookDao) ctx.getBean("bookDao");

        bookDao.save();
    }
}

注意:无参构造方法如果不存在,将抛出异常BeanCreationException

6.2 通过简单工厂模式实例化

  • OrderDao接口和OrderDaoImpl实现类

public interface OrderDao {
    public void save();
}

public class OrderDaoImpl implements OrderDao {
    public void save() {
        System.out.println("order dao save ...");
    }
}
  • OrderDaoFactory工厂类

//静态工厂创建对象
public class OrderDaoFactory {
    public static OrderDao getOrderDao(){
        System.out.println("factory setup....");
        return new OrderDaoImpl();
    }
}
  • applicationContext.xml配置,factory-method 告诉Spring框架,调用哪个类获取Bean


Spring框架学习笔记,超详细!!(2)_第3张图片
  • 测试类

public class AppForInstanceOrder {
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");

        OrderDao orderDao = (OrderDao) ctx.getBean("orderDao");

        orderDao.save();
    }
}
  • 结果

6.3 通过factory-bean实例化

这种方式本质上是:通过工厂方法模式进行实例化

  • UserDao接口和UserDaoImpl实现类

public interface UserDao {
    public void save();
}
public class UserDaoImpl implements UserDao {
    public void save() {
        System.out.println("user dao save ...");
    }
}
  • UserDaoFactory工厂类

//实例工厂创建对象
public class UserDaoFactory {
    public UserDao getUserDao(){
        return new UserDaoImpl();
    }
}
  • applicationContext.xml配置,factory-method + factory-bean实现




Spring框架学习笔记,超详细!!(2)_第4张图片

factory-bean:告诉Spring调用哪个对象

factory-method:告诉Spring调用该对象的哪个方法

  • 测试类

public class AppForInstanceUser {
    public static void main(String[] args) {
        //        //创建实例工厂对象
        //        UserDaoFactory userDaoFactory = new UserDaoFactory();
        //        //通过实例工厂对象创建对象
        //        UserDao userDao = userDaoFactory.getUserDao();
        //        userDao.save();
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserDao userDao = (UserDao) ctx.getBean("userDao");
        userDao.save();
    }
}
  • 结果

6.4 通过FactoryBean<>接口实例化

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

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

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

FactoryBean在Spring中是一个接口。被称为“工厂Bean”。“工厂Bean”是一种特殊的Bean。所有的“工厂Bean”都是用来协助Spring框架来创建其他Bean对象的。

  • UserDao接口和UserDaoImpl实现类

public interface UserDao {
    public void save();
}
public class UserDaoImpl implements UserDao {
    public void save() {
        System.out.println("user dao save ...");
    }
}
  • 定义UserDaoFactoryBean实现FactoryBean

//FactoryBean创建对象
public class UserDaoFactoryBean implements FactoryBean {
    //代替原始实例工厂中创建对象的方法
    public UserDao getObject() throws Exception {
        return new UserDaoImpl();
    }

    public Class getObjectType() {
        return UserDao.class;
    }
    
    /*@Override
    public boolean isSingleton() {
        //true:单例   false:非单例
        return false;
    }*/
}
  • applicationContext.xml配置


  • 测试类

public class AppForInstanceUser {
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserDao userDao = (UserDao) ctx.getBean("userDao");
        userDao.save();
    }
}
  • 结果

6.5 BeanFactory和FactoryBean的区别

  • BeanFactory:Spring IoC容器的顶级对象,BeanFactory被翻译为“Bean工厂”,在Spring的IoC容器中,“Bean工厂”负责创建Bean对象。BeanFactory是工厂。

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

在Spring中,Bean可以分为两类:

  • 普通Bean

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

7. Bean的生命周期

7.1 什么是Bean的生命周期

Spring其实是一个管理Bean对象的工厂。它负责对象的创建,对象的销毁等。

所谓的生命周期就是:对象从创建开始到最终销毁的整个过程。

7.2 Bean的生命周期之5步

Bean生命周期可以粗略划分为五大步:

  • 实例化Bean(调用无参数构造方法)

  • Bean属性赋值(调用set方法)

  • 初始化Bean(调用Bean的init方法)

  • 使用Bean

  • 销毁Bean(调用Bean的destroy方法)

graph LR;
A(实例化Bean)-->B(Bean属性赋值)
B-->C(初始化Bean)
C-->D(使用Bean)
D-->E(销毁Bean)

编写测试程序

  • 定义一个Bean

public class User {
    private String name;

    public User() {
        System.out.println("1.实例化Bean");
    }

    public void setName(String name) {
        this.name = name;
        System.out.println("2.Bean属性赋值");
    }

    public void initBean(){
        System.out.println("3.初始化Bean");
    }

    public void destroyBean(){
        System.out.println("5.销毁Bean");
    }

}
  • 修改配置文件




    
    
        
    

  • 测试

public class BeanLifecycleTest {
    @Test
    public void testLifecycle(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        User userBean = applicationContext.getBean("userBean", User.class);
        System.out.println("4.使用Bean");
        
        // 只有正常关闭spring容器才会执行销毁方法
        ClassPathXmlApplicationContext context = (ClassPathXmlApplicationContext) applicationContext;
        context.close();
    }
}
  • 结果

Spring框架学习笔记,超详细!!(2)_第5张图片

注意:

  • 只有正常关闭的Spring容器Bean的销毁方法才会被调用

  • ClassPathXmlApplicationContext类才有close()方法

  • 配置文件中的init-method指定初始化方法。destroy-method指定销毁方法。

7.3 Bean的生命周期之7步

在以上的5步中,第3步是初始化Bean,如果想在初始化前和初始化后添加代码,可以加入“Bean后处理器”。

graph LR;
A(实例化Bean)-->B(Bean属性赋值)
B(Bean属性赋值)-->F(Bean后处理器before执行)
F-->C(初始化Bean)
C-->G(Bean后处理器after执行)
G-->D(使用Bean)
D-->E(销毁Bean)
  • 编写一个类实现BeanPostProcessor类,并且重写before和after方法:

public class LogBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("Bean后处理器的before方法执行,即将开始初始化");
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("Bean后处理器的after方法执行,已完成初始化");
        return bean;
    }
}
  • 修改配置文件




    
    
        
    
    
    
	

  • 结果

Spring框架学习笔记,超详细!!(2)_第6张图片

7.4 Bean的生命周期之10步

增加步骤:

  1. 在Bean后处理器before之前

  1. 在Bean后处理器before之后

  1. 在使用Bean之后,或者销毁之前

都是在检查Bean是否实现了某些特定的接口,如果实现了这些接口,则Spring容器会调用这个接口的方法

graph TD;
A(实例化Bean)-->B(Bean属性赋值)
B-->c(检查Bean是否实现了Aware接口,并设置相关依赖)
c-->D(Bean后处理器before执行)
D-->E(检查Bean是否实现了InitializingBean接口,并调用接口方法)
E-->F(初始化Bean)
F-->G(Bean后处理器after执行)
G-->H(使用Bean)
H-->I(检查Bean是否实现了DisposableBean接口,并调用接口方法)
I-->J(销毁Bean)

Aware相关的接口包括:BeanNameAware、BeanClassLoaderAware、BeanFactoryAware

  • 当Bean实现了BeanNameAware,Spring会将Bean的名字传递给Bean。

  • 当Bean实现了BeanClassLoaderAware,Spring会将加载该Bean的类加载器传递给Bean。

  • 当Bean实现了BeanFactoryAware,Spring会将Bean工厂对象传递给Bean。

示例:

  • 实现Aware相关接口,InitializingBean, DisposableBean接口

public class User implements BeanNameAware, BeanClassLoaderAware, BeanFactoryAware, InitializingBean, DisposableBean {
    private String name;

    public User() {
        System.out.println("1.实例化Bean");
    }

    public void setName(String name) {
        this.name = name;
        System.out.println("2.Bean属性赋值");
    }

    public void initBean(){
        System.out.println("6.初始化Bean");
    }

    public void destroyBean(){
        System.out.println("10.销毁Bean");
    }

    @Override
    public void setBeanClassLoader(ClassLoader classLoader) {
        System.out.println("3.类加载器:" + classLoader);
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        System.out.println("3.Bean工厂:" + beanFactory);
    }

    @Override
    public void setBeanName(String name) {
        System.out.println("3.bean名字:" + name);
    }

    @Override
    public void destroy() throws Exception {
        System.out.println("9.DisposableBean destroy");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("5.afterPropertiesSet执行");
    }
}
  • 编写一个类实现BeanPostProcessor类,并且重写before和after方法:

public class LogBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("4.Bean后处理器的before方法执行,即将开始初始化");
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("7.Bean后处理器的after方法执行,已完成初始化");
        return bean;
    }
}
  • 修改配置文件




    
    
        
    
    
    
	

  • 结果

Spring框架学习笔记,超详细!!(2)_第7张图片

注意:

  • InitializingBean的方法早于init-method的执行。

  • DisposableBean的方法早于destroy-method的执行。

7.5 Bean的作用域不同,管理方式不同

Spring 根据Bean的作用域来选择管理方式。

  • 对singleton作用域的Bean进行完整的生命周期管理,Spring 能够精确地知道该Bean何时被创建,何时初始化完成,以及何时被销毁;

  • 而对于 prototype 作用域的 Bean,Spring 只负责创建,当容器创建了 Bean 的实例后,Bean 的实例就交给客户端代码管理,Spring 容器将不再跟踪其生命周期。

7.6 自己new的对象如何让Spring管理

有些时候可能会遇到这样的需求,某个java对象是我们自己new的,然后我们希望这个对象被Spring容器管理,怎么实现?

DefaultListableBeanFactory可以实现

示例:

public class User {
}
public class RegisterBeanTest {

    @Test
    public void testBeanRegister(){
        // 自己new的对象
        User user = new User();
        System.out.println(user);

        // 创建 默认可列表BeanFactory 对象
        DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
        // 注册Bean
        factory.registerSingleton("userBean", user);
        // 从spring容器中获取bean
        User userBean = factory.getBean("userBean", User.class);
        System.out.println(userBean);
    }
}

结果:

Spring框架学习笔记,超详细!!(2)_第8张图片

你可能感兴趣的:(Spring框架学习笔记,学习,java,开发语言,spring,架构)