Spring知识点总结

306 阅读4分钟

spring配置文件及启动类

// Student类中的test方法
public void test() {
    System.out.println("你好,我是一名学生,我的名字是"+this.name+", 我的学号为"+this.id);
}
<?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">
​
    <!--配置JavaBean:指定id和要配置的Javabean-->
    <!--scope 默认singleton单例,可以设置为 prototype 标准模式,即每get一个bean就新生成一个实例-->
    <bean id="student" class="com.zwh.redis.entity.Student" scope="prototype">
        <!--配置JavaBean的属性-->
        <property name="name" value="AlexanderBai"/>
        <property name="id" value="110"/>
    </bean></beans>
public class Application {
    public static void main(String[] args) {
        //创建Spring上下文(加载spring-config.xml文件)
        ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("spring-config.xml");
        //获取Student的实例
        Student student = (Student) classPathXmlApplicationContext.getBean("student");
        //调用student的方法
        student.test();
    }
}

打印结果为:

image-20211009204235743.png

spring

  1. 解析配置文件
  2. 要有BeanDefiniton,然后把这些BeanDefinition的信息反射生成具体的实例化对象(BeanDefinitionReader接口)
  3. 在对象创建的前后会有一堆Processor的处理机制,对当前的Bean做一些增强的功能,可以添加很多扩展功能(BeanPostProcessor)

BeanFactory 和 FactoryBean 区别:

BeanFactory 是生成的是一个模板对象,FactoryBean可以按照自己的需求进行独特的控制,更有扩展性。

spring提供了什么扩展性?

  1. 在对象创建之前添加某些功能
  2. 在容器初始化之前添加某些功能
  3. 在不同的阶段发出不同的事件,完成一些功能
  4. 抽象出一堆的接口来完成扩展
  5. 面向接口编程

bean 生命周期

简单的说就是:bean的实例化–>bean的初始化–>bean的使用–>bean的销毁

具体的就是

  1. 实例化bean
  2. 属性注入
  3. 检查Aware相关接口并设置相关依赖(例如BeanNameAware接口,会调用它实现的setBeanName(String)方法,此处传递的就是Spring配置文件中Bean的id值)
  4. BeanPostProcessor的前置处理(postProcessBeforeInitialization)
  5. 如果在spring配置中配置了init-method属性,会自动调用该方法;
  6. BeanPostProcessor的后置处理(postProcessAfterInitialization)
    接下来bean就可以使用了
  7. 当Bean不再需要时,会经过清理阶段,如果Bean实现了DisposableBean这个接口,会调用其实现的destroy()方法,如果在spring配置中配置了destroy-method属性,会自动调用该方法。

如何解决循环依赖的问题

将实例化与初始化分开进行。

如果有两个类A和B,A依赖B,B依赖A。首先Spring尝试通过ApplicationContext.getBean()方法获取A对象的实例,由于Spring容器中还没有A对象实例,因而其会创建一个A对象。

然后发现其依赖了B对象,因而会尝试递归的通过ApplicationContext.getBean()方法获取B对象的实例。但是Spring容器中此时也没有B对象的实例,因而其还是会先创建一个B对象的实例。此时A对象和B对象都已经创建了,并且保存在Spring容器中了,只不过A对象的属性b和B对象的属性a都还没有设置进去。在前面Spring创建B对象之后,Spring发现B对象依赖了A对象,因而还是会尝试递归的调用ApplicationContext.getBean()方法获取A对象的实例。因为Spring中已经有一个A对象的实例,虽然只是半成品,但其也还是目标bean,因而会将该A对象的实例返回。实际上就是返回它的引用。此时,B对象的属性a就设置进去了,然后就是ApplicationContext.getBean()方法的返回,也就是将B对象的实例返回,此时就会将该实例设置到A对象的属性b中。这个时候,A对象的属性b和B对象的属性a都已经设置了目标对象的实例了。完成这些以后再对AB进行初始化,这样就解决了循环依赖的问题。

三级缓存有什么用

三级缓存的value类型是ObjectFactory,是一个函数式接口,存在的意义是保证在整个容器的运行过程中同名的bean对象只能有一个。

谈谈Spring IOC的理解,原理与实现

spring主要有两个点,一个是控制反转,一个是容器。

控制反转就是原来的对象是由使用者来进行控制,有了spring之后,可以把整个对象交给spring来帮我们进行管理,然后通过依赖注入的方式把对应的属性的值注入到具体的对象中。

容器是用来存储对象的,使用map结构来存储,在spring中一般存在三级缓存,singletonObjects存放完整的bean对象,整个bean的生命周期,从创建到使用到销毁的过程全部都是由容器来管理。

具体的细节我记不太清了,但是spring中的bean都是通过反射的方式生成的,同时其中包含了很多的扩展点。

如何指定Bean加载的顺序

使用@Order或者@DependsOn注解

多个相同类型的Bean如何注入

使用@Resource按 byName自动注入

Spring中的bean默认是单例

xml方式中,在bean中添加scope="prototype"即可
基于注解的方式添加@Scope("prototype")即可