IoC和DI是Spring的基础,他们是从不同角度描述同一个概念。
1.IoC
IoC:Inversion of Control, 控制反转。Spring中对象创建和生命周期管理由IoC容器来实施,控制权在Ioc容器而不是应用程序。通过使用IoC容器来解耦,对象间没有直接联系。如下图所示。
对象A依赖对象B,在引入IoC容器前,A在实例化到某点的时候必须主动创建B或者使用已创建好的B,这些控制权都在应用程序本身。而引入IoC后,A和B之间失去直接联系,A需要B时IoC容器主动注入对象B到A所需要的地方。对象A获得B的过程,由主动变为被动,即把创建对象交给了ioC容器处理,控制权颠倒过来了,即所谓的控制反转。
2.DI
Di:Dependency Inject, 由IoC容器在运行期间动态的将某种依赖关系注入到对象中。
DI从应用程序角度描述,即应用程序依赖IoC容器创建并注入它所需要的外部资源。
IoC从容器角度描述,即容器控制应用程序,由容器反向向应用程序注入应用所需要的外部资源。
3.实现
Spring框架最重要、最基本的两个包org.springframework.beans.factory和org.springframework.context。
Spring IoC框架的主要组件有Beans、applicationContext.xml、BeanFactory接口及类似、ApplicatinContext接口及类。
4.Spring中Bean
一般在applicatinContext.xml中定义Bean。
5.Spring Bean装配方式
bean装配方式即Bean依赖注入的方式。Spring容器支持多种装配方式,主要有基于xml的装配、基于annotation注解的装配和基于autowire属性的自动装配等。
5.1 基于xml的装配
1) 设值装配Setter injection
Spring实例化bean时,spring先调用bean的默认构造方法来实例化bean对象,然后通过反射方式调用setter()方法注入属性值。因此设值注入需满足:
a. bean类必须提供默认的无参数构造方法;
b. bean必须为需要注入的属性提供setter()方法。
在xml中使用<bean id="idx" class="class name"><property name="pro1" value="val1"/></bean>
2) 构造注入Constructor injection
在xml中使用<bean>子元素<constructor-arg>来定义构造方法的参数,并使用value属性或子元素来设置参数值。
<bean id="" class=""><constructor-arg index="0" value="val1" /> </bean>
public class User
{
private String userName;
private String password;
private List list;
}
#cat applicationContext.xml
<beans>
<bean id="user1" class="com.ssm.assemble.User">
<constructor-arg index="0" value="zhangsan" />
<constructor-arg index="1" value="111" />
<constructor-arg index="2">
<list>
<value>"constructorValue1"</value>
<value>"constructorValue2"</value>
</list>
</constructor-arg>
</bean>
<bean id="user2" class="com.ssm..assemble.User">
<property name="UserName" value="lisi"></property>
<property name="password" value="222"></property>
<property name="list">
<list>
<value>"listval1"</value>
<value>"listbal2"</value>
</list>
</property>
</bean>
</beans>
5.2基于Annotation的装配
<context:component-scan base-package="com.xxx.yyy.* />
@Scope,在类上注解Bean的作用域
@Value基本类型属性注入,在属性上使用,指定要注入的值。
@Autowired和@Qualifier联合使用,为属性指定要装配的Bean id值(名称)。
@Resource在域属性上注解,可以按照name和type两种方式装配。
@Scope("prototype")
@Component("user")
public class User
{
@Value("1")
private String uid;
@Value("李白")
private String uname;
@Value("男")
private String gender;
@Vaue("18")
private int age;
@Autowired //默认按类型注入域属性值
private Company company;
@Autowired
@Qualifier("mycompany") //指定要匹配的Bean id; id为mycompany的Bean需存在
private Company company2;
@Resource //默认按照类型匹配进行Bean的注入
private Company company3;
@Resource(name="mycompany") //注入名为mycompany的bean
private Company company4;
}
5.3 基于antowire属性的自动装配
<bean id="userService" class="com.xxx.yyy.UserServiceImpl" autowire="byName" />
<bean id="userService" class="com.xxx.yyy.UserServiceImpl" autowire="byType" />
User类中含有Company类型的属性值company,以下使用自动装配为company自动装配,分别是按byName和byType两种方式。Bean中的company属性的注入不再直接引用company,而是改为自动注入。
当配置文件中被调用者的Bean的id值与调用者的Bean类的属性名相同时,可使用byName方式,让容器自动将被调用者的Bean注入调用者的Bean。容器通过调用者的Bean类的属性名与配置文件的被调用者的Bean的id进行比较而实现自动注入。
byType注入是指按类型进行匹配注入,即只要Spring容器中有跟域属性类型相同的Bean就自动注入。使用byType方式自动注入,要满足条件:配置文件中的被调用者Bean的class属性指定的类,要与调用者的Bean类的某域属性的类型同源,要么相同,要么有is-a关系(子类或是实现类)。但这样同源的被调用的Bean只能有一个。多于一个,容器就不知该匹配哪一个,从而导致报错。
public class User
{
private String uid;
private String uname;
private String gender;
private int age;
private Company company;
.....
}
<bean id="company"class="com.lifeng.entity.Company">
<property name="id"><value>2</value></property>
<property name="companyname"><value>砺锋软件公司</value></property>
<property name="address"><value>广州天河建中路</value></property>
</bean>