一、配置Bean的两种方式之使用XML配置Bean
1.Bean的自动装配
①.Spring IOC 容器可以自动装配 Bean. 需要做的仅仅是在 <bean> 的 autowire 属性里指定自动装配的模式
②.byType(根据类型自动装配): 若 IOC 容器中有多个与目标 Bean 类型一致的 Bean. 在这种情况下, Spring 将无法判定哪个 Bean 最合适该属性, 所以不能执行自动装配.
③.byName(根据名称自动装配): 必须将目标 Bean 的名称和属性名设置的完全相同.
④.constructor(通过构造器自动装配): 当 Bean 中存在多个构造器时, 此种自动装配方式将会很复杂. 不推荐使用
首先创建两个Bean,Person和Mobile:
public class Person {
private String name;
private Mobile mobile;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Mobile getMobile() {
return mobile;
}
public void setMobile(Mobile mobile) {
this.mobile = mobile;
}
@Override
public String toString() {
return "Person [name=" + name + "]";
}
}
public class Mobile {
private String brand;
private double price;
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
@Override
public String toString() {
return "Mobile [brand=" + brand + ", price=" + price + "]";
}
}
在IOC容器中配置byName自动装配:
<?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:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<bean id="mobile" class="com.spring.model.Mobile">
<property name="brand" value="iphone"></property>
<property name="price" value="5000"></property>
</bean>
<bean id="person" class="com.spring.model.Person" autowire="byName">
<property name="name" value="loose"></property>
</bean>
</beans>
byName: 若属性名和某一个 bean 的 id 名一致, 即可完成自动装配. 若没有 id 一致的, 则无法完成自动装配
在IOC容器中配置byType自动装配:
<?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:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<!-- 无需id,根据Bean的类型自动装配 -->
<bean class="com.spring.model.Mobile">
<property name="brand" value="iphone"></property>
<property name="price" value="5000"></property>
</bean>
<bean id="person" class="com.spring.model.Person" autowire="byType">
<property name="name" value="loose"></property>
</bean>
</beans>
byType: 根据类型进行自动装配. 但要求 IOC 容器中只有一个类型对应的 bean, 若有多个则无法完成自动装配
总结:
自动装配,即将实体内的实体(例如Person类中的Car类)自动引用;
使用byName,只要实体内的实体名称的setXxx方法名中的Xxx和IOC容器中配置的bean id一致,即自动装配;
使用byType,只要实体内的实体类型和IOC容器中的bean定义的类型一致即自动装配上。
自动装配的缺点:
--->在 Bean 配置文件里设置 autowire 属性进行自动装配将会装配 Bean 的所有属性. 然而, 若只希望装配个别属性时, autowire 属性就不够灵活了.
--->autowire 属性要么根据类型自动装配, 要么根据名称自动装配, 不能两者兼而有之.
注意:本身自动装配实际开发中运用不多,所以其他属性不再说明,有兴趣自己去查阅相关资料。
2.继承Bean配置
注意:
①.这不是java上的继承,而是配置上的继承。
②.Spring 允许继承 bean 的配置, 被继承的 bean 称为父 bean. 继承这个父 Bean 的 Bean 称为子 Bean
③.子 Bean 从父 Bean 中继承配置, 包括 Bean 的属性配置
④.子 Bean 也可以覆盖从父 Bean 继承过来的配置
⑤.父 Bean 可以作为配置模板, 也可以作为 Bean 实例. 若只想把父 Bean 作为模板, 可以设置 <bean> 的abstract 属性为 true, 这样 Spring 将不会实例化这个 Bean
⑥.并不是 <bean> 元素里的所有属性都会被继承. 比如: autowire, abstract 等.
⑦.也可以忽略父 Bean 的 class 属性, 让子 Bean 指定自己的类, 而共享相同的属性配置. 但此时 abstract 必须设为 true
首先创建一个Bean:
public class Person {
private String name;
private String province;
private String city;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getProvince() {
return province;
}
public void setProvince(String province) {
this.province = province;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
@Override
public String toString() {
return "Person [name=" + name + ", province=" + province + ", city=" + city + "]";
}
}
接着在IOC容器中配置该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:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<bean id="personParent" class="com.spring.model.Person">
<property name="name" value="loose"></property>
</bean>
<!-- 使用parent声明继承哪个Bean的配置 -->
<bean id="personSon" parent="personParent"></bean>
</beans>
测试简单继承程序:
public class Main {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
Person person = (Person) ctx.getBean("personSon");
System.out.println(person);
//输出:Person [name=loose, province=null, city=null]
}
}
在IOC容器中配置子Bean覆盖父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:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<bean id="personParent" class="com.spring.model.Person">
<property name="name" value="loose"></property>
</bean>
<bean id="personSon" parent="personParent">
<!-- 覆盖父Bean的name属性 -->
<property name="name" value="loose2"></property>
</bean>
</beans>
测试子Bean覆盖父Bean程序:
public class Main {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
Person person = (Person) ctx.getBean("personSon");
System.out.println(person);
//输出:Person [name=loose2, province=null, city=null]
}
}
在IOC容器中将父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:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<!-- 定义为模板可以不配置class属性,但子Bean必须配置class -->
<bean id="personParent" abstract="true">
<property name="name" value="loose"></property>
</bean>
<bean id="personSon" class="com.spring.model.Person" parent="personParent"></bean>
</beans>
测试将父Bean定义为模板程序:
public class Main {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
Person person = (Person) ctx.getBean("personSon");
System.out.println(person);
//输出:Person [name=loose2, province=null, city=null]
}
}
3.Bean的依赖配置
Spring 允许用户通过 depends-on 属性设定 Bean 前置依赖的Bean,前置依赖的 Bean 会在本 Bean 实例化之前创建好,如果前置依赖于多个 Bean,则可以通过逗号,空格或的方式配置 Bean 的名称。
4.Bean的作用域
在 Spring 中,可以在 <bean> 元素的 scope 属性里设置 Bean 的作用域,默认情况下, Spring 只为每个在 IOC 容器里声明的 Bean 创建唯一一个实例, 整个 IOC 容器范围内都能共享该实例:所有后续的 getBean() 调用和 Bean 引用都将返回这个唯一的 Bean 实例.该作用域被称为 singleton, 它是所有 Bean 的默认作用域,常见的值有4个,分别是:
singleton:在IOC容器中仅存在一个实例,Bean以单例的形式存在;
prototype:每次调用getBean()都会返回一个全新的实例;
request:每次Http请求都会创建一个新的Bean,该作用域仅适用于WebApplicationContext环境;
session:同一个HttpSession共享同一个Bean,不同的HttpSession使用不同的Bean,该作用域仅适用于WebApplicationContext环境;
最常用的是singleton和prototype!
我们创建一个Bean为Person来测试一下:
public class Person {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Person [name=" + name + "]";
}
}
在IOC容器中,将该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:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<bean id="person" class="com.spring.model.Person" scope="singleton">
<property name="name" value="loose"></property>
</bean>
</beans>
测试Bean单例:
public class Main {
@SuppressWarnings("resource")
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
Person person1 = (Person) ctx.getBean("person");
Person person2 = (Person) ctx.getBean("person");
System.out.println(person1 == person2);
//输出true,证明是单例子
}
}
在IOC容器中,将该Bean配置为prototype类型:
<?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:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<bean id="person" class="com.spring.model.Person" scope="prototype">
<property name="name" value="loose"></property>
</bean>
</beans>
测试Bean prototype:
public class Main {
@SuppressWarnings("resource")
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
Person person1 = (Person) ctx.getBean("person");
Person person2 = (Person) ctx.getBean("person");
System.out.println(person1 == person2);
//输出false,证明非单例
}
}
上面的例子仅仅是获取两个id一致的Bean,比较无法直观的看出IOC容器为我们的Bean创建实例的过程,接下来,我们通过一个例子再来看单例和prototype的区别:我们将Person的无参构造器显示出来
public class Person {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Person() {
System.out.println("我是person无参构造器");
}
@Override
public String toString() {
return "Person [name=" + name + "]";
}
}
接着将IOC容器中的Bean配置为单例模式:
<bean id="person" class="com.spring.model.Person" scope="singleton">
<property name="name" value="loose"></property>
</bean>
测试单例,看看控制台的输出:
public class Main {
@SuppressWarnings("resource")
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
//运行后输出:我是person无参构造器
}
}
说明:单例模式是IOC一启动就帮我们实例化了Person。
再将Bean配置为prototype,然后在看测试程序的控制台输出:
<bean id="person" class="com.spring.model.Person" scope="prototype">
<property name="name" value="loose"></property>
</bean>
public class Main {
@SuppressWarnings("resource")
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
//运行后输出:没有任何输出
}
}
说明:prototype模式,IOC容器启动并不会帮我们实例化Person。
最后,我们通过获取Bean再来对比下两者的区别:
<bean id="person" class="com.spring.model.Person" scope="singleton">
<property name="name" value="loose"></property>
</bean>
public class Main {
@SuppressWarnings("resource")
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
Person person1 = (Person) ctx.getBean("person");
Person person2 = (Person) ctx.getBean("person");
System.out.println(person1 == person2);
//运行后输出:
//我是person无参构造器
//true
}
}
<bean id="person" class="com.spring.model.Person" scope="prototype">
<property name="name" value="loose"></property>
</bean>
public class Main {
@SuppressWarnings("resource")
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
System.out.println("前面没有帮忙实例化...");
Person person1 = (Person) ctx.getBean("person");
Person person2 = (Person) ctx.getBean("person");
System.out.println(person1 == person2);
//运行后输出:
//我是person无参构造器
//我是person无参构造器
//false
}
}
总结:
单例模式的Bean,IOC容器启动会自动帮我们创建了该Bean的实例,并且只创建一次;而prototype模式下IOC容器启动不会帮我们创建该Bean的实例,而是每次去getBean的时候,每次都实例化一个对象出来。
注意:常用的是单例和prototype模式,其它的了解就行,有兴趣的自行翻阅资料。