2019-06-11
Ioc即Inverse of Control,中文为控制反转。
在Spring中,创建对象的工作不再由应用程序主动完成,而是由Spring容器负责创建,然后注入给应用程序,由Spring来管理应用程序中的所有对象及其依赖关系。所以控制反转是说创建对象的控制权进行转移,以前创建对象是由应用程序自己把控的,而现在这种权力转移交给了Spring容器。
应用程序在使用了Spring后,就无需再进行对象的创建工作了,而是通过Spring配置文件描述对象的创建方法、参数以及对象间的依赖关系。Spring会自动依据配置文件中对象之间的依赖关系运用Java的反射技术创建所需要的对象。
创建对象
在Spring核心文件中使用<bean>标签创建对象
<bean id="user" class="com.jevon.model.User">
<property name="id" value="001"></property>
<property name="name" value="张三"></property>
<property name="age" value="20"></property>
</bean>
获取对象
ApplicationContext container = new ClassPathXmlApplicationContext("applicationContext.xml");
User obj = container.getBean("user", User.class);
System.out.println(obj.getId());
System.out.println(obj.getName());
Spring Bean的作用域
Bean的作用域就是Bean实例的生存空间或有效范围。可通过配置文件中<bean>元素的scope属性配置。
作用域名称 | 功 能 描 述 |
---|---|
singleton | 单实例作用域,这是Spring容器默认的作用域。使用singleton作用域生成的是单实例,在整个Bean容器中仅保留一个实例对象供所有调用者共享引用。Spring容器负责跟踪Bean实例的状态,负责维护Bean实例的生命周期行为。单例模式对于那些无会话状态的Bean(如辅助工具类、DAO组件、业务逻辑组件等)是最理想的选择。 注意:Spring通过AOP与LocalThread功能解决了DAO中Connection的非线程安全问题。 |
prototype | 原型模式,这是多实例作用域,每次从容器中获取Bean时,都会创建一个新的实例以供调用者使用。prototype作用域非常适用于那些需要保持会话状态的Bean实例,但其内存开销太大。 有一点值得注意的就是,Spring不能对一个prototype Bean的整个生命周期负责,容器在初始化、装配好一个prototype实例后,将它交给客户端,随后就对该prototype实例不闻不问了。因此,客户端要负责prototype实例的生命周期管理。 |
request | 针对每次HTTP请求,Spring容器会根据Bean的定义创建一个全新的Bean实例, 且该Bean实例仅在当前HTTP request内有效,因此可以根据需要放心地更改所建实例的内部状态, 而其他请求中根据Bean定义创建的实例,将不会看到这些特定于某个请求的状态变化。 当处理请求结束,request作用域的Bean实例将被销毁。该作用域仅在基于web的Spring ApplicationContext情形下有效。 |
session | 针对某个HTTP Session,Spring容器会根据Bean定义创建一个全新的Bean实例,且该Bean实例仅在当前HTTP Session内有效。 与request作用域一样,我们可以根据需要放心地更改所创建实例的内部状态,而别的HTTP Session中根据Bean定义创建的实例, 将不会看到这些特定于某个HTTP Session的状态变化。 当HTTP Session最终被废弃的时候,在该HTTP Session作用域内的Bean实例也会被废弃掉。该作用域仅在基于Web的Spring ApplicationContext情形下有效。 |
global session | global session作用域类似于标准的HTTP Session作用域,不过它仅仅在基于portlet的Web应用中才有意义。portlet规范定义了全局Session的概念,它被所有构成某个portlet Web应用的各种不同的portlet所共享。在global session作用域中定义的Bean被限定于全局portlet Session的生命周期范围内。如果我们是在编写一个标准的基于Servlet的Web应用,并且定义了一个或多个具有global session作用域的Bean,系统会使用标准的HTTP Session作用域,并且不会引起任何错误。该作用域仅在基于Web的Spring ApplicationContext情形下有效。 |
当系统创建Spring容器时,默认会预初始化所有的singleton Bean。即容器初始化完成后,容器中所有的singleton Bean也实例化完成。这意味着系统前期初始化时将有较大的开销,但一旦初始化完成,程序后面获取singleton Bean实例时将拥有较好性能。
可以通过指定<bean>元素中的lazy-init属性来延迟初始化Bean,这样将会在第一次获取Bean的时候初始化Bean。
<bean id="" class="" lazy-init="true"/>
如果想对所有的Bean都延迟初始化,可以修改<beans>元素
<beans lazy-init="true">
ApplicationContext接口的常用方法
boolean containsBean(String name)
判断IoC容器是否包含id为name的Bean实例。
Class<?> getType(String name)
返回容器中指定Bean实例的类型。
Boolean isSingleton(String)
判断给定名称的Bean实例是否为单例(Singleton)模式。
T getBean(Class<T> requiredType)
获取IoC容器中属于requiredType类型的、唯一的Bean实例。
Object getBean(String name)
返回容器id为name的Bean实例。
T getBean(String name,Class requiredType)
返回容器中id为name,但在返回之前会进行类型检查。如果不能转换成requiredType类型,则会抛出异常。
Spring DI配置
DI即依赖注入,是Ioc思想的具体体现,表示对象之间的依赖关系由Spring管理,应用程序在运行时由Spring容器动态地将对象的依赖关系装配好,而不是由应用程序手动装配。
基于setter方法的依赖注入
<!-- 注册一个Country实例名称为country -->
<bean id="country" class="com.model.Country">
<property name="id" value="101"/>
<property name="name" value="中华人民共和国"/>
</bean>
<!-- 注册一个User实例名称为user -->
<bean id="user" class="com.model.User">
<property name="id" value="0001" />
<property name="name" value="张三" />
<property name="password" value="123456" />
<property name="country" ref="country" /><!-- 引用country实例 -->
</bean>
基于构造器的依赖注入
通过调用带参数的构造器实现。配置<constructor-arg>元素时可指定index属性,用于指定该构造参数将作为第几个构造参数值。如index="0"表明该构造参数值将作为第一个构造参数。可以通过type属性指定参数类型,以避免出现构造器重载的匹配问题。
<!-- 注册一个Country实例名称为country -->
<bean id="country" class="com.model.Country">
<property name="id" value="101"/>
<property name="name" value="中华人民共和国"/>
</bean>
<!-- 注册一个User实例名称为user -->
<bean id="user" class="com.model.User">
<constructor-arg value="0001" type="String" />
<constructor-arg value="张三" type="String" />
<constructor-arg value="123456" type="String" />
<constructor-arg ref="country" type="com.model.Country" />
</bean>
集合属性注入
可以使用<list>、<set>、<map>、<array>标签分别用来设置类型为List、Set、Map、数组的属性值。
主要参数:
- value:指定集合元素值是基本数据类型值或字符串类型值
- ref:指定集合元素值是容器中另一个Bean实例
- bean:指定集合元素值是一个嵌套Bean
public class User {
private String id;// ID号
private String name; // 用户名
private String password;// 密码
private List<String> friends; // 好友列表
private Set<Account> accounts;// 账户列表
}
<bean id="account" class="com.model.Account" scope="prototype">
<property name="id" value="0001" />
<property name="password" value="111111" />
<property name="balance" value="1000" />
</bean>
<!-- 注册一个User实例名称为user -->
<bean id="user" class="com.model.User">
<property name="id" value="1000" />
<property name="name" value="张三" />
<property name="password" value="123456" />
<property name="friends">
<list>
<value>"李四"</value>
<value>"王五"</value>
<value>"赵六"</value>
</list>
</property>
<property name="accounts">
<set>
<ref bean="account" />
<bean class="com.model.Account">
<property name="id" value="0002" />
<property name="password" value="222222" />
<property name="balance" value="2000"/>
</bean>
</set>
</property>
</bean>
分层开发依赖注入
<!-- 注册UserDaoImpl实例userDao -->
<bean id="userDao" class="com.dao.impl.UserDaoImpl" />
<!-- 注册UserServiceImpl实例userService -->
<bean id="userService" class="com.service.impl.UserServiceImpl">
<!--调用set方法,将UserDaoImpl实例userDao注入给UserServiceImpl实例的userDao属性-->
<property name="userDao" ref="userDao"/>
</bean>
<!-- 注册LoginController实例名称为loginController -->
<bean id="loginController" class="com.controller.LoginController">
<!--调用set方法,将UserServiceImpl实例userService注入给LoginController实例的userService属性-->
<property name="userService" ref="userService" />
</bean>
自动装配
Spring IoC容器可以使用自动装配(autowire)管理Bean之间的依赖关系,以减少配置量。
自动装配方式可以通过<bean>元素的autowire属性指定, 取值如下:
- no:不使用自动装配,默认值。需要通过ref属性进行依赖关系的指定。在较大的部署环境中不鼓励改变这个配置,显式配置能够得到清晰的依赖关系。
- byName:根据属性名自动装配。查找id值与属性名完全一致的Bean,并将其与属性自动装配。
- byType:如果容器中存在一个与指定属性类型相同的Bean,那么将与该属性自动装配。如果存在多个该类型的Bean,那么将会抛出异常。
方法一:给bean元素设置autowire属性
<bean id="" class="" autowire="byName" />
方法二:设置beans全局自动装配
<beans default-autowire="byName">
基于注解的Ioc实现
Spring提供了完全基于注解配置Bean、装配Bean的功能,用于替换原来基于XML的配置方法,减少配置量。
首先要在配置文件中启用注解扫描:
<context:component-scan base-package="com"/>
<context:component-scan />
标签负责扫描哪些类有注解,如果扫描到有注解的类,则将其注册为bean,并将bean的名字设置为该类的类名,但首字母小写。base-package为需要扫描的包路径(含所有子包)。
常用Spring注解:
- @Controller:用于标注控制器组件
- @Service:用于标注业务层组件
- @Repository:用于标注数据访问组件
- @Component:用于对比较中立的类进行注解。与前三个注解等效。
- @Resource:用于依赖关系装配。默认按名称装配。名称可以通过@Resource的name属性指定。如果没有指定name属性,则支持自动装配。
- @Autowired:自动装配
网友评论