1.依赖注入
在之前我们编写好的java类在创建对象的时候,都是new+构造方法来完成对象的创建,此时对象创建和维护的权利都控制在开发人员手中。
IOC[控制反转]--就是将对象的创建和维护权利从开发人员手中转移到Spring容器。就是通过Spring容器来创建和维护对象。
依赖注入(Dependency Injection,DI)和控制反转含义相同,它们是从两个角度描述的同一个概念。
当某个 Java 实例需要另一个 Java 实例时,传统的方法是由调用者创建被调用者的实例(例如,使用 new 关键字获得被调用者实例),而使用 Spring 框架后,被调用者的实例不再由调用者创建,而是由 Spring 容器创建,这称为控制反转。
Spring 容器在创建被调用者的实例时,会自动将调用者需要的对象实例注入给调用者,这样,调用者通过 Spring 容器获得被调用者实例,这称为依赖注入。
当某个 Java 实例【Student】需要另一个 Java 实例【Person】,Spring 容器在创建被调用者的实例【Person】时会自动将调用者需要的对象实例【Person】注入给调用者【Student】,这样调用者【Student】通过 Spring 容器获得被调用者【Person】实例,这称为依赖注入。
依赖注入主要有两种实现方式,分别是属性 setter 注入和构造方法注入。具体介绍如下。
1.1 setter注入
<?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">
<bean id="per" class="com.weiwei.springdemo2.Person"/>
<bean id="stu" class="com.weiwei.springdemo2.Student">
<property name="person" ref="per"/>
</bean>
</beans>
<!--property : Set方法注入-->
<!--name : 成员变量【依赖对象】名称-->
<!--ref:引入/引用Spring容器创建依赖对象-->
也就是说,person对象注入给student对象中,spring会自动调用setter方法。
1.2 构造方法注入
即通过调用者类的构造方法,通过参数把被调用者的对象传进去。
<!--constructor-arg:构造方法注入-->
<!--name:构造方法参数名称-->
<!--ref:引入/引用Spring容器创建依赖对象-->
如果参数有好几个,可以通过type和index指定
<!--type:构造方法参数类型-->
<!--index:构造方法参数位置,从0开始-->
2.Spring实例化对象的三种方法
即通过Spring配置文件创建java类对象的方式。
2.1 构造器实例化
构造器实例化,是指Spring容器通过Bean对应的类中默认的构造函数实例化Bean。
就是我们上面一直在使用的方法,配置文件中<bean>
<bean id="per" class="com.weiwei.springdemo2.Person"/>
2.2 静态工厂方法实例化
需要提供一个静态工厂方法创建 Bean 的实例。就是创建一个类,类里面有一个静态方法,这个方法里面new另一个类的对象,再在配置文件里进行配置。
2.3 实例工厂方法实例化
需要提供一个实例工厂方法创建 Bean 的实例。就是创建一个类,类里面有一个实例方法,这个方法里面new另一个类的对象,再在配置文件里进行配置。
factory-bean------工厂对象 factory-method-----工厂方法
【注意】:和静态工厂不同,实例工厂需要先创建实例工厂的对象,静态不需要,因为静态可以直接类名调用。
3. Spring中Bean的作用域
Spring 容器在初始化一个 Bean 的实例时,同时会指定该实例的有效范围。
Spring为 Bean 定义了五种作用域:
1)singleton
单例模式,使用 singleton 定义的 Bean 在 Spring 容器中只有一个实例,这也是 Bean 默认的作用域。
输出:是同一个对象
2)prototype
原型模式,每次通过 Spring 容器获取 prototype 定义的 Bean 时,容器都将创建一个新的 Bean 实例。
输出:不是同一个对象
3)request
在一次 HTTP 请求中,容器会返回该 Bean 的同一个实例。而对不同的 HTTP 请求,会返回不同的实例,该作用域仅在当前 HTTP Request 内有效。
4)session
在一次 HTTP Session 中,容器会返回该 Bean 的同一个实例。而对不同的 HTTP 请求,会返回不同的实例,该作用域仅在当前 HTTP Session 内有效。
5)global Session
在一个全局的 HTTP Session 中,容器会返回该 Bean 的同一个实例。该作用域仅在使用 portlet context 时有效。
在上述五种作用域中,singleton 和 prototype 是最常用的两种,其他的3种需要在javaweb程序中测试,目前先不用关注。
4. Spring Bean的生命周期
Spring 容器可以管理 singleton 作用域 Bean 的生命周期,在此作用域下,Spring 能够精确地知道该 Bean 何时被创建,何时初始化完成,以及何时被销毁。
而对于 prototype 作用域的 Bean,Spring 只负责创建,当容器创建了 Bean 的实例后,Bean 的实例就交给客户端代码管理,Spring 容器将不再跟踪其生命周期。
了解 Spring 生命周期的意义就在于,可以利用 Bean 在其存活期间的指定时刻完成一些相关操作。这种时刻可能有很多,但一般情况下,会在 Bean 被初始化后和被销毁前执行一些相关操作。
在 Spring 中,Bean 的生命周期是一个很复杂的执行过程,我们可以利用 Spring 提供的方法定制 Bean 的创建过程。当一个 Bean 被加载到 Spring 容器时,它就具有了生命,而 Spring 容器在保证一个 Bean 能够使用之前,会进行很多工作。
Bean 生命周期的整个执行过程描述如下。
1)根据配置情况调用 Bean 构造方法或工厂方法实例化 Bean。
2)利用依赖注入完成 Bean 中所有属性值的配置注入。
3)如果 Bean 实现了 BeanNameAware 接口,则 Spring 调用 Bean 的 setBeanName() 方法传入当前 Bean 的 id 值。
4)如果 Bean 实现了 BeanFactoryAware 接口,则 Spring 调用 setBeanFactory() 方法传入当前工厂实例的引用。
5)如果 Bean 实现了 ApplicationContextAware 接口,则 Spring 调用 setApplicationContext() 方法传入当前 ApplicationContext 实例的引用。
6)如果 BeanPostProcessor 和 Bean 关联,则 Spring 将调用该接口的预初始化方法 postProcessBeforeInitialzation() 对 Bean 进行加工操作,此处非常重要,Spring 的 AOP 就是利用它实现的。
7)如果 Bean 实现了 InitializingBean 接口,则 Spring 将调用 afterPropertiesSet() 方法。
8)如果在配置文件中通过 init-method 属性指定了初始化方法,则调用该初始化方法。
9)如果 BeanPostProcessor 和 Bean 关联,则 Spring 将调用该接口的初始化方法 postProcessAfterInitialization()。此时,Bean 已经可以被应用系统使用了。
10)如果在 <bean> 中指定了该 Bean 的作用范围为 scope="singleton",则将该 Bean 放入 Spring IoC 的缓存池中,将触发 Spring 对该 Bean 的生命周期管理;如果在 <bean> 中指定了该 Bean 的作用范围为 scope="prototype",则将该 Bean 交给调用者,调用者管理该 Bean 的生命周期,Spring 不再管理该 Bean。
11)如果 Bean 实现了 DisposableBean 接口,则 Spring 会调用 destory() 方法将 Spring 中的 Bean 销毁;如果在配置文件中通过 destory-method 属性指定了 Bean 的销毁方法,则 Spring 将调用该方法对 Bean 进行销毁。
4.1 定制初始化方法和定制销毁方法
默认情况下SpringBean的初始化是由InitializingBean 接口中的afterPropertiesSet()方法完成,那么如果我们想要在bean对象初始化的时候添加额外的处理操作,就需要InitializingBean 接口中的afterPropertiesSet() 方法,这样做比较麻烦。这是Spring给出另一个解决方法,在配置文件中配置bean的init-method 属性定制初始化方法,已达到在对象初始化的时候添加额外的处理操作目的。
默认情况下SpringBean的销毁是由DisposableBean接口中的destory()方法完成,那么如果我们想要在bean对象销毁之前添加额外的处理操作,就需要DisposableBean接口中的destory() 方法,这样做比较麻烦。这是Spring给出另一个解决方法,在配置文件中配置bean的destory-method属性定制销毁方法,已达到在bean对象销毁之前添加额外的处理操作目的。
Spring容器创建bean对象的时候会调用无参数的构造方法,此时需要注意类中有有参数构造方法时,将无参数构造方法重载出来。
输出:Student无参数构造方法
Student的实例方法
Spring容器创建bean对象的时候会调用无参数的构造方法,如果我们需要在创建对象的时候添加额为的处理操作,只需要将额为的处理操作写在构造方法中。
输出:
Student无参数构造方法
初始化Student对象
Student的实例方法
销毁Student对象
当spring配置文件中的scope属性是prototype时,Spring 只负责创建,当容器创建了 Bean 的实例后,Bean 的实例就交给客户端代码管理,Spring 容器将不再跟踪其生命周期
<bean id="stu" class="com.weiwei.springdemo2.demo5.Student"
init-method="studentinit" destroy-method="studentdestory" scope="prototype"/>
被定制的销毁方法【destoryPerson()】不会执行