Spring
Spring ——是一个轻量级的控制反转和面向切面的容器
Spring 的作用
- 在 JavaEE 开发中,支持 JavaBean 开发方式,使应用面向接口开发,充分支持面向对象的设计方法
- Spring通过IoC容器实现对象耦合关系的管理,并实现依赖反转,将对象之间的依赖关系交给IoC容器,实现解耦
什么是 IOC ?
- IOC 是控制反转
- 在传统开发中,我们在对象内部用 new 创建依赖对象,是主动控制对象
- IOC是有一个专门的容器创建依赖对象,由 Spring 控制和管理这些对象,对象的创建由程序自己控制
- Spring 容器在初始化时先读取配置文件,根据配置文件创建对象(getBean()方法)存入容器,程序使用时再从 IOC 容器中取出需要的对象。
- IOC 与 DI 的关系:控制反转是通过 XML 文件或注解去生成并获取特定对象的方式。在 Spring 中实现控制反转的是 IOC 容器,他的实现方法是依赖注入 DI。
什么是 AOP ?
- AOP,一般称为面向切面,作为面向对象的一种补充
- 用于把与业务无关的,但对多个对象产生影响的公共行为和逻辑,抽取并封装为一个可重用的模块
- 减少系统中的重复代码,降低了模块间的耦合度,提高系统的可维护性
- AOP实现的关键在于代理模式,主要使用动态代理
- Spring AOP 使用的动态代理,就是每次运行时在内存中临时为方法生成一个AOP对象,这个AOP对象包含了目标对象的全部方法,并且在特定的切点做了增强处理,并回调原对象的方法
BeanFactory和ApplicationContext有什么区别
- BeanFactory 和 ApplicationContext 是 Spring 的两大核心接口,都可以当做 Spring 的容器
- BeanFactory是Spring里面最底层的接口,是IoC的核心,定义了IoC的基本功能,包含了各种Bean的定义、加载、实例化,依赖注入和生命周期管理。
- ApplicationContext 接口是 BeanFactory 的子类,除了提供BeanFactory所具有的功能外,还提供了更完整的功能:
- 继承MessageSource,因此支持国际化。
- 资源文件访问,如URL和文件(ResourceLoader)。
- 同时加载多个配置文件 ,使得每一个上下文都专注于一个特定的层次,比如应用的web层。
- 提供在监听器中注册bean的事件
- 具体区别:
- BeanFactroy采用的是延迟加载形式来注入Bean的,只有在使用到某个Bean时(调用getBean()),才对该Bean进行加载实例化。
- ApplicationContext,它是在容器启动时,一次性创建了所有的Bean。这样,在容器启动时,我们就可以发现Spring中存在的配置错误,这样有利于检查所依赖属性是否注入。
- ApplicationContext启动后预载入所有的单实例Bean,所以在运行的时候速度比较快,因为它们已经创建好了。相对于BeanFactory,ApplicationContext 唯一的不足是占用内存空间,当应用程序配置Bean较多时,程序启动较慢。
Spring 的使用
- 加入依赖
- 创建类:接口、实现类、没有接口的类
- 创建 Spring 的配置文件,使用声明对象
- 通过 ApplicationContext 接口和他的实现类 ClassPathXmlApplicationContext 的 getBean()方法使用容器中的对象
Spring Bean 的生命周期
- 总体:实例化(Instantiation)–属性赋值(Populate)–初始化(Initialization)–销毁(Destruction)
- 实例化Bean:
- 对于BeanFactory容器,当客户向容器请求一个尚未初始化的bean时,或初始化bean的时候需要注入另一个尚未初始化的依赖时,容器就会调用createBean进行实例化。
- 对于ApplicationContext容器,当容器启动结束后,通过获取BeanDefinition对象中的信息,实例化所有的bean。
- 设置对象属性(依赖注入):实例化后的对象被封装在BeanWrapper对象中,然后 Spring 根据 BeanDefinition 中的信息 以及 通过BeanWrapper提供的设置属性的接口完成属性设置与依赖注入。
- 处理Aware接口:Spring 会检测该对象是否实现了xxxAware接口,通过Aware类型的接口,可以让我们拿到Spring容器的一些资源:
- 如果这个Bean实现了BeanNameAware接口,会调用它实现的setBeanName(String beanId)方法,传入Bean的名字;
- 如果这个Bean实现了BeanClassLoaderAware接口,调用setBeanClassLoader()方法,传入ClassLoader对象的实例。
- 如果这个Bean实现了BeanFactoryAware接口,会调用它实现的setBeanFactory()方法,传递的是Spring工厂自身。
- 如果这个Bean实现了ApplicationContextAware接口,会调用setApplicationContext(ApplicationContext)方法,传入Spring上下文;
- BeanPostProcessor前置处理:如果想对Bean进行一些自定义的前置处理,那么可以让Bean实现了BeanPostProcessor接口,那将会调用postProcessBeforeInitialization(Object obj, String s)方法。
- InitializingBean:如果Bean实现了InitializingBean接口,执行afeterPropertiesSet()方法。
- init-method:如果Bean在Spring配置文件中配置了 init-method 属性,则会自动调用其配置的初始化方法。
- BeanPostProcessor后置处理:如果这个Bean实现了BeanPostProcessor接口,将会调用postProcessAfterInitialization(Object obj, String s)方法;由于这个方法是在Bean初始化结束时调用的,所以可以被应用于内存或缓存技术;这时 Bean 就被正确创建了
- DisposableBean:当Bean不再需要时,会经过清理阶段,如果Bean实现了DisposableBean这个接口,会调用其实现的destroy()方法;
- destroy-method:最后,如果这个Bean的Spring配置中配置了destroy-method属性,会自动调用其配置的销毁方法。
Spring 框架中的 Bean 如何保证线程安全?
- 对于prototype作用域的Bean,每次都创建一个新对象,也就是线程之间不存在Bean共享,因此不会有线程安全问题。
- 对于singleton作用域的Bean,所有的线程都共享一个单例实例的Bean,因此是存在线程安全问题的。
- 如果单例Bean是一个无状态Bean,也就是线程中的操作不会对Bean的成员执行查询以外的操作,那么这个单例Bean是线程安全的。比如Controller类、Service类和Dao等,这些Bean大多是无状态的,只关注于方法本身。
- 对于有状态的bean(比如Model和View),就需要自行保证线程安全,最容易的解决办法就是将有状态的bean的作用域由“singleton”改为“prototype”。也可以采用ThreadLocal解决线程安全问题,为每个线程提供一个独立的变量副本,不同线程只操作自己线程的副本变量。
Spring 中 bean 的作用域
- singleton:默认作用域,单例bean,每个容器中只有一个bean的实例。
- prototype:为每一个bean请求创建一个实例。
- request:为每一个request请求创建一个实例,在请求完成以后,bean会失效并被垃圾回收器回收。
- session:与request范围类似,同一个session会话共享一个实例,不同会话使用不同的实例。
- global-session:全局作用域,所有会话共享一个实例。如果想要声明让所有会话共享的存储变量的话,那么这全局变量需要存储在global-session中。
Spring 常用注解
- @Autowired 与 @Resource 比较:
- @Autowired 与 @Resource 都考研用来装配 bean
- @Autowired 默认情况下必须要求依赖对象不能为 null
- @Resource 默认按照名称装配对象,可以通过 name 属性指定装配的类
- @Autowired 先执行 byType 方式注入对象,@Resource 先执行byName 方式注入对象
(持续更新中,建议收藏)