配置形式:基于XML文件的形式、基于注解的形式;
配置方式:通过全类名(反射)、工厂方法(静态工厂方法或实例工厂方法)或FactoryBean的方式进行配置。
1. IoC容器
在Spring IoC容器读取Bean配置来创建Bean实例前,必须对其进行实例化;只有在IoC容器实例化后,可以从中获取Bean实例并使用。
Spring提供了BeanFactory和ApplicationContext两种类型的IOC容器实现;其中, BeanFactory接口是IoC容器的基本实现,面向Spring框架本身;而ApplicationContext是BeanFactory的子接口,提供了更多的高级特性,面向Spring框架的开发者,故常使用ApplicationContext来代表IoC容器。
Spring的IoC容器使用示例如下:
/**
* 基于Spring框架实现
* ApplicationContext接口代表IoC容器:在初始化上下文时即实例化所有单例的Bean
* -- ClassPathXmlApplicationContext:实现类,其从类路径下加载配置文件;
* -- FileSystemXmlApplicationContext:实现类,其从文件系统中加载配置文件;
* -- ConfigurableApplicationContext:子接口,增加refresh()和close()方法,使ApplicationContext具有启动、刷新和关闭上下文的能力。
*/
// 1. 创建Spring的IoC容器
ApplicationContext ctx = new ClassPathXmlApplicationContext("helloBean.xml");
// 2. 从IoC容器中获取Bean:getBean(String idStr)方法
HelloWorld helloWorld = (HelloWorld) ctx.getBean("qiaobc");
2. 依赖注入的方式
Spring支持属性注入、构造器注入和工厂方法注入(不推荐)共三种依赖注入的方式。
2.1 属性注入
<!--
配置bean
id:唯一标识容器中的bean;可指定多个名字,中间用逗号隔开;
class:bean的全类名,采用反射的方式在IoC容器中创建Bean,即要求Bean必须有无参的构造器;
-->
<bean id="qiaobc" class="com.qiaobc.spring.beans.HelloWorld">
<!-- 属性注入:通过setter方法注入Bean的属性值或依赖的对象 -->
<property name="name" value="Android"></property>
</bean>
2.2 构造器注入
<!-- 通过构造方法来配置Bean的属性:可以指定参数的位置和类型,以区分重载的构造器 -->
<!-- 1). 按索引匹配入参:可用index实现位置区分 -->
<bean id="car" class="com.qiaobc.spring.beans.Car">
<!-- public Car(String brand, String corp, double price){} -->
<constructor-arg value="BMW"></constructor-arg>
<constructor-arg value="WuHan"></constructor-arg>
<constructor-arg value="600000"></constructor-arg>
</bean>
<!-- 2). 按类型匹配入参 -->
<bean id="car2" class="com.qiaobc.spring.beans.Car">
<!-- public Car(String brand, String corp, int maxSpeed){} -->
<constructor-arg value="BMW2" type="java.lang.String"></constructor-arg>
<constructor-arg type="java.lang.String">
<!-- 字面值(可以用字符串表示的值)可以通过value属性或value子元素进行注入 -->
<!-- 若字面值包含特殊字符,可以使用 <![CDATA[]]>把字面值包裹起来 -->
<value><![CDATA[>WuHan]]></value>
</constructor-arg>
<constructor-arg value="240.00" type="int"></constructor-arg>
</bean>
3. 详解属性注入
3.1 引用其他的Bean
组成应用程序的Bean经常需要相互协作以完成应用程序的功能,在Bean配置文件中通过<ref>元素或ref 属性指定对Bean的引用即可实现互相访问。
bean配置文件核心代码如下所示:
<!-- 引用其他的bean -->
<bean id="person" class="com.qiaobc.spring.beans.Person">
<property name="name" value="qiaobc"></property>
<property name="age" value="23"></property>
<!-- 可以使用property的ref属性建立bean之间的引用关系 -->
<property name="car" ref="car2"></property>
<!-- 为级联属性赋值:属性需要先初始化后才可以为级联属性赋值,与Struts不同 -->
<property name="car.maxSpeed" value="250"></property>
</bean>
3.2 内部Bean
bean配置文件核心代码如下所示:
<!-- 内部bean:只能在内部使用,而不能被外部引用 -->
<bean id="person1" class="com.qiaobc.spring.beans.Person">
<property name="name" value="qiaobc"></property>
<property name="age" value="23"></property>
<property name="car">
<bean class="com.qiaobc.spring.beans.Car">
<constructor-arg value="BMW"></constructor-arg>
<!-- 配置null值: <null/> -->
<constructor-arg><null/></constructor-arg>
<constructor-arg value="260" type="int"></constructor-arg>
</bean>
</property>
</bean>
3.3 集合属性
bean配置文件核心代码如下所示:
<!-- 1). 配置List属性:Person类中声明private List<Car> cars; -->
<bean id="person2" class="com.qiaobc.spring.beans.collections.Person">
<property name="name" value="qiaobei"></property>
<property name="age" value="23"></property>
<property name="cars">
<!-- 使用list节点为List类型的属性赋值 -->
<list>
<ref bean="car" />
<ref bean="car2" />
<ref bean="car3" />
</list>
</property>
</bean>
<!-- 2). 配置Set属性需要使用set节点类配置,而数组元素仍采用list节点来配置 -->
<!-- 3). 配置Map属性:Person类中声明private Map<String, Car> carsMap; -->
<bean id="person3" class="com.qiaobc.spring.beans.collections.Person">
<property name="name" value="chenchen"></property>
<property name="age" value="23"></property>
<property name="carsMap">
<!-- 使用Map节点和entry子节点为Map类型的属性赋值 -->
<map>
<entry key="AA" value-ref="car"></entry>
<entry key="BB" value-ref="car2"></entry>
<entry key="CC" value-ref="car3"></entry>
</map>
</property>
</bean>
<!-- 4). 配置Properties属性:Person类中声明private Properties properties; -->
<bean id="person4" class="com.qiaobc.spring.beans.collections.Person">
<property name="properties">
<!-- 使用props和prop节点为Properties属性赋值 -->
<props>
<prop key="name">root</prop>
<prop key="password">1234</prop>
</props>
</property>
</bean>
<!-- 5). 使用util schema里集合标签定义独立的集合Bean,以供其他Bean引用 -->
<util:map id="carsMap">
<entry key="AAA" value-ref="car"></entry>
<entry key="BBB" value-ref="car2"></entry>
<entry key="CCC" value-ref="car3"></entry>
</util:map>
<!-- 6). 简化配置:使用p命名空间为bean的属性赋值,需要先导入p命名空间 -->
<bean id="person5" class="com.qiaobc.spring.beans.collections.Person"
p:name="chengege" p:age="25" p:carsMap-ref="carsMap"></bean>
4. 自动装配
bean配置文件核心代码如下所示:
<bean id="address" class="com.qiaobc.spring.beans.autowire.Address"
p:city="Wuhan" p:street="Luoshi"></bean>
<bean id="car" class="com.qiaobc.spring.beans.autowire.Car"
p:brand="BMW" p:price="600000"></bean>
<!-- 手动装配 -->
<bean id="person" class="com.qiaobc.spring.beans.autowire.Person"
p:name="qiaobc" p:address-ref="address" p:car-ref="car"></bean>
<!--
自动装配:使用autowire属性指定自动装配的方式
byName 根据当前bean的属性名称和目标bean的名称进行自动装配;需要精确匹配
byType 根据当前bean的属性类型和目标bean的类型进行自动装配;若IoC容器中有多个相同类型的bean则抛出异常
-->
<bean id="person2" class="com.qiaobc.spring.beans.autowire.Person"
p:name="qiaobc" autowire="byType"></bean>
5. bean之间的关系
bean配置文件核心代码如下所示:
<!-- 抽象bean:其abstract属性为true,抽象bean不能被IoC容器实例化 -->
<!-- 若某个bean的class属性未指定,则其必须是抽象bean -->
<bean id="address1" p:city="Wuhan" p:street="Luoshi" abstract="true"></bean>
<!-- bean之间的继承关系:使用bean的parent来实现 -->
<bean id="address2" class="com.qiaobc.spring.beans.autowire.Address"
parent="address1" p:street="Wuluo"></bean>
<bean id="car" class="com.qiaobc.spring.beans.autowire.Car"
p:brand="bmw" p:price="600000"></bean>
<!-- bean之间的依赖关系:要求在配置Person时,必须有一个关联的Car,即依赖于Car -->
<bean id="person" class="com.qiaobc.spring.beans.autowire.Person"
p:name="qiaobei" p:address-ref="address2" depends-on="car"></bean>
6. bean的作用域
bean配置文件核心代码如下所示:
<!--
bean的作用域:使用bean的scope属性来配置bean的作用域,默认值为singleton
singleton:默认值,IoC容器初始化时即创建bean实例,仅创建一次,即单例的;
prototype:原型的,IoC容器初始化时不创建bean实例,而在每次请求时均创建新的bean实例返回;
-->
<bean id="car" class="com.qiaobc.spring.beans.scope.Car" scope="singleton">
<property name="brand" value="BMW"></property>
<property name="price" value="600000"></property>
</bean>
7. 使用外部属性文件
src/db.properties文件内容如下所示:
user=root
password=root
driverClass=com.mysql.jdbc.Driver
jdbcUrl=jdbc:mysql:///hibernate
bean配置文件核心代码如下所示:
<!-- 在属性文件中配置c3p0数据源,推荐使用 -->
<!-- 在Spring2.5以后使用context:property-placeholder元素导入属性文件,并进行配置即可 -->
<context:property-placeholder location="classpath:db.properties"/>
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="user" value="${user}"></property>
<property name="password" value="${password}"></property>
<property name="driverClass" value="${driverClass}"></property>
<property name="jdbcUrl" value="${jdbcUrl}"></property>
</bean>
<!-- 在Bean配置文件中:配置c3p0数据源,不建议如此配置 -->
<!--
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="user" value="root"></property>
<property name="password" value="root"></property>
<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
<property name="jdbcUrl" value="jdbc:mysql:///hibernate"></property>
</bean>
-->
8. SpEL
bean配置文件核心代码如下所示:
<bean id="address" class="com.qiaobc.spring.beans.spel.Address">
<!-- 使用SpEL为属性赋一个字面值:标准数据类型或字符串 -->
<property name="city" value="#{'Wuhan'}"></property>
<property name="street" value="Jiedaokou"></property>
</bean>
<bean id="car" class="com.qiaobc.spring.beans.spel.Car">
<property name="brand" value="BMW"></property>
<property name="price" value="500000"></property>
<!-- 使用SpEL引用类的静态属性 -->
<property name="tyrePerimeter" value="#{T(java.lang.Math).PI * 80}"></property>
</bean>
<bean id="person" class="com.qiaobc.spring.beans.spel.Person">
<property name="name" value="qiaobc"></property>
<!-- 使用SpEL来引用其他bean -->
<property name="car" value="#{car}"></property>
<!-- 使用SpEL来引用其他bean的属性 -->
<property name="city" value="#{address.city}"></property>
<!-- 在SpEL中使用运算符 -->
<property name="info" value="#{car.price > 300000 ? '金领' : '白领'}"></property>
</bean>
9. IoC容器中bean的生命周期
bean配置文件核心代码如下所示:
<bean id="car" class="com.qiaobc.spring.beans.cycle.Car"
init-method="init" destroy-method="destory">
<property name="brind" value="BMW"></property>
</bean>
<!--
需要实现BeanPostProcessor接口,并实现其中的方法:
postProcessBeforeInitialization(Object bean, String beanName):在init-method之前被调用
postProcessAfterInitialization(Object bean, String beanName):在init-method之后被调用
-->
<!-- 配置bean的后置处理器:不需要配置id,IoC容器自动识别是一个BeanPostProcessor -->
<bean class="com.qiaobc.spring.beans.cycle.MyBeanPostProcessor"></bean>
自定义BeanPostProcessor的实现类如下:
package com.qiaobc.spring.beans.cycle;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
if("car".equals(beanName)) {
System.out.println("postProcessAfterInitialization:" + beanName);
}
return bean;
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
System.out.println("postProcessBeforeInitialization:" + beanName);
return bean;
}
}
10. 通过工厂方法配置Bean
bean配置文件核心代码如下所示:
<!--
通过静态工厂方法来配置bean:注意不是配置静态工厂方法实例
class属性:指向静态工厂方法所属类的全类型
factory-method属性:指向静态工厂方法的名称
constructor-arg标签:若静态工厂方法需要传入参数,则使用该元素为其配置参数
-->
<bean id="car1" class="com.qiaobc.spring.beans.factory.StaticCarFactory"
factory-method="getCar">
<constructor-arg value="bmw"></constructor-arg>
</bean>
<!-- 配置实例工厂方法所属类的实例 -->
<bean id="instanceCarFactory" class="com.qiaobc.spring.beans.factory.InstanceCarFactory"></bean>
<!-- 通过实例工厂方法来配置bean -->
<bean id="car2" factory-bean="instanceCarFactory" factory-method="getCar">
<constructor-arg value="audi"></constructor-arg>
</bean>
自定义静态工厂StaticCarFactory如下:
package com.qiaobc.spring.beans.factory;
import java.util.HashMap;
import java.util.Map;
/**
* 静态工厂方法:直接调用某一个类的静态方法就可以返回Bean的实例
*/
public class StaticCarFactory {
private static Map<String, Car> cars = new HashMap<String, Car>();
static{
cars.put("bmw", new Car("bmw", 600000));
cars.put("audi", new Car("audi", 400000));
}
public static Car getCar(String name) {
return cars.get(name);
}
}
自定义实例工厂InstanceCarFactory如下:
package com.qiaobc.spring.beans.factory;
import java.util.HashMap;
import java.util.Map;
/**
* 实例工厂方法:需要先创建工厂本身,再调用工厂的实例方法来返回bean的实例
*/
public class InstanceCarFactory {
private Map<String, Car> cars = null;
public InstanceCarFactory() {
cars = new HashMap<String, Car>();
cars.put("bmw", new Car("bmw", 600000));
cars.put("audi", new Car("audi", 400000));
}
public Car getCar(String brand) {
return cars.get(brand);
}
}
11. 通过FactoryBean配置Bean
bean配置文件核心代码如下所示:
<!--
通过FactoryBean来配置Bean的实例
class属性:指向FactoryBean的全类名;
property:配置FactoryBean的属性;
注意:实例返回的实例是FactoryBean的getObject()方法所返回的实例
-->
<bean id="car" class="com.qiaobc.spring.beans.factoryBean.CarFactoryBean"></bean>
自定义FactoryBean的实现类如下:
package com.qiaobc.spring.beans.factoryBean;
import org.springframework.beans.factory.FactoryBean;
/**
* 自定义的FactoryBean需要实现FactoryBean接口
*/
public class CarFactoryBean implements FactoryBean<Car> {
// 返回bean的对象
@Override
public Car getObject() throws Exception {
return new Car("bmw", 600000);
}
// 返回bean的类型
@Override
public Class<?> getObjectType() {
return Car.class;
}
// 是否为单实例的
@Override
public boolean isSingleton() {
return true;
}
}
12. 配置形式之基于注解的方式
12.1 基于注解配置Bean
其中,context:include-filter和context:exclude-filter子节点支持多种类型的过滤表达式,如下图所示:
12.2 基于注解装配Bean的属性
bean配置文件核心代码如下所示:
<!--
指定Spring IoC容器扫描的包
resource-pattern属性:指定扫描的资源,如repository/*.java
context:include-filter子节点:指定包含哪些指定表达式的组件,该子节点需要use-default-filters配合使用
-->
<context:component-scan
base-package="com.qiaobc.spring.beans.annotation" use-default-filters="true">
<!-- context:include-filter子节点:指定包含哪些指定表达式的组件,该子节点需要use-default-filters配合使用 -->
<!--
<context:include-filter type="annotation" expression="org.springframework.stereotype.Service"/>
-->
<!-- context:exclude-filter子节点:指定排除哪些指定表达式的组件 -->
<!--
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
-->
<!--
<context:exclude-filter type="assignable" expression="com.qiaobc.spring.beans.annotation.repository.UserRepository"/>
-->
<!--
<context:include-filter type="assignable" expression="com.qiaobc.spring.beans.annotation.repository.UserRepository"/>
-->
</context:component-scan>
<!-- 可能会抛出java.lang.NoClassDefFoundError: org/springframework/aop/TargetSource异常,加入spring-aop-4.0.0.RELEASE.jar即可 -->
13. 泛型依赖注入
Spring4.x中可以为子类注入子类对应的泛型类型的成员变量的引用,示意图如下:
14. 整合多个配置文件
Spring允许通过import将多个配置文件引入到一个文件中,进行配置文件的集成;在启动Spring容器时,仅需要指定合并好的配置文件即可;其中,import元素的resource属性支持Spring的标准路径资源。
578

被折叠的 条评论
为什么被折叠?



