重点知识学习(5)--[spring部分]

首先回顾一下当时学习spring时的知识,
spring就是一个轻量级的,非侵入式,IOC和AOP,的一站式开源框架.

这里的非侵入式说的就是业务代码不会侵入到框架代码.
IOC:控制反转,将生成对象的权利反转给spring框架,这里当时还涉及到DI依赖注入.

AOP:面向切面编程,将一些与业务代码无关的代码从公共代码中抽取出来,通过代理对象调用,达到在不修改源代码的基础上扩展新的功能.

简易搭建流程回顾:
创建spring配置文件: spring.xml文件
在spring.xml文件中配置,比如将类注入容器(使用bean标签);
然后spring框架读取xml文件,解析xml,
通过工厂模式+反射机制 创建对象 + 代理模式;
在需要使用对象时,从spring容器注入对象即可.

案例

package com.xiaozhi.advanced.day05spring.pojo;

/**
 * @author by 信计1801 李智青 学号:1809064012
 * 宠物类
 */

public class Pet {
    public Pet() {
        System.out.println("Pet类的无参构造方法");
    }

    private String name;
    private Integer age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }
}

配置文件spring.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
        https://www.springframework.org/schema/beans/spring-beans.xsd">
    <!--将pet类注入spring容器-->
    <bean id="pet" class="com.xiaozhi.advanced.day05spring.pojo.Pet">
        <property name="name" value="小白"/>
        <property name="age" value="22"/>
    </bean>
</beans>

测试调用;

public class Demo {
    public static void main(String[] args) {
        //读取配置文件;
        ApplicationContext app = new ClassPathXmlApplicationContext("spring.xml");
        Pet pet = app.getBean("pet", Pet.class);
        System.out.println(pet.hashCode());
        System.out.println(pet.getName());
        System.out.println(pet.getAge());
    }
}
Pet类的无参构造方法
909295153
小白
22

1.BeanFactory 和 ApplicationContext

在 spring 容器中,BeanFactory 接口是 IOC 容器要实现的最基础的接口,定义了管理 bean 的最基本的方法.
比如之前就使用过getbean()方法获取到容器中的对象.

在这里插入图片描述

ApplicationContext也间接继承了BeanFactory


例如:new Pet() ,创建Pet对象,由spring框架创建的对象就是bean;

区别

  • BeanFactory是基础接口,面向spring,不支持AOP,Web…扩展功能; ApplicationContext是面向于应用程序,增强了一些扩展功能.

  • BeanFactory 在使用对象时才会创建, ApplicationContext 适用于Web应用程序,在服务器启动时创建.

  • BeanFactory 是 Spring 框架的基础设施,面向 Spring 本身,是 Spring 中比较原始的 Factory,它不支持 AOP、Web 等 Spring 插件. 而 ApplicationContext 不仅包含了 BeanFactory 的所有功能,还支持 Spring的各种插件,还以一种面向框架的方式工作以及对上下文进行分层和实现继承。

  • BeanFactory:需要等到获取某个 bean 的时候才会创建该 bean,即延迟初始化. ApplicationContext:在启动 Spring 容器时就会创建所有的 bean(Web 应用中推荐)


2. SpringBean的生命周期

大致分为5个阶段:

  • 实例化 Instantiation.

  • 属性赋值 Populate.

  • 初始化 Initialization.

  • 将 bean 对象放入到容器中,进行使用.

  • 销毁 Destruction.

  • 1.instantiate bean 对象实例化------ 创建原始对象,底层使用反射机制,;

  • 2.populate properties 属性赋值 -------- 属性注入;

  • 第三步:初始化时,下面这块就是 实现了什么接口,则重写对应的方法,执行使用;

    • 3.1 如果 Bean 实现 BeanNameAware 执行 setBeanName,
    • 3.2 如果 Bean 实现 BeanFactoryAware 或者 ApplicationContextAware 设置工厂 setBeanFactory 或者上下文对象 setApplicationContext 对象. 初始化.
    • 3.3 如果存在类实现 BeanPostProcessor(AOP) ,执行postProcessBeforeInitialization;
    • 3.4 如果 Bean 实现InitializingBean 执行 afterPropertiesSet,可以配置自己的初始化方法init-method="指定的方法"
    • 3.5 如果存在类实现 BeanPostProcessor(AOP),执行postProcessAfterInitialization;
  • 4.完整的 bean 创建好,将 bean 对象放入到容器中,使用;

  • 5.销毁 如果 Bean 实现 DisposableBean 执行 destroy;可以配置自己的销毁方法destroy-method="指定的销毁时执行方法";

在这里插入图片描述

在这里插入图片描述


3.spring的线程安全问题

可以回顾一下servlet是线程安全的吗?servlet的线程不安全;
spring框架的话,本身就不是线程安全的,具体的话还是看scope的参数设置;

  • singleton:单例,默认作用域。
  • prototype:原型,每次创建一个新对象。
  • request:请求,每次 Http 请求创建一个新对象,

这里分析spring框架的线程安全问题,就要从单例与原型 Bean 进行考虑。

原型 Bean:
对于原型 Bean,每次创建一个新对象,也就是线程之间并不存在 Bean 共享,线程安全。

单例 Bean:
对于单例 Bean,所有线程都共享一个单例实例 Bean,因此是存在资源的竞争,线程不安全.

Bean 又分为有状态和无状态

  • 有状态 就是有数据存储功能(例如使用成员变量);线程不安全;
  • 无状态 就是不会保存数据,线程安全.

如果单例 Bean,是一个无状态 Bean,也就是线程中的操作不会对 Bean 的成员执行查询以外的操作,那么这个单例 Bean 是线程安全的。比如 Spring mvc 的 Controller、Service、Dao 等,这些 Bean 大多是无状态的,只关注于方法本身。

但是如果 Bean 是有状态的 那就需要开发人员自己来进行线程安全的保证,最简单的办法就是改变 bean 的作用域 把 "singleton"改为’‘protopyte’ 这样每次请求Bean 就相当于是 new Bean() 这样就可以保证线程的安全了。controller、service 和 dao 层本身并不是线程安全的,只是如果只是调用里面的方法,而且多线程调用一个实例的方法,会在内存中复制变量,这是自己的线程的工作内存,
是安全的。


4.Bean的循环依赖

在Java中的循环依赖是比较容易理解的;
例如在A类中使用B类作属性,进行使用;
在B类中使用A类作为属性,进行使用.

在这里插入图片描述

看这个图,就想到之前学习线程的时候,那个死锁问题.

那么,若不是在spring框架中使用这个场景,那么循环依赖其实就不是个问题;
直接调用即可;

A a = new A();
B b = new B();

a.b = b;
b.a = a;

现在这个问题是放在spring框架中进行考虑的:
在 Spring 中,一个对象并不是简单 new 出来,而是经过一系列的Bean 的生命周期,这个循环依赖问题也随之而来.

  • spring框架在创建对象过程中,会检验注入的属性,需要直接查找依赖的属性对象.
  • 其实就是 A对象 创建时–>发现需要 B----就去创建B对象—>又发现其中需要 A对象,从而产生了循环。

在这里插入图片描述

那么,该如何解决呢?

可利用spring的三级缓存进行解决;(实际可看做是三个map容器),也就是不同的对象进行存储;
(1)singletonObjects 一级缓存,创建对象后,用于保存实例化、注入、初始化完成的 bean 实例
(2)earlySingletonObjects 二级缓存,用于保存实例化完成的 bean 实例;
(3)singletonFactories 三级缓存,用于保存 bean 创建工厂,便于之后扩展创建代理对象。

在这里插入图片描述

A,B 循环依赖,先初始化 A,先暴露一个半成品 A,再去初始化依赖的 B,初始化 B 时如果发现 B 依赖 A,也就是循环依赖,就注入半成品 A,之后初始化完毕 B,再回到 A 的初始化过程时就解决了循环依赖,在这里只需要一个 Map能缓存半成品 A 就行了,也就是二级缓存就够了,但是这个二级缓存存的是 Bean对象,如果这个对象存在代理,那应该注入的是代理,而不是 Bean,此时二级缓存无法及缓存 Bean,又缓存代理,因此三级缓存做到了缓存 工厂 ,也就是生成代理,这我的理解:总结起来:二级缓存就能解决缓存依赖,三级缓存解决的是代理。


5.Servlet的过滤器与spring的拦截器区别

在这里插入图片描述

在这里插入图片描述

可以这么看;实际上servlet的过滤器是基于tomcat服务器;客户端发来的请求首先回来到过滤器,然后才能根据路径找到相关的servlet;

而spring的拦截器是框架内部封装的;客户端发出请求后,到达总servlet(请求分发器);这时就会分配到达拦截器,然后在适配,找到对应的控制层controller;

在这里插入图片描述

  • 实现原理不同
    过滤器 基于函数回调的
    拦截器 基于 Java 的反射机制(动态代理)实现
  • 使用范围不同
    过滤器 实现的是 javax.servlet.Filter 接口,而这个接口是在 Servlet规范中定义的,也就是说过滤器 Filter 的使用要依赖于 Tomcat 等容器,导致它只能在 web 程序中使用。
  • 拦截的请求范围不同
    过滤器几乎可以对所有进入容器的请求起作用,
    拦截器只会对 Controller 中请求或访问 static 目录下的资源请求起作用。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小智RE0

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值