关于 Spring 中配置 Bean 对象的几种方式

1. Bean 的配置方式

配置方式有两种:

  • 基于 XML 文件配置:在 Spring 配置文件中,使用特定的标签元素来声明 Bean 及它们的依赖关系
  • 基于注解的方式:通过在类、方法、属性等上面使用注解的方式来管理配置 Bean

2. 依赖注入的方式

为对象注入属性值或依赖对象的主要方式有三种,分别是:构造器注入、属性注入和接口方法注入(比较不常用)。

1)构造器注入

使用构造器注入 Bean 的属性值或依赖的对象,Bean 在实例化后就可以使用:

<!-- 1. 按照顺序 -->
<bean id="user" class="com.sonata.spring.helloworld.User">
	<!-- 要求: 在 Bean 中必须有对应的构造器. -->
	<constructor-arg value="Mike"></constructor-arg>
</bean>

<!-- 2. 按照索引匹配入参 -->
<bean id="user" class="com.sonata.spring.helloworld.User">
	<constructor-arg value="Mike" index="0"></constructor-arg>
	<constructor-arg value="18" index="1"></constructor-arg>
	<constructor-arg value="male" index="2"></constructor-arg>
</bean>

<!-- 3. 按照类型匹配入参 -->
<bean id="user" class="com.sonata.spring.helloworld.User">
	<constructor-arg value="Mike" type="java.lang.String"></constructor-arg>
	<constructor-arg value="18" type="java.lang.Integer"></constructor-arg>
	<constructor-arg value="male" type="java.lang.String"></constructor-arg>
</bean>

<!-- 若一个 bean 有多个构造器, 如何通过构造器来为 bean 的属性赋值 -->
<!-- 可以根据 index 和 type 进行更加精确的定位 -->
<bean id="user" class="com.sonata.spring.helloworld.User">
	<constructor-arg value="KUGA" index="1"></constructor-arg>
	<constructor-arg value="ChangAnFord" index="0"></constructor-arg>
	<constructor-arg value="250000" type="float"></constructor-arg>
</bean>

优点:

  • 一注入即就绪状态,可以马上用

缺点:

  • 当依赖对象多的时候,参数列表长;
  • 因为是通过反射来注入的,当多个同类型参数存在比较难处理;
  • 针对不同的需求,可能需要引入多个构造方法,不方便维护。

2)属性注入

实际使用中比较常用的注入方式,使用 setter 方法进行赋值,所以对象中必须有对应的属性 set 方法:

<!-- 配置一个 bean -->
<bean id="user" class="com.sonata.spring.helloworld.User">
	<!-- 为属性赋值 -->
	<property name="name" value="Jason"></property>
</bean>

优点:

  • setter 方法命名比较随意,描述性比构造方法好;
  • setter 方法可以被继承,可以设置默认值;

3. 注入属性值或依赖对象

上面已经讲了注入属性或依赖对象的主要方式,但是在注入不同类型的值或对象的时候,写法有些区别,可以分为字面值(或者说是魔法值),其他 Bean 对象,内部 Bean,null 值,集合,级联属性。

1)字面值

字面值, 可以用字符串表示的值, 这种类型的值可以使用 value 属性或者 <value> 元素标签进行注入:

<bean id="user" class="com.sonata.spring.helloworld.User">
	<constructor-arg value="Mike" index="0"></constructor-arg>
	<constructor-arg>
		<value>18</value>
	</constructor-arg>
</bean>

若字面值中包含特殊字符,如 < , > 等, 可以使用 <![CDATA[字面值]]> 把字面值包裹起来:

<bean id="user" class="com.sonata.spring.helloworld.User">
	<!-- 这里为姓名注入值: Jack<>son -->
	<constructor-arg>
		<value><![CDATA[Jack<>son]]></value>
	</constructor-arg>
</bean>

2)其他 Bean 对象

Java 程序通常是由很多对象组成的,有些对象中又会包含对其他对象的引用,所以 Bean 之间需要相互访问,在配置文件中,可以通过<ref>元素或 ref 属性为 Bean 的属性或构造器进行注入:

<bean id="car" class="com.sonata.spring.helloworld.Car">
	<!-- 通过 ref 属性值指定当前属性指向哪一个 bean! -->
	<property name="dao" ref="dao5"></property>
</bean>

<bean id="user" class="com.sonata.spring.helloworld.User">
	<!-- 通过 ref 属性值指定当前属性指向哪一个 bean 的 ID -->
	<property name="car" ref="car"></property>
</bean>

3)集合对象

当 Bean 对象中的属性包含集合属性时, 如 List, Set, Map 等, 可以使用 Spring 提供的特定标签进行配置:

<!-- 装配集合属性 -->
<bean id="user" class="com.sonata.spring.helloworld.User">
	<property name="userName" value="Jack"></property>
	<property name="cars">
		<!-- 使用 list 元素来装配集合属性 -->
		<list>
			<ref bean="car"/>
			<ref bean="car2"/>
		</list>
	</property>
</bean>
  • set 集合使用 <set> 标签
  • 数组的定义和 List 一样, 也是使用<list>
  • java.util.Properties 对象, 可以使用<props>标签定义, 其内包含多个<prop>作为子标签, 每个<prop>标签需要定义 key 属性

util 空间下的标签
为了复用 list 配置对象, 可以使用 util schema 来定义一个带有 ID 的集合对象, 为其他 Bean 对象提供引用:

<!-- 声明集合类型的 bean -->
<util:list id="cars">
	<ref bean="car"/>
	<ref bean="car2"/>
</util:list>

<bean id="user" class="com.sonata.spring.helloworld.User">
	<property name="userName" value="Jack"></property>
	<!-- 引用外部声明的 list -->
	<property name="cars" ref="cars"></property>
</bean>

4)内部 Bean

内部 Bean,有点类似内部类,就是在 Bean 或构造器内部赋值的时候直接声明一个 Bean 对象,这个对象可以不需要定义 id 属性。如果有 Bean 对象仅仅只是给某个对象的特定属性使用时, 可以将它声明为内部 Bean,直接放在<property><constructor-arg>元素中:

<!-- 声明使用内部 bean -->
<bean id="user" class="com.sonata.spring.helloworld.User">
	<property name="car">
		<!-- 内部 bean, 类似于匿名内部类对象. 不能被外部的 bean 来引用, 也没有必要设置 id 属性 -->
		<bean class="com.sonata.spring.helloworld.Car">
			<property name="color" value="black"></property>
		</bean>
	</property>
</bean>

5)null 值和级联属性

  • null 值:可以使用专用的 <null/> 元素标签为 Bean 的字符串或其它对象类型的属性注入 null 值
  • 级联属性:和 Struts、Hiberante 等框架一样,Spring 支持级联属性的配置
<!-- 设置 null 值 -->
<bean id="user" class="com.sonata.spring.helloworld.User">
	<property name="car"><null/></property>
</bean>

<!-- 设置级联属性 -->
<bean id="user" class="com.sonata.spring.helloworld.User">
	<property name="car" ref="car"></property>
	<property name="car.color" value="black"></property>
</bean>

6)使用 p 命名空间

为了简化 XML 文件的配置,Spring 2.5 版本引入了 p 命名空间,可以直接作为<bean>标签的属性来配置:

<bean id="user" class="com.sonata.spring.helloworld.User"
		p:cars-ref="cars" p:userName="Tim Cook"></bean>

7)Bean 的继承

<!-- 使用 parent 来完成继承 -->	
<bean id="user4" parent="user" p:userName="Bob"></bean>

8)引用外部文件属性值

比如在配置数据库连接的时候, 经常使用db.properties文件来保存连接参数:

jdbc.user=root
jdbc.password=123456
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.jdbcUrl=jdbc:mysql:///sonata

如果我们需要在 Spring 配置文件中引用的话, 在 Spring2.0 的时候, 需要先配置 PropertyPlaceholderConfigurer 类, 同时引入配置文件:

<!-- 使用 parent 来完成继承 -->	
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
	<property name="location" value="classpath:db.properties"></property>
</bean>

Spring2.5之后, 可以通过简化的元素:

<!-- 导入外部的资源文件 -->
<context:property-placeholder location="classpath:db.properties"/>

<!-- 配置数据源 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
	<property name="user" value="${jdbc.user}"></property>
	<property name="password" value="${jdbc.password}"></property>
	<property name="driverClass" value="${jdbc.driverClass}"></property>
	<property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property>
</bean>

4. 自动装配

IoC 容器可以自动装配 Bean,只需通过在<bean>标签的autowire属性指定自动装配的模式, 这样在配置 Bean 的时候就不需要再手动指定属性值是什么:

public class Dao {
	private DataSource dataSource;
	//getter, setter...
}

public class Service {
	private Dao dao;
	//getter, setter...
}
<!-- 自动装配: 只需要声明 bean, 然后把 bean 之间的关系交给 IOC 容器来完成 -->
<!-- 
	byType: 根据类型进行自动装配. 但要求 IOC 容器中只有一个类型对应的 bean, 若有多个则无法完成自动装配.
	byName: 若属性名和某一个 bean 的 id 名一致, 即可完成自动装配. 若没有 id 一致的, 则无法完成自动装配
-->
<!-- 在使用 XML 配置时, 自动转配用的不多. 但在基于 注解 的配置时, 自动装配使用的较多. -->
<bean id="dao" class="com.spring.ref.Dao">
	<property name="dataSource" value="C3P0"></property>				
</bean>

<!-- 默认情况下 bean 是单例的! -->
<!-- 但有的时候, bean 就不能使单例的. 可以通过 scope 属性来指定 bean 的作用域 -->
<!-- 
	prototype: 原型的. 每次调用 getBean 方法都会返回一个新的 bean. 且在第一次调用 getBean 方法时才创建实例
	singleton: 单例的. 每次调用 getBean 方法都会返回同一个 bean. 且在 IOC 容器初始化时即创建 bean 的实例. 默认值 
-->
<bean id="service" class="com.spring.ref.Service" autowire="byName"></bean>

autowire 属性要么根据类型自动装配, 要么根据名称自动装配, 不能两者兼而有之

5. Bean 之间的关系

1)Bean 的继承关系

  1. Spring 允许继承 bean 的配置, 被继承的 bean 称为父 bean. 继承这个父 Bean 的 Bean 称为子 Bean
  2. 子 Bean 从父 Bean 中继承配置, 包括 Bean 的属性配置
  3. 子 Bean 也可以覆盖从父 Bean 继承过来的配置
  4. 父 Bean 可以作为配置模板, 也可以作为 Bean 实例. 若只想把父 Bean 作为模板, 可以设置 <bean> 的 abstract 属性为 true, 这样 Spring 将不会实例化这个 Bean
  5. 并不是 <bean> 元素里的所有属性都会被继承. 比如: autowire, abstract 等.
  6. 也可以忽略父 Bean 的 class 属性, 让子 Bean 指定自己的类, 而共享相同的属性配置. 但此时 abstract 必须设为 true

2)Bean 的依赖关系

  1. Spring 允许用户通过 depends-on 属性设定 Bean 前置依赖的 Bean,前置依赖的 Bean 会在本 Bean 实例化之前创建好
  2. 如果前置依赖于多个 Bean,则可以通过逗号,空格或的方式配置 Bean 的名称

6. Bean 的作用域

  • singleton: 在 SpringIOC 容器中仅存在一个 Bean 实例, Bean 以单例的方式存在
  • prototype: 每次调用 getBean() 时都会返回一个新的实例
  • request: 每次 HTTP 请求都会创建一个新的 Bean, 该作用域仅适用于 WebApplicationContext 环境
  • session: 同一个 HTTP Session 共享一个 Bean, 不同的 HTTP Session 使用不同的 Bean。该作用域仅适用于 WebApplicationContext 环境

7. SpEL

支持运行时查询和操作对象图的强大的表达式语言;语法类似于 EL:SpEL 使用 #{…} 作为定界符,所有在大框号中的字符都将被认为是 SpEL;SpEL 为 bean 的属性进行动态赋值提供便利。

通过 SpEL 可以实现:

  • 通过 bean 的 id 对 bean 进行引用
  • 调用方法以及引用对象中的属性
  • 计算表达式的值
  • 正则表达式的匹配

1)字面量 (也可以不需要用到 SpEL)

  • 整数:<property name="count" value="#{5}"/>
  • 小数:<property name="frequency" value="#{89.7}"/>
  • 科学计数法:<property name="capacity" value="#{1e4}"/>
  • String 可以使用单引号或者双引号作为字符串的定界符号:<property name=「name」value="#{'Chuck'}"/><property name='name' value='#{"Chuck"}'/>
  • Boolean:<property name="enabled" value="#{false}"/>
<bean ...>
	<property name="name" value="Jack"></property>
</bean>

2)引用 Bean、属性和方法

<bean id="car" class="com.spring.beans.spel.Car">
<bean id="address" class="com.spring.beans.spel.Address">

<bean id="person" class="com.spring.beans.spel.Person">
	<!-- 使用 SpEL 引用其他的 Bean -->
	<property name="car" value="#{car}"></property>
	<!-- 使用 SpEL 引用其他的 Bean 的属性 -->
	<property name="city" value="#{address.city}"></property>
	<!-- 使用运算符 -->
	<property name="info" value="#{car.price > 100 ? 'Y' : 'N'}"></property>
</bean>

3)比较运算符, if/else, and/or/not, 正则表达式

8. 静态工厂方法和实例工厂方法创建 Bean

1) 静态工厂方法

调用静态工厂方法创建 Bean是将对象创建的过程封装到静态方法中. 当客户端需要对象时, 只需要简单地调用静态方法, 而不同关心创建对象的细节。要声明通过静态方法创建的 Bean, 需要在 Bean 的 class 属性里指定拥有该工厂的方法的类, 同时在 factory-method 属性里指定工厂方法的名称. 最后, 使用 <constrctor-arg> 元素为该方法传递方法参数:

public class StaticCarFactory {
	private static Map<String, Car> cars = new HashMap<>();

	static {
		cars.put("audi", new Car("audi", 10000));
		cars.put("ford", new Car("ford", 20000));
	}

	public static Car getCar(String name) {
		return cars.get(name);
	}
}

Bean 文件配置:

<!-- 如果工厂方法需要传入参数, 则使用 constrctor-arg 来配置参数 -->
<bean id="car" class="com.sonata.spring.factory.StaticCarFactory"
	factory-method="getCar">
	<constrctor-arg value="audi"/>
</bean>

2) 实例工厂方法

先创建工厂实例, 然后再调用工厂实例的工厂方法创建 Bean:

/**
 * 创建实例化的工厂
 */
public class InstanceCarFactory {
	private Map<String, Car> cars = new HashMap<>();

	public InstanceCarFactory {
		cars.put("audi", new Car("audi", 10000));
		cars.put("ford", new Car("ford", 20000));
	}

	public Car getCar(String name) {
		return cars.get(name);
	}
}

Bean 文件配置:

<!-- 先配置工厂, 进行实例 -->
<bean id="factory" class="com.sonata.spring.factory.InstanceCarFactory "></bean>

<!-- 如果工厂方法需要传入参数, 则使用 constrctor-arg 来配置参数 -->
<bean id="car" factory-bean="factory" factory-method="getCar">
	<constrctor-arg value="audi"/>
</bean>

3) FactoryBean接口

工厂 Bean 跟普通 Bean 不同, 其返回的对象不是指定类的一个实例, 其返回的是该工厂 Bean 的 getObject 方法所返回的对象 :

/**
 * 自定义的 FactoryBean 需要实现 Spring 的 FactoryBean 接口
 */
public class CarFactoryBean implements FactoryBean<Car> {
	private String brand;
	//getter(), setter()

	@Override
	public Car getObject() throws Exception {
		return new Car("BMW", 5000);
	}
	
	@Override
	public Class<?> getObjectType() {
		return Car.class;
	}

	@Override
	public boolean isSingleton() {
		return return;
	}
}

Bean 文件配置:

<bean id="car" class="com.sonata.spring.factory.CarFactoryBean">
	<property name="brand" value="BMW"/>
</bean>
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring支持四种基于XML的Bean注入方式:构造函数注入、设值注入、工厂方法注入和静态工厂方法注入。 使用XML注入Bean的几种方式包括:1、使用构造函数注入;2、使用静态工厂方法注入;3、使用实例工厂方法注入;4、使用注解注入;5、使用Java配置类注入。Spring基于XML注入Bean时有以下几种方式: 1. 构造函数注入 使用constructor-arg元素在bean的定义注入构造函数参数。例如: ```xml <bean id="person" class="com.example.Person"> <constructor-arg name="name" value="Alice"/> <constructor-arg name="age" value="25"/> </bean> ``` 2. Setter方法注入 使用property元素在bean的定义注入属性值。例如: ```xml <bean id="person" class="com.example.Person"> <property name="name" value="Alice"/> <property name="age" value="25"/> </bean> ``` 3. 工厂方法注入 使用factory-method元素在bean的定义注入工厂方法返回的实例。例如: ```xml <bean id="person" class="com.example.Person" factory-bean="personFactory" factory-method="createPerson"/> ``` 其,personFactory是一个工厂类,createPerson方法返回一个Person对象。 4. 静态工厂方法注入 使用factory-method元素在bean的定义注入静态工厂方法返回的实例。例如: ```xml <bean id="person" class="com.example.Person" factory-class="com.example.PersonFactory" factory-method="createPerson"/> ``` 其,PersonFactory是一个静态工厂类,createPerson方法返回一个Person对象

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值