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();
}
}
打印结果为:
spring
- 解析配置文件
- 要有BeanDefiniton,然后把这些BeanDefinition的信息反射生成具体的实例化对象(BeanDefinitionReader接口)
- 在对象创建的前后会有一堆Processor的处理机制,对当前的Bean做一些增强的功能,可以添加很多扩展功能(BeanPostProcessor)
BeanFactory 和 FactoryBean 区别:
BeanFactory 是生成的是一个模板对象,FactoryBean可以按照自己的需求进行独特的控制,更有扩展性。
spring提供了什么扩展性?
- 在对象创建之前添加某些功能
- 在容器初始化之前添加某些功能
- 在不同的阶段发出不同的事件,完成一些功能
- 抽象出一堆的接口来完成扩展
- 面向接口编程
bean 生命周期
简单的说就是:bean的实例化–>bean的初始化–>bean的使用–>bean的销毁
具体的就是
- 实例化bean
- 属性注入
- 检查Aware相关接口并设置相关依赖(例如BeanNameAware接口,会调用它实现的setBeanName(String)方法,此处传递的就是Spring配置文件中Bean的id值)
- BeanPostProcessor的前置处理(postProcessBeforeInitialization)
- 如果在spring配置中配置了init-method属性,会自动调用该方法;
- BeanPostProcessor的后置处理(postProcessAfterInitialization)
接下来bean就可以使用了 - 当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")即可