spring的bean的生命周期整个过程

  • Bean 容器找到配置文件中 Spring Bean 的定义。
  • Bean 容器利用 Java Reflection API 创建一个Bean的实例。(相当于程序中的new Xx())
  • 如果涉及到一些属性值 利用 set()方法设置一些属性值。

  • 如果 Bean 实现了 BeanNameAware 接口,调用 setBeanName()方法,传入Bean ID。(实现BeanNameAware主要是为了通过Bean的引用来获得Bean的ID

  • 如果 Bean 实现了 BeanClassLoaderAware 接口,调用 setBeanClassLoader()方法,传入 ClassLoader对象的实例。
  • 如果Bean实现了BeanFactoryAware接口,Spring将调用setBeanDactory (BeanFactory bf)方法,并把BeanFactory容器实例作为参数传入。(实现BeanFactoryAware 主要是为了获取Spring容器,如Bean通过Spring容器发布事件等
  • 如果Bean实现了ApplicationContextAwaer接口,Spring容器将调用setApplicationContext(ApplicationContext ctx)方法,把应用上下文作为参数传入(作用与BeanFactory都是为了获取Spring容器,不同是Spring容器在调用setApplicationContext方法时把它自己作为setApplicationContext 的参数传入,而Spring容器在调用setBeanDactory前需要程序员自己指定(注入)setBeanDactory里的参数BeanFactory )
  • 与上面的类似,如果实现了其他 *.Aware接口,就调用相应的方法。

  • 如果有和 加载这个 Bean 的 Spring 容器 相关的 BeanPostProcessor 对象,执行postProcessBeforeInitialization() 方法(作用是在Bean实例创建成功后对进行增强处理,如对Bean进行修改,增加某个功能

  • 如果Bean实现了InitializingBean接口,执行afterPropertiesSet()方法。
  • 如果 Bean 在配置文件中的定义包含 init-method 属性,执行指定的方法。
  • 如果有和加载这个 Bean的 Spring 容器相关的 BeanPostProcessor 对象,执行postProcessAfterInitialization()方法(作用与前面postProcessBeforeInitialization 方法类似,只是时机不同

  • 经过以上的工作后,Bean将一直驻留在应用上下文中给应用使用,直到应用上下文被销毁

  • 当要销毁 Bean 时,如果 Bean 实现了 DisposableBean 接口,执行 destroy() 方法。
  • 当要销毁 Bean 时,如果 Bean 在配置文件中的定义包含 destroy-method 属性,执行指定的方法。

image.png
与之比较类似的中文版本:
image.png

IOC控制反转

IoC(Inverse of Control)是一种设计思想将原本在程序中创建对象的控制权,交由Spring框架管理

  • IoC 在其他语言中也有应用,并非 Spring 特有。
  • IoC 容器是 Spring 用来实现 IoC 的载体, IoC 容器实际上就是个Map,Map 中存放各种对象。
  1. 将对象之间的相互依赖关系交给 IoC 容器来管理,并由 IoC 容器完成对象的注入。这样可以很大程度上简化应用的开发,把应用从复杂的依赖关系中解放出来。
  2. IoC 容器就像是一个工厂一样,当我们需要创建一个对象的时候,只需要配置好配置文件/注解即可,完全不用考虑对象是如何被创建出来的。

    在实际项目中,一个 Service 类可能有几百甚至上千个类作为它的底层,假如我们需要实例化这个 Service,你可能要每次都要搞清这个 Service 所有底层类的构造函数,这可能会把人逼疯。如果利用 IoC 的话,你只需要配置好,然后在需要的地方引用就行了,这大大增加了项目的可维护性且降低了开发难度。

控制反转就是把创建和管理 bean 的过程转移给了第三方。而这个第三方,就是 Spring IoC Container,对于 IoC 来说,最重要的就是容器。

  • 容器负责创建、配置和管理 bean,也就是它管理着 bean 的生命,控制着 bean 的依赖注入。Bean 其实就是包装了的 Object,无论是控制反转还是依赖注入,它们的主语都是 object —— bean 就是由第三方包装好了的 object。

    什么是bean? 在 Spring 中,构成应用程序 主干 并由 Spring IoC容器 管理的 对象 称为 bean 。 bean是一个由Spring IoC容器实例化、组装和管理的对象。

    1. bean是对象,一个或者多个不限定
    2. bean由Spring中一个叫IoC的东西管理
    3. 我们的应用程序由一个个bean构成

DI依赖注入的三种方法

  1. set注入:通过setXxx()赋值

赋值,默认使用的是 set方法()。依赖注入底层是通过反射实现的。

  1. 构造器注入:通过构造方法赋值

需要注意:如果 的顺序 与构造方法参数的顺序不一致,则需要通过type或者index或name指定。

  1. p命名空间注入
  • 引入p命名空间:xmlns:p=”http://www.springframework.org/schema/p
  • 简单类型(8个基本+String):p:属性名=”属性值”
  • 引用类型(除了String外):p:属性名-ref=”引用的id”

注意:无论是String还是Int/short/long,在赋值时都是 value=”值” ,因此建议 此种情况 需要配合 name\type进行区分

在ioc中定义bean的前提:该bean的类 必须提供了 无参构造

开发spring至少需要使用的jar(5个+1个)
开发spring至少需要使用的jar(5个+1个):
spring-aop.jar 开发AOP特性时需要的JAR
spring-beans.jar 处理Bean的jar
spring-context.jar 处理spring上下文的jar
spring-core.jar spring核心jar
spring-expression.jar spring表达式
三方提供的日志jar commons-logging.jar 日志包

要取spring ioc容器内的bean需要预定义:
ApplicationContext conext = new ClassPathXmlApplicationContext(“applicationContext.xml”) ;

  1. 何为控制,控制的是什么?

答:是 bean 的创建、管理的权利,控制 bean 的整个生命周期。

  1. 何为反转,反转了什么?

答:把这个权利交给了 Spring 容器,而不是自己去控制,就是反转。由之前的自己主动创建对象,变成现在被动接收别人给我们的对象的过程,这就是反转。

  1. 何为依赖DI,依赖什么?

程序运行需要依赖外部的资源,提供程序内对象的所需要的数据、资源。

  1. 何为注入,注入什么?

配置文件把资源从外部注入到内部,容器加载了外部的文件、对象、数据,然后把这些资源注入给程序内的对象,维护了程序内外对象之间的依赖关系。

所以说,控制反转是通过依赖注入实现的。

  • IoC 是设计思想,DI 是具体的实现方式;
  • IoC 是理论,DI 是实践;

从而实现对象之间的解藕。
当然,IoC 也可以通过其他的方式来实现,而 DI 只是 Spring 的选择。

IoC 和 DI 也并非 Spring 框架提出来的,Spring 只是应用了这个设计思想和理念到自己的框架里去。

  • 对象在容器中默认是单例的。
  • 每次启动容器时,就已经创建好容器中的所有对象了。(当然,这在 scope = “prototype” 的时候不适用,只是 singleton 的时候。)

多说一句,其实最好应该一直保留一个无参的 constructor,因为这里 bean 对象的创建是通过反射,clazz.newInstance() 默认是调用无参的 constructor。不过,现在已经被弃用掉了,换用了这个:clazz.getDeclaredConstructor().newInstance()。

Spring 如何设计容器的呢?

使用 ApplicationContext,它是 BeanFactory 的子类。

  1. BeanFactory是Spring里面最低层的接口,提供了最简单的容器的功能,只提供了实例化对象和拿对象的功能。BeanFactory 简单粗暴,可以理解为 HashMap:
  • Key - bean name
  • Value - bean object

但它一般只有 get, put 两个功能,所以称之为“低级容器”。

  1. ApplicationContext 多了很多功能,因为它继承多个接口,可称为“高级容器。
  • 继承BeanFactory接口,它是Spring的一各更高级的容器,提供了更多的有用的功能;

1) 国际化(MessageSource)
2) 访问资源,如URL和文件(ResourceLoader)
3) 载入多个(有继承关系)上下文 ,使得每一个上下文都专注于一个特定的层次,比如应用的web层
4) 消息发送、响应机制(ApplicationEventPublisher)
5) AOP(拦截器)

ApplicationContext 里有两个具体的实现子类,用来读取配置配件的:

  • ClassPathXmlApplicationContext - 从 class path 中加载配置文件,更常用一些;
  • FileSystemXmlApplicationContext - 从本地文件中加载配置文件,不是很常用,如果再到 Linux 环境中,还要改路径,不是很方便。

    ClassPathXmlApplicationContext 不是直接继承ApplicationContext 的,它有很多层的依赖关系,每层的子类都是对父类的补充实现。而再往上找,发现最上层的 class 回到了 BeanFactory,所以它非常重要。

注意:Spring 中还有个 FactoryBean,两者并没有特别的关系,只是名字比较接近。

BeanFactory是个Factory,也就是IOC容器或对象工厂,FactoryBean是个Bean。在Spring,所有的Bean都由BeanFactory(也就是IOC容器)来进行管理的。但对FactoryBean而言,这个Bean不是简单的Bean,而是一个能生产或者修饰对象生成的工厂Bean,它的实现与设计模式中的工厂模式和修饰器模式类似。

  1. BeanFactory
  • 在Spring中,BeanFactory是IOC容器的核心接口,它的职责包括:实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。BeanFactory只是个接口,并不是IOC容器的具体实现,但Spring容器给出了很多种实现,如 DefaultListableBeanFactory、XmlBeanFactory、ApplicationContext。
  • BeanFactory和ApplicationContext就是spring框架的两个IOC容器,现在一般使用ApplicationnContext,其不但包含了BeanFactory的作用,同时还进行更多的扩展。
  1. FactoryBean
  • 在某些情况下,实例化Bean过程比较复杂,如果按传统的方式,则需要在中提供大量的配置信息。Spring为此提供了一个org.springframework.bean.factory.FactoryBean的工厂类接口,用户可以通过实现该接口定制实例化Bean的逻辑,隐藏实例化一些复杂Bean的细节,给上层应用带来了便利。
  • 不同于普通Bean的是:它是实现了FactoryBean接口的Bean,根据该Bean的ID从BeanFactory中获取的实际上是FactoryBean的getObject()返回的对象,而不是FactoryBean本身,如果要获取FactoryBean对象,请在id前面加一个&符号来获取。


  1. 两者装载bean的区别
  • BeanFactory:BeanFactory启动时不会去实例化Bean,只有从容器中拿Bean的时候才会去实例化;
  • ApplicationContext:ApplicationContext启动时就把所有的Bean实例化了。可以配置lazy-init=true来让Bean延迟实例化;
  1. 我们该用BeanFactory还是ApplicationContent

1)延迟实例化的优点:(BeanFactory

  • 应用启动的时候占用资源很少;对资源要求较高的应用,比较有优势;

    2)不延迟实例化的优点: (ApplicationContext

  • 所有的Bean在启动的时候都加载,系统运行的速度快;

  • 在启动时所有的Bean都加载了,我们就能在系统启动时,尽早的发现系统中的配置问题
  • 建议web应用,在启动时就把所有的Bean都加载了。(把费时的操作放到系统启动中完成)

AOP

  1. 什么是 AOP

AOP (Aspect Orient Programming)面向切面编程:一种编程思想,是面向对象编程(OOP)的一种补充。面向对象编程将程序抽象成各个层次的对象,而面向切面编程是将程序抽象成各个切面。

  1. 为什么需要 AOP

想象下面的场景,开发中在多个模块间有某段重复的代码,我们通常是怎么处理的?

  • 显然,没有人会靠“CV”吧。在传统的面向过程编程中,我们也会将这段代码,抽象成一个方法,然后在需要的地方分别调用这个方法,这样当这段代码需要修改时,我们只需改变这个方法。
  • 然而需求总是变化,有一天,新增了一个需求,需要再多出做修改,我们需要再抽象出一个方法,然后再在需要的地方分别调用这个方法,又或者我们不需要这个方法了,我们还得删除掉每一处调用该方法的地方(传统方法的缺点)。实际上涉及到多个地方具有相同的修改的问题我们都可以通过 AOP 来解决。


  1. AOP 实现分类

AOP 要达到的效果是,保证开发者不修改源代码的前提下,去为系统中的业务组件添加某种通用功能。AOP 的本质是由 AOP 框架修改业务组件的多个方法的源代码 —— AOP 其实就是代理模式的典型应用。

按照 AOP 框架修改源代码的时机,可以将其分为两类:

  • 静态 AOP 实现, AOP 框架在编译阶段对程序源代码进行修改,生成了静态的 AOP 代理类(生成的 *.class 文件已经被改掉了,需要使用特定的编译器),比如 AspectJ。
  • 动态 AOP 实现, AOP 框架在运行阶段对程序源代码进行修改,动态生成代理对象(在内存中以 JDK 动态代理,或 CGlib 动态地生成 AOP 代理类),如 SpringAOP。


  1. AOP 术语

AOP 领域中的特性术语:

  • 通知(Advice): AOP 框架中的增强处理。通知描述了切面何时执行以及如何执行增强处理。
  • 连接点(join point): 连接点表示应用执行过程中能够插入切面的一个点,这个点可以是方法的调用、异常的抛出。在 Spring AOP 中,连接点总是方法的调用。
  • 切点(PointCut): 可以插入增强处理的连接点。
  • 切面(Aspect): 切面是通知和切点的结合。
  • 引入(Introduction):引入允许我们向现有的类添加新的方法或者属性。
  • 织入(Weaving): 将增强处理添加到目标对象中,并创建一个被增强的对象,这个过程就是织入。