文章目录
1. IOC和DI
1.1 概念
- ioc就是控制反转,在Spring中,对象的属性是由对象自己创建的,就是正向流程;如果属性不是对象创建的,而是由Spring来自动进行装配,就是控制反转。这里的DI也就是依赖注入,就是实现控制反转的方式。正向流程导致了对象于对象之间的高耦合,IOC可以解决对象耦合的问题,有利于功能的复用,能够使程序的结构变得灵活。
- 依赖注入和控制反转的定义相同,它们是从两个角度描述用一个概念。当某个java实例需要另一个java实例的时候,传统的方法是由调用者创建创建被调用者的实例,而使用Spring框架后,被调用者的实例不再由调用者创建,而是由Spring容器创建,这就是控制反转。
1.2 依赖注入的实现方式
- 属性setter注入:指IOC容器使用setter方法注入被依赖的实例。通过调用无参构造器或无参static工厂方法实例化bean后,调用该bean的setter方法,即可实现基于setter的DI。
- 构造方法注入:指IOC容器使用构造方法注入被依赖的实例,基于构造器的DI通过调用带参数的构造方法实现,每个参数代表一个依赖。
2. context上下文和bean
2.1 概念
- Spring进行IOC实现时使用的有两个概念:context上下文和bean。
所有被Spring管理的、由Spring创建的、用于依赖注入的对象,就叫做一个bean。
Spring创建并完成依赖注入后,所有的bean统一放在一个叫做context的上下文中进行管理。
2.2 bean的配置及常用属性
Spring 容器可以被看作一个大工厂,而 Spring 容器中的 Bean 就相当于该工厂的产品。如果希望这个大工厂能够生产和管理 Bean,这时则需要告诉容器需要哪些 Bean,以及需要以何种方式将这些 Bean 装配到一起。
-
Spring配置文件支持两种不同的格式,分别是XML文件格式和Properties文件格式。通常情况下,Spring会以XML文件格式作为Spring的配置文件,这种配置方式通过XML文件注册并管理Bean之间的依赖关系。
(1)XML格式配置文件的根元素是,该元素包含了多个子元素,每一个子元素定义了一个Bean,并描述了该Bean如何被装配到Spring容器中。- 定义Bean的实例代码如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd">
<!-- 使用id属性定义person1,其对应的实现类为com.mengma.person1 -->
<bean id="person1" class="com.mengma.damain.Person1" />
<!--使用name属性定义person2,其对应的实现类为com.mengma.domain.Person2-->
<bean name="Person2" class="com.mengma.domain.Person2"/>
</beans>
- 上述的代码中,分别使用 id 和 name 属性定义了两个 Bean,并使用 class 元素指定了 Bean 对应的实现类。
(2)Porperties类是键和值均为字符串的可以永久存储到文件中的key-value组合。
(3)元素中包含了很多的属性,常用的属性有:
2.3 Spring实例化Bean的三种方法
- 在面向对象的程序中,要想调用某个类的成员方法,就需要先实例化该类的对象。在Spring中,实例化Bean有三种方式,分别是构造器实例化、静态工厂方式实例化和实例工厂方式实例化。
(1)构造器实例化:构造器实例化是指Spring容器通过Bean对应的类中默认的构造函数实例化Bean。
(2)静态工厂实例化:此种方式需要提供一个静态工厂方法创建Bean的实例。
(3)实例工厂方式实例化:在这种方式中,工厂类不在使用静态方法创建Bean的实例,而是直接在成员方法中创建Bean的实例。
2.4 Spring中Bean的作用域
-
共有5种,其中重点是singleton和prototype这两种最常用的作用域。
(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 request内有效。
(5)global Session:在一次全局的http Session中,容器会返回该Bean的同一个实例,该作用域仅在当前http request内有效。 -
我们重点说说singleton和prototype两种作用域
(1)singleton作用域:当一个Bean的作用域为singleton时。Spring容器只会存在一个共享的Bean实例,并且所有对Bean的请求,只要id与该Bean定义相匹配,就只会返回Bean的同一个实例。
通常情况下,这种单例模式对于无会话状态的Bean(如DAO层,Service层)来说,是最好的选择。
在 Spring 配置文件中,可以使用 元素的 scope 属性,将 Bean 的作用域定义成 singleton,其配置方式如下所示:
<bean id="person" class="com.mengma.scope.Person" scope="singleton"/>
(2)prototype作用域
使用 prototype 作用域的 Bean 会在每次请求该 Bean 时都会创建一个新的 Bean 实例。因此对需要保持会话状态的 Bean(如 Struts2 的 Action 类)应该使用 prototype 作用域。
在 Spring 配置文件中,要将 Bean 定义为 prototype 作用域,只需将 元素的 scope 属性值定义成 prototype,其示例代码如下所示:
<bean id="person" class="com.mengma.scope.Person" scope="prototype"/>
2.5 Spring Bean的生命周期
- Spring容器可以管理singleton作用域的生命周期,在此作用域下,Spring能够精确的直到该Bean何时被创建,何时初始化完成,以及何时被销毁。
- 而对于prototype作用域的Bean,Spring只负责创建,当容器创建了Bean的实例后,Bean的实例就交给客户端代码管理,Spring容器将不再跟踪器生命周期。每次客户端请求 prototype 作用域的 Bean 时,Spring 容器都会创建一个新的实例,并且不会管那些被配置成 prototype 作用域的 Bean 的生命周期。
- 当一个Bean被加载到Spring容器中时,它就具有了生命,而Spring容器在保证一个Bean能够工作之前,会进行很多的工作,其在Spring容器中的生命周期如图:
- Bean生命周期的执行过程如下:
(1)根据配置情况调用Bean构造方法或工厂方法实例化Bean。
(2)利用依赖注入完成Bean中所有属性值的配置注入。
(3)如果Bean实现了BeanNameAware接口,则Spring调用Bean的setBeanName()方法传入当前Bean的id值。
(4)如果Bean实现了BeanFactorAware接口,则Spring调用setBeanFactor()方法传入当前工厂实例的引用。
(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 的作用范围为 scope=“singleton”,则将该 Bean 放入 Spring IoC 的缓存池中,将触发 Spring 对该 Bean 的生命周期管理;如果在 中指定了该 Bean 的作用范围为 scope=“prototype”,则将该 Bean 交给调用者,调用者管理该 Bean 的生命周期,Spring 不再管理该 Bean。
(11)如果Bean 实现了DisposableBean接口,则Spring会调用destory()方法将Spring中的Bean销毁;如果在配置文件咱通过destory-method属性指定了Bean的销毁方法,则Spring将调用该方法对Bean进行销毁。
2.6 Spring对于Bean的装配
- Bean的装配可以理解为依赖关系注入,Bean的装配方式也就是Bean的依赖注入方式。
2.6.1 基于XML装配Bean的方式
- 基于XML装配Bean的方式,通常有两种实现方式,即设值注入和构造注入。
- 在Spring实例化Bean的过程中,首先调用默认的构造方法实例化Bean对象,然后通过Java的反射机制调用setXXX()方法进行属性的注入。因此,设值注入要求一个Bean的对应类必须满足下面的要求:
(1)必须提供一个默认的无参构造方法
(2)必须为需要注入的属性提供对应的setter方法 - 使用设值注入时,在Spring配置文件中,需要使用 元素的子元素 元素为每个属性注入值。
- 而使用构造注入时,在配置文件中,主要使用< constructor-arg >标签定义构造方法的参数,可以使用其 value 属性(或子元素)设置该参数的值。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd">
<!-- 使用设值注入方式装配Person实例 -->
<bean id="person1" class="com.mengma.assembly.Person">
<property name="name" value="zhangsan" />
<property name="age" value="20" />
</bean>
<!-- 使用构造方法装配Person实例 -->
<bean id="person2" class="com.mengma.assembly.Person">
<constructor-arg index="0" value="lisi" />
<constructor-arg index="1" value="21" />
</bean>
</beans>
2.6.2 基于Annotation装配Bean
- 常用的注解有很多,大体如下:
(1)@Component --> 中文意为组件,音标为 /kəmˈpəʊnənt/
可以使用此注解描述Spring中的Bean,但它是一个泛化的概念,仅仅表示一个组件(Bean),并且可以作用在任何层次,使用时只需将该注解标注在相应的类上即可。
(2)@Repository -->中文意为仓库,音标为 /rɪˈpɒzətri/
用于将数据访问层(DAO层)的类的标识为Spring的Bean,其功能与@Component相同。
(3)@Service
通常作用在业务层(Service 层),用于将业务层的类标识为 Spring 中的 Bean,其功能与 @Component 相同。
(4)@Controller
通常作用在控制层(如 Struts2 的 Action),用于将控制层的类标识为 Spring 中的 Bean,其功能与 @Component 相同。
(5)Autowired -->中文意为自动装配
用于堆Bean的属性变量、属性的Set方法及构造函数进行标注,配合对应的注解处理器完成Bean的自动装配工作,默认按照Bean的类型进行装配。
(6)Resource
其作用和Autowired一样,其区别在于@Autowired默认按照Bean类型装配,而@Resource默认按照Bean实例名称进行装配。
@Resource中两个重要属性:name和type。
String将name属性解析为Bean实例名称,type属性解析为Bean实例类型。如果指定name属性,则按实例名称进行装配;如果指定type属性,则按Bean类型进行装配。
如果都不指定,则先按Bean实例名称进行装配,如果不能匹配,则按照Bean类型进行装配;如果都无法匹配,则抛出NoSuchBeanDefinitionException异常。
(7)Qualifier -->中文意为修饰语 音标为 /ˈkwɒlɪfaɪə®/
与@Autowired注解配合使用,会将默认的按Bean类型装配修改为按Bean的实例名称进行装配,Bean的实例名称由@Qualifier注解的参数指定。
2.6.3 Spring自动装配Bean
- 除了使用XML和Annotation的方式装配Bean以外,还有一种常见的装配方式:自动装配。自动装配就是指Spring容器可以自动装配(Autowire)相互协作的Bean之间的关联关系,将一个Bean注入其他Bean的Property中。
要使用自动装配,就需要配置元素的autowire属性,autowire属性有5个值,如下图。