spring 之基于XML的方式配置 Bean

本文详细介绍了Spring框架中通过XML配置管理Bean的各种方式,包括Bean的定义、别名、导入、描述、属性赋值、构造函数注入、自动装配、作用域、初始化和销毁方法、工厂方法、抽象Bean、依赖关系等。通过实例展示了如何配置和使用这些特性。
摘要由CSDN通过智能技术生成

Spring 通过 IOC 容器的方式管理 Bean。在本篇,将通过 xml 配置的方式介绍如何配置 Bean。

1. 常见的 xml 配置文件头解析

<?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:p="http://www.springframework.org/schema/p"
    xmlns:c="http://www.springframework.org/schema/c"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:aop="http://www.springframework.org/schema/aop" 
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans  
    					http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
           				http://www.springframework.org/schema/context 
           				http://www.springframework.org/schema/context/spring-context-3.0.xsd
           				http://www.springframework.org/schema/aop 
           				http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
           				http://www.springframework.org/schema/tx 
           				http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
    <!-- 简单的 Bean 配置,后面详讲 -->      
	<bean id="animal" class="cn.cerish.entity.Animal"></bean>
</beans>
  • xml 作为文件的开头,beans 是配置文件的顶级元素,不必讨论。
  • xmlns(XML NameSpace):类似于一个保留字,它只用于声明命名空间。
    • 若后面未使用前缀显式限定(如aop、context) ,则该元素将被隐式限定。即 声明了一个 默认命名空间无论在任何时候都只能存在一个默认命名空间
    • 通常我们会用一个具有特点的名字来作为命名空间的前缀(例如这里的aop),在使用该命名空间的时候,需要加上该前缀,如
<aop:config>
	<aop:aspect id="***" ref="***"/>
	<aop:pointcut id="***" expression="****" />
</aop:config>
  • xsi(xml schema instance):schemaLocation 提供了一个xml 命名空间到对应的XSD(Xml Schema Definition)文件的一个映射,它的值由一个或多个URI引用对组成,两个URI之间以空白符分隔(空格和换行均可)。c p 命名空间没有对应的 xsd 文件,是在 handler 中处理的。

    • 第一个URI是定义的 XML命名空间的值,
    • 第二个URI给出Schema文档的实际位置,Schema处理器将从这个位置读取Schema文档,该文档的targetNamespace必须与第一个URI(XML命名空间的值)相匹配。
  • xmlns:c xmlns:p 分别指定 c、p命名空间,用于简化示例 Bean 的配置,后面会讲。

  • 还有比较冷门的配置(xml属于 xml 文件的知识,xsi 属于 xsd 文件的知识)

    • xml:base 重写默认URI
    • xml:id 指定一个元素或属性有在文档范围内惟一的标识符
    • xml:lang 设置 属性和内容的语言
    • xml:space 设置应用程序如何处理空白,取值为default或preserve
    • xsi:type 允许XML实例直接关联元素类型信息
    • xsi:nil 允许在XSD可能不允许的情况下将空元素视为有效。
    • xsi:noNamespaceSchemaLocation 没有命名空间的情况下使用,只给出 xsd 文件的URI

2. Bean 的详细配置

先定义几个类信息,作为 Bean 注入 ioc 容器

/* 省略 getter、setter 方法 */
public class Animal {
	private Dog dog;
	private Cat cat;
}

public class Dog {
	private int age;
	private String name;
}
public class Cat {
	private int age;
	private String name;
}

2.1 bean 与 alias

  • 一个 Bean,可以使用 name 属性配置多个别名(使用逗号、空格、分号分割都可以),或者使用 alias 标签配置别名
  • spring-cat.xml 文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	   xsi:schemaLocation="http://www.springframework.org/schema/beans
	https://www.springframework.org/schema/beans/spring-beans-4.3.xsd">
	<bean id="cat" name="cat1, cat2;cat5 cat6" class="cn.cerish.entity.Cat"></bean>
	<alias name="cat" alias="cat3"></alias>
	<alias name="cat1" alias="cat4"></alias>
</beans>
  • 测试类
package cn.cerish;

import cn.cerish.entity.Cat;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class IOCTest {
	@Test
	public void test() {
		ApplicationContext ac = new ClassPathXmlApplicationContext("spring-animal.xml");
		Cat cat = (Cat) ac.getBean("cat");
		Cat cat1 = (Cat) ac.getBean("cat1");
		Cat cat2 = (Cat) ac.getBean("cat2");
		Cat cat3 = (Cat) ac.getBean("cat3");
		Cat cat4 = (Cat) ac.getBean("cat4");
		Cat cat5 = (Cat) ac.getBean("cat5");
		Cat cat6 = (Cat) ac.getBean("cat6");
		System.out.println("cat: " + cat);
		System.out.println("cat1: " + cat1);
		System.out.println("cat2: " + cat2);
		System.out.println("cat3: " + cat3);
		System.out.println("cat4: " + cat4);
		System.out.println("cat5: " + cat5);
		System.out.println("cat6: " + cat6);
	}
}
  • 拿到的 Cat 对象都是同一个,这是因为 spring 默认 Bean 的生成是单实例。
    在这里插入图片描述

2.2 import

  • 在开发时,难免遇到需要使用多个配置文件的情况,可以使用 import 导入其他 xml 资源,进行整合。
  • resourse 可以导入项目目录下的资源,也可以导入磁盘(file)、网络(http)的资源,这里只演示导入项目目录下的资源。
  • spring-cat.xml 增加如下语句
<import resource="spring-dog.xml"></import>
  • spring-dog.xml 文件如下
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	   xsi:schemaLocation="http://www.springframework.org/schema/beans
	https://www.springframework.org/schema/beans/spring-beans-4.3.xsd">
	<bean id="dog" class="cn.cerish.entity.Dog"></bean>
</beans>
  • 测试类
package cn.cerish;

import cn.cerish.entity.*;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class IOCTest {
	@Test
	public void test() {
		ApplicationContext ac = new ClassPathXmlApplicationContext("spring-cat.xml");
		Cat cat = (Cat) ac.getBean("cat");
		System.out.println("cat: " + cat);
		Dog dog = (Dog) ac.getBean("dog");
		System.out.println("dog: " + dog);
	}
}
  • 可以看到,也是可以拿到 dog 对象的
    在这里插入图片描述

2.3 description

  • description 标签的作用在于,可以给当前配置文件作出描述,例如当前文件是为哪一模块进行配置的,且必须方法 beans 内的第一个标签,且只能配置一次。
<description>用来配置 Animal 信息的文件</description>

2.4 bean 的子节点详解

2.4.1 property

  • new ClassPathXmlApplicationContext("spring-animal.xml").getBean("XXX");得到的 Bean 实例,默认经过空构造生成,属性值为默认的。如下图所示
    在这里插入图片描述
  • 可通过 property 配置属性默认值,本质上是调用 setter 方法赋值
  • 实体类
package cn.cerish.entity;


import java.util.*;

public class Student {
	private int age;
	private String name;
	private Cat cat;
	private String[] books;
	private List<String> hobbys;
	private Map<String, String> card;
	private Set<String> games;
	private String wife;
	private Properties info;

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Cat getCat() {
		return cat;
	}

	public void setCat(Cat cat) {
		this.cat = cat;
	}

	public String[] getBooks() {
		return books;
	}

	public void setBooks(String[] books) {
		this.books = books;
	}

	public List<String> getHobbys() {
		return hobbys;
	}

	public void setHobbys(List<String> hobbys) {
		this.hobbys = hobbys;
	}

	public Map<String, String> getCard() {
		return card;
	}

	public void setCard(Map<String, String> card) {
		this.card = card;
	}

	public Set<String> getGames() {
		return games;
	}

	public void setGames(Set<String> games) {
		this.games = games;
	}

	public String getWife() {
		return wife;
	}

	public void setWife(String wife) {
		this.wife = wife;
	}

	public Properties getInfo() {
		return info;
	}

	public void setInfo(Properties info) {
		this.info = info;
	}

	@Override
	public String toString() {
		return "Student{" +
				"age=" + age +
				", name='" + name + '\'' +
				", cat=" + cat +
				", books=" + Arrays.toString(books) +
				", hobbys=" + hobbys +
				", card=" + card +
				", games=" + games +
				", wife='" + wife + '\'' +
				", info=" + info +
				'}';
	}
}
  • spring-student.xml 配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	   xsi:schemaLocation="http://www.springframework.org/schema/beans
	   https://www.springframework.org/schema/beans/spring-beans-2.0.xsd">

	<description>本配置文件用于展示 property 的属性配置</description>
	<bean id="student" class="cn.cerish.entity.Student">
		<property name="age" value="18"></property>
		<property name="name" value="cerish"></property>
		<property name="cat" ref="cat" />
		<!--  数组:注意这里要使用 list,使用 array会报错,不清楚为啥	-->
		<property name="books">
			<list>
				<value>红楼梦</value>
				<value>西游记</value>
				<value>三国演义</value>
				<value>水浒传</value>
			</list>
		</property>
		<!--  List	-->
		<property name="hobbys">
			<list>
				<value>听歌</value>
				<value>敲代码</value>
			</list>
		</property>
		<!--  Map	-->
		<property name="card">
			<map>
				<entry key="idCard" value="4454644546"></entry>
			</map>
		</property>
		<!--  set	-->
		<property name="games">
			<set>
				<value>Lol</value>
				<value>王者荣耀</value>
			</set>
		</property>
		<!--  Properties	-->
		<property name="info">
			<props>
				<prop key="学号">1520711</prop>
				<prop key="性别"></prop>
			</props>
		</property>
		<!--  null值  -->
		<property name="wife">
			<null></null>
		</property>

	</bean>

	<bean id="cat" class="cn.cerish.entity.Cat">
		<property name="age" value="2" />
		<property name="name" value="miao~" />
	</bean>

</beans>
  • 测试类
public class IOCTest {
	@Test
	public void test() {
		ApplicationContext ac = new ClassPathXmlApplicationContext("spring-student.xml");
		Student student = (Student) ac.getBean("student");
		System.out.println("student: " + student);
	}
}

在这里插入图片描述

2.4.2 constructor-arg

  • propety 是通过 setter 方法进行赋值,constructor-arg 则是通过构造方法进行赋值。
  • constructor-arg 可通过三种方式进行赋值(当然,需要有对应的构造函数)
    • index 属性,指定参数位置,例如 <constructor-arg index="0" value="1"></constructor-arg>
    • type 属性,指定参数类型,例如 <constructor-arg type="java.lang.String" value="wang~"></constructor-arg>
    • 前两者不推荐使用,建议使用 name 属性指定名称例如<constructor-arg name="name" value="wang~"></constructor-arg>

2.5 bean 的属性详解

2.5.1 p、c命名空间

  • 前面介绍了属性赋值与构造函数赋值,实际上 p、c命名空间就是对应用来简化赋值操作的。
  • 若想使用 p、c命名空间,就需要先导入对应的配置,在 beans 标签中加入以下配置
xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
  • 完整的 spring-dog.xml 配置如下:
<?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:p="http://www.springframework.org/schema/p"
	   xmlns:c="http://www.springframework.org/schema/c"
	   xsi:schemaLocation="http://www.springframework.org/schema/beans
	https://www.springframework.org/schema/beans/spring-beans-4.3.xsd">

	<bean id="dogC" class="cn.cerish.entity.Dog" c:age="3" c:name="wangC"></bean>
	<bean id="dogP" class="cn.cerish.entity.Dog" p:age="2" p:name="wangP~"></bean>
</beans>
  • 测试类
public class IOCTest {
	@Test
	public void test() {
		ApplicationContext ac = new ClassPathXmlApplicationContext("spring-dog.xml");
		Dog dogC = (Dog) ac.getBean("dogC");
		Dog dogP = (Dog) ac.getBean("dogP");
		System.out.println("dogC: " + dogC);
		System.out.println("dogP: " + dogP);
	}
}

在这里插入图片描述

2.5.2 autowire

  • 自动装配功能,从前面可以看到,若 Bean 对象的个数较多或者属性较多,那么需要配置很多个 property,spring 提供了 autowire 属性帮我们做了这件事。

  • autowire 的取值有五个

    • no:不会自动注入。
    • default:与 no 一致, 不会自动注入。
    • byName:根据名字自动注入,本质上使用 setter 方法注入。
    • byType:根据类型自动注入,本质上使用 setter 方法注入。
    • constructor:根据构造器方法注入,需要有对应的构造器,本质上是根据构造函数的参数类型进行赋值,若有多个相同类型,则不赋值。(构造函数参数依次递减)
  • spring-dog.xml 配置如下,独自运行查看结果(例如,name 正确,类型不正确?类型多个?)

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	   xsi:schemaLocation="http://www.springframework.org/schema/beans
	https://www.springframework.org/schema/beans/spring-beans-4.3.xsd">
	<!-- byName 实例,若名称相同,类型不同,会报错 Failed to convert property value of type xxx-->
	<!--<bean id="animalName" class="cn.cerish.entity.Animal" autowire="byName"></bean>-->
	<!--<bean id="cat" class="cn.cerish.entity.Cat">-->
	<!--	<property name="age" value="1"></property>-->
	<!--	<property name="name" value="miaoName~"></property>-->
	<!--</bean>-->
	<!--<bean id="dog" class="cn.cerish.entity.Dog">-->
	<!--	<property name="age" value="1"></property>-->
	<!--	<property name="name" value="wangName~"></property>-->
	<!--</bean>-->

	<!-- byType实例:根据类型查找Bean,若具有多个相同的类型,不进行匹配 -->
	<bean id="animalType" class="cn.cerish.entity.Animal" autowire="byType"></bean>
	<bean id="catType" class="cn.cerish.entity.Cat">
		<property name="age" value="2"></property>
		<property name="name" value="miaoType~"></property>
	</bean>
	<bean id="dogType" class="cn.cerish.entity.Dog">
		<property name="age" value="2"></property>
		<property name="name" value="wangType~"></property>
	</bean>

	<!-- 从参数最多的构造参数开始查找对应的类型,直至空构造为止 -->
	<!--<bean id="animalConstructor" class="cn.cerish.entity.Animal" autowire="constructor"></bean>-->
	<!--<bean id="catConstructor" class="cn.cerish.entity.Cat">-->
	<!--	<property name="age" value="3"></property>-->
	<!--	<property name="name" value="miaoConstructor~"></property>-->
	<!--</bean>-->
	<!--<bean id="dogConstructor" class="cn.cerish.entity.Dog">-->
	<!--	<property name="age" value="3"></property>-->
	<!--	<property name="name" value="wangConstructor~"></property>-->
	<!--</bean>-->
</beans>	

2.5.3 autowire-candidate

  • autowire-candidate 是与 autowire 搭配使用的,每个在 xml 配置的 Bean,都默认为 自动注入的候选 Bean,使用autowire-candidate 可将指定的 Bean 从候选队列除名,值为 byName 时不生效
  • spring-animal.xml 配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	   xsi:schemaLocation="http://www.springframework.org/schema/beans
	https://www.springframework.org/schema/beans/spring-beans-4.3.xsd">
	<bean id="animalType" class="cn.cerish.entity.Animal" autowire="byType"></bean>
	<bean id="catType" class="cn.cerish.entity.Cat">
		<property name="age" value="2"></property>
		<property name="name" value="miao~"></property>
	</bean>
	<bean id="dogType" class="cn.cerish.entity.Dog" autowire-candidate="false">
		<property name="age" value="2"></property>
		<property name="name" value="wang~"></property>
	</bean>
</beans>
  • 测试类
public class IOCTest {
	@Test
	public void test() {
		ApplicationContext ac = new ClassPathXmlApplicationContext("spring-animal.xml");
		Animal animal = (Animal) ac.getBean("animalType");
		System.out.println("animal: " + animal);
	}
}

在这里插入图片描述

2.5.4 scope

  • 设置 Bean 的作用域

    • singleton:单例模式,每次获取共享同一个实例
    • prototype:多例模式,每次获取生成一个新的实例
    • request:表示该针对每一次HTTP请求都会产生一个新的bean,同时该bean仅在当前HTTP request内有效。
    • session:表示该针对每一次HTTP请求都会产生一个新的bean,同时该bean仅在当前HTTP session内有效。
    • golabl session:类似于标准的HTTP Session作用域,仅在基于portlet的web应用中才有意义。
    • request、session、golabl session只有在 spring web 中使用才有效,这里不做过多讲解。
  • 实体类

public class Person {
	private int age;
	private String name;
	....省略 getter、setter
}	
  • spring-person.xml 配置:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	   xsi:schemaLocation="http://www.springframework.org/schema/beans
	https://www.springframework.org/schema/beans/spring-beans-4.3.xsd">

	<bean id="personSingleton" class="cn.cerish.entity.Person" scope="singleton"></bean>
	<bean id="personPrototype" class="cn.cerish.entity.Person" scope="prototype"></bean>
</beans>
  • 测试类
public class IOCTest {
	@Test
	public void test() {
		ApplicationContext ac = new ClassPathXmlApplicationContext("spring-person.xml");
		Person person1 = (Person) ac.getBean("personSingleton");
		Person person2 = (Person) ac.getBean("personSingleton");
		Person person3 = (Person) ac.getBean("personSingleton");
		System.out.println("person1: " + person1);
		System.out.println("person2: " + person2);
		System.out.println("person3: " + person3);
		System.out.println("==============================");
		Person person4 = (Person) ac.getBean("personPrototype");
		Person person5 = (Person) ac.getBean("personPrototype");
		Person person6 = (Person) ac.getBean("personPrototype");
		System.out.println("person4: " + person4);
		System.out.println("person5: " + person5);
		System.out.println("person6: " + person6);
	}
}

在这里插入图片描述

2.5.5 primary

  • 在使用 autowire 自动注入的时候,会出现多个相同类型而导入的问题,可以使用 primary 将指定的 Bean 设置为首选的 Bean 解决,当然,如果设置了多个 primary 还是会报错。
  • sprin-animal.xml 配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	   xsi:schemaLocation="http://www.springframework.org/schema/beans
	https://www.springframework.org/schema/beans/spring-beans-4.3.xsd">
	<bean id="animal" class="cn.cerish.entity.Animal" autowire="byType"></bean>
	<bean id="cat" class="cn.cerish.entity.Cat">
		<property name="age" value="2"></property>
		<property name="name" value="miao~"></property>
	</bean>
	<bean id="dog1" class="cn.cerish.entity.Dog" primary="true">
		<property name="age" value="2"></property>
		<property name="name" value="wang~"></property>
	</bean>
	<bean id="dog2" class="cn.cerish.entity.Dog">
		<property name="age" value="3"></property>
		<property name="name" value="wang~"></property>
	</bean>
	<bean id="dog3" class="cn.cerish.entity.Dog">
		<property name="age" value="4"></property>
		<property name="name" value="wang~"></property>
	</bean>
</beans>
  • 测试类
@Test
public void testPrimary() {
	ApplicationContext ac = new ClassPathXmlApplicationContext("spring-animal.xml");
	Animal animal = (Animal) ac.getBean("animal");
	System.out.println("animal" + animal);
}

在这里插入图片描述

2.5.6 lazy-init

  • 在 spring 中,所有的单实例 Bean 会在容器创建完成后进行实例化(多实例 Bean 不会提前创建),可将 lazy-init 赋值为 true,则通过 getBean 索取 bean 时才会实例化的。
  • 实体类
/* Person 类 */
public class Person {
	private int age;
	private String name;
	public Person() {
		System.out.println("我是 person 空构造");
	}
}	
/* Animal 类 */
public class Animal {
	private int age;
	private String name;
	public Animal () {
		System.out.println("我是 Animal 空构造");
	}
}	
  • sprin-person.xml 配置:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	   xsi:schemaLocation="http://www.springframework.org/schema/beans
	https://www.springframework.org/schema/beans/spring-beans-4.3.xsd">

	<bean id="personSingleton" class="cn.cerish.entity.Person" scope="singleton" lazy-init="true"></bean>
	<bean id="animalSingleton" class="cn.cerish.entity.Animal" scope="singleton"></bean>

</beans>
  • 测试类
@Test
public void testLazyInit() {
	ApplicationContext ac = new ClassPathXmlApplicationContext("spring-person.xml");
}

在这里插入图片描述

2.5.7 init-method & destroy-method

  • 两个方法分别为 Bean 初始化时执行 与 销毁时执行的函数。
  • 实体类
public class Person {
	private int age;
	private String name;
	public Person() {
		System.out.println("我是 person 空构造");
	}
	public void initMethod() {
		System.out.println("我是 Person 类的 initMethod");
	}
	public void destoryMethod() {
		System.out.println("我是 Person 类的 destoryMethod");
	}
}
  • spring-person.xml 配置:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	   xsi:schemaLocation="http://www.springframework.org/schema/beans
	https://www.springframework.org/schema/beans/spring-beans-4.3.xsd">

	<bean id="personInitDestory" class="cn.cerish.entity.Person" init-method="initMethod" destroy-method="destoryMethod"></bean>
</beans>
  • 测试类
@Test
public void testInitDestory() {
	ApplicationContext ac = new ClassPathXmlApplicationContext("spring-person.xml");
	Person person = (Person) ac.getBean("personInitDestory");
	/* 关闭容器,意在销毁 Bean */
	((ClassPathXmlApplicationContext) ac).close();
}

在这里插入图片描述

2.5.8 factory-method & factory-bean

  • 之前的配置中,生成的 Bean 都是通过构造函数生成的,那么,如何指定函数去生产 Bean?factory-method 帮我们完成了这件事。
  • 实体类
/* Car:实体类 */
public class Car {}
/* CarFactory: 生产 Car 的工厂类 */
public class CarFactory {
	public static Car getCar() {
		System.out.println("我是 static 方法创建的 Car");
		return new Car();
	}

	public Car getInstanceCar() {
		System.out.println("我是 static 方法创建的 Car");
		return new Car();
	}
}
  • spring-car.xml 配置
<!-- lazy-init 是为了更好的区分静态方法与非静态方法 -->
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	   xsi:schemaLocation="http://www.springframework.org/schema/beans
	https://www.springframework.org/schema/beans/spring-beans-4.3.xsd">
	<!-- 静态方法配置 -->
	<bean id="staticCar" class="cn.cerish.entity.CarFactory" factory-method="getCar" lazy-init="true"></bean>
	<!-- 非静态方法配置 -->
	<bean id="carFactory" class="cn.cerish.entity.CarFactory" />
	<bean id="instanceCar" factory-bean="carFactory" factory-method="getInstanceCar" lazy-init="true"></bean>
</beans>
  • 测试类
@Test
public void testFactoryBean() {
	ApplicationContext ac = new ClassPathXmlApplicationContext("spring-car.xml");
	// 静态方法获取对象
	Car staticCar = (Car) ac.getBean("staticCar");
	System.out.println("======================");
	// 非静态方法获取对象
	Car instanceCar = (Car) ac.getBean("instanceCar");
}

在这里插入图片描述

2.5.9 abstract & parent

  • 类似于 Java 的继承,spring 的 Bean 也可以有继承。例如,Teacher 类拥有同一个学校,可以把 school 属性提取,作为公共部分被多个老师同时继承。
  • 继承分为:类继承与公共部分继承,即 配置的 Bean 可以不是class类。
  • 实体类
public class Teacher {
	private String school;
	private String name;
	private int age;
	....getter setter 方法
}
  • spring-teacher.xml 配置:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	   xsi:schemaLocation="http://www.springframework.org/schema/beans
	https://www.springframework.org/schema/beans/spring-beans-4.3.xsd">
	<!-- 父类继承,若不想该类被容器加载,则设置 abstract="true" -->
	<bean id="major" class="cn.cerish.entity.Major">
		<property name="majorName" value="计算机技术"></property>
	</bean>

	<!-- 公共部分继承 -->
	<bean name="schoolName" abstract="true">
		<property name="school" value="清华大学"></property>
	</bean>

	<bean id="teacher1" parent="major" class="cn.cerish.entity.Teacher">
		<property name="name" value="teacher1"></property>
		<property name="age" value="28"></property>
		<property name="school" value="北京大学"></property>
	</bean>
	<bean id="teacher2" parent="major" class="cn.cerish.entity.Teacher">
		<property name="name" value="teacher2"></property>
		<property name="age" value="38"></property>
		<property name="school" value="北京大学"></property>
	</bean>

	<bean id="teacher3" parent="schoolName" class="cn.cerish.entity.Teacher">
		<property name="name" value="teacher3"></property>
		<property name="age" value="48"></property>
		<property name="majorName" value="计算机技术"></property>
 	</bean>

	<bean id="teacher4" parent="schoolName" class="cn.cerish.entity.Teacher">
		<property name="name" value="teacher4"></property>
		<property name="age" value="58"></property>
		<property name="majorName" value="计算机技术"></property>
	</bean>
</beans>
  • 测试类
@Test
public void testAbstract() {
	ApplicationContext ac = new ClassPathXmlApplicationContext("spring-teacher.xml");
	Teacher teacher1 = (Teacher) ac.getBean("teacher1");
	System.out.println("teacher1: " + teacher1);
	Teacher teacher2 = (Teacher) ac.getBean("teacher2");
	System.out.println("teacher2: " + teacher2);
	Teacher teacher3 = (Teacher) ac.getBean("teacher3");
	System.out.println("teacher3: " + teacher3);
	Teacher teacher4 = (Teacher) ac.getBean("teacher4");
	System.out.println("teacher4: " + teacher4);
}

在这里插入图片描述

2.5.10 depends-on

  • 在Bean之间没有明确的依赖关系时,depends-on 可以为 Bean 指定依赖关系。例如,需要先有 专业major 后有教师 teacher,则需要 Major 创建在前,销毁在后。
  • 实体类
public class Teacher {
	private String school;
	private String name;
	private int age;
}
public class Major {
	private String majorName;
}	
  • spring-major.xml 配置:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	   xsi:schemaLocation="http://www.springframework.org/schema/beans
	https://www.springframework.org/schema/beans/spring-beans-4.3.xsd">
	<bean id="teacher" class="cn.cerish.entity.Teacher" init-method="initMethod" destroy-method="destoryMethod" depends-on="major">
		<property name="name" value="teacher"></property>
		<property name="age" value="28"></property>
	</bean>

	<bean id="major" class="cn.cerish.entity.Major" init-method="initMethod" destroy-method="destoryMethod">
		<property name="majorName" value="计算机科学"></property>
	</bean>

</beans>
  • 测试类
@Test
public void testDependOn() {
	ApplicationContext ac = new ClassPathXmlApplicationContext("spring-major.xml");

	((ClassPathXmlApplicationContext) ac).close();
}

在这里插入图片描述

3. 奇思妙想计

3.1 若使用了相同的 id 配置不同的Bean,会发生什么?配置相同的Bean 呢?

  • 相同的id,不同的类型,xml 配置:
<?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:p="http://www.springframework.org/schema/p"
	   xmlns:c="http://www.springframework.org/schema/c"
	   xsi:schemaLocation="http://www.springframework.org/schema/beans
	https://www.springframework.org/schema/beans/spring-beans-4.3.xsd">

	<bean id="dog" class="cn.cerish.entity.Dog">
		<property name="name" value="wang~~"></property>
		<property name="age" value="2"></property>
	</bean>

	<bean id="dog" class="cn.cerish.entity.Cat">
		<property name="name" value="miao~~"></property>
		<property name="age" value="1"></property>
	</bean>

</beans>
  • 结果报错如下:(相同的类型也报错)
org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: Bean name 'dog' is already used in this <beans> element
Offending resource: class path resource [spring-dog.xml]
	at org.springframework.beans.factory.parsing.FailFastProblemReporter.error(FailFastProblemReporter.java:72)
	at org.springframework.beans.factory.parsing.ReaderContext.error(ReaderContext.java:119)...

3.2 property 与 命名空间同时配置属性,哪个优先级高?

  • spring-dog.xml 配置:
<?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:p="http://www.springframework.org/schema/p"
	   xmlns:c="http://www.springframework.org/schema/c"
	   xsi:schemaLocation="http://www.springframework.org/schema/beans
	https://www.springframework.org/schema/beans/spring-beans-4.3.xsd">

	<bean id="dog" class="cn.cerish.entity.Dog" p:name="wangP:~" p:age="1">
		<property name="name" value="wangProperty~"></property>
		<property name="age" value="2"></property>
	</bean>
</beans>
  • 测试类
@Test
public void testPriority() {
	ApplicationContext ac = new ClassPathXmlApplicationContext("spring-dog.xml");
	Dog dog = (Dog) ac.getBean("dog");
	System.out.println(dog);
}
  • 结果为,报错 BeanDefinitionParsingException
org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: Property 'age' is already defined using both <property> and inline syntax. Only one approach may be used per property.
Offending resource: class path resource [spring-dog.xml]

	at org.springframework.beans.factory.parsing.FailFastProblemReporter.error(FailFastProblemReporter.java:72)
	at org.springframework.beans.factory.parsing.ReaderContext.error(ReaderContext.java:119)...
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值