一、Spring IoC 容器 Bean 花式注册与获取
花式一:通过Bean的类型获取Bean
配置文件beans.xml保持不变,在ContainerTest中新增方法
// 通过bean类型获取bean
@Test
public void testGetBeanByClass(){
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:beans.xml");
Person stark = context.getBean(Person.class);
System.out.println(stark);
}
配置文件beans.xml新增加一个bean标签的配置
<bean id="parker" class="com.citi.entity.Person">
<property name="lastName" value="Parker" />
<property name="age" value="18" />
<property name="gender" value="male" />
<property name="email" value="peterparker@gmail.com" />
</bean>
再次执行testGetBeanByClass(),会出现如下报错: No qualifying bean of type 'com.citi.entity.Person' available: expected single matching bean but found 2: stark,parker
这是因为配置文件中有连个bean配置,获取的时候没有指定获取哪个bean,所以会报错,修改testGetBeanByClass()
// 通过bean类型获取bean
@Test
public void testGetBeanByClass(){
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:beans.xml");
Person stark = context.getBean("stark",Person.class);
System.out.println(stark);
}
输出结果如下
花式二:通过Constructor获取Bean
Person实体类中新增有参数构造方法
public Person(String lastName, Integer age, String gender, String email) {
System.out.println("有参构造方法被调用");
this.lastName = lastName;
this.age = age;
this.gender = gender;
this.email = email;
}
beans.xml中注册所有bean标签配置,并增加如下bean标签
<bean id="parker" class="com.citi.entity.Person">
<constructor-arg name="lastName" value="Parker" />
<constructor-arg name="age" value="18" />
<constructor-arg name="gender" value="male" />
<constructor-arg name="email" value="peterparker@gmail.com" />
</bean>
ContainerTest中获取bean
@Test
public void testGetBeanByConstructor(){
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:beans.xml");
Person parker = context.getBean("parker",Person.class);
System.out.println(parker);
}
执行testGetBeanByConstructor,控制台打印结果如下
通过Constructor获取Bean时bean.xml第二种注册方式
<bean id="parker" class="com.citi.entity.Person">
<constructor-arg value="Parker" />
<constructor-arg value="18" />
<constructor-arg value="male" />
<constructor-arg value="peterparker@gmail.com" />
</bean>
name标签可以省略,但是这个顺序一定要与构造方法中属性的顺序一致,也可以添加index属性来让value和类的属性保持一致,index从0开始
<bean id="parker" class="com.citi.entity.Person">
<constructor-arg value="Parker" index="0"/>
<constructor-arg value="18" index="1"/>
<constructor-arg value="male" index="2"/>
<constructor-arg value="peterparker@gmail.com" index="3"/>
</bean>
有参构造方法重载的情况下,可以使用type执行属性值的类型
### 花式三:为各种属性正确赋值
新增一个实体类Car,Book
public class Car {
private String carName;
private Integer price;
private String color;
// 此处省略getter/setter/toString方法
}
public class Book {
private String bookName;
private String author;
// 此处省略getter/setter/toString方法
}
给Person实体类增加属性
public class Person {
private String lastName;
private Integer age;
private String gender;
private String email;
// 为各种属性正确赋值
private Car car;
private List<Book> bookList;
private Map<String,Object> map;
private Properties properties;
//无参构造方法
public Person() {
System.out.println("无参构造方法被调用");
}
public Person(String lastName, Integer age, String gender, String email) {
System.out.println("有参构造方法被调用");
this.lastName = lastName;
this.age = age;
this.gender = gender;
this.email = email;
}
// 此处省略getter/setter/toString方法
}
resources目录下新建一个assgin_value.xml的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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
</beans>
test目录下新建一个测试类AssignValueTest
public class AssignValueTest {
}
不给属性赋值,基本数据类型就是默认值,引用数据类型是null
在assing_value.xml增加bean标签
<!--不赋值,默认为Null-->
<bean id="stark" class="com.citi.entity.Person">
</bean>
AssignValueTest测试类中增加测试代码
@Test
public void testAssignNull(){
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:assign_value.xml");
Person stark = context.getBean(Person.class);
System.out.println(stark);
}
执行testAssignNull()测试方法,属性都为null
如果要为一个属性赋值null,以lastName为例,修改xml配置文件
<!--不赋值,默认为Null-->
<bean id="stark" class="com.citi.entity.Person">
<property name="lastName">
<null/>
</property>
</bean>
修改测试类,增加判断lastName是否为null
@Test
public void testAssignNull(){
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:assign_value.xml");
Person stark = context.getBean(Person.class);
System.out.println(stark.getLastName() == null);
System.out.println(stark);
}
控制台输出为true,说明赋值null成功,对属性赋值null要使用<null/>标签
为应用的外部的值
在xml配置文件中增加Car实体类的配置,增加一个Person实体了的bean标签配置,给Car属性赋值
<bean id="JAGUAR" class="com.citi.entity.Car">
<property name="carName" value="JAGUAR"></property>
<property name="color" value="英国绿"></property>
<property name="price" value="580000"></property>
</bean>
<!--引用外部的值-->
<bean id="stark01" class="com.citi.entity.Person">
<property name="car" ref="JAGUAR"></property>
</bean>
增加测试方法testRefOutsideValue()
@Test
public void testRefOutsideValue(){
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:assign_value.xml");
Car car = context.getBean(Car.class);
Person stark01 = context.getBean("stark01",Person.class);
System.out.println(stark01.getCar() == car);
System.out.println(stark01);
System.out.println(car);
}
执行该方法,xml配置中使用了ref标签引用容器中存在的Car配置,所以容器中的Car和Person中的Car是同一个
引用内部的Value
增加Bean xml配置
<!--引用内部的值-->
<bean id="stark02" class="com.citi.entity.Person">
<property name="car">
<bean class="com.citi.entity.Car">
<property name="carName" value="Model 3"></property>
<property name="price" value="265652"></property>
<property name="color" value="black"></property>
</bean>
</property>
</bean>
增加测试方法
@Test
public void testInsideValue(){
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:assign_value.xml");
Car car = context.getBean(Car.class);
Person stark02 = context.getBean("stark02",Person.class);
System.out.println(stark02.getCar() == car);
System.out.println(stark02);
System.out.println(car);
}
容器中的Car仍然为JAGUAR,而Person中定义了Car为Model 3,两者不是同一个,输出false,使用内部的Value,要在propert标签内再定一个Bean标签
List属性赋值
增加xml配置,定义一个Book的bean标签供bookList引用,列表引用要是用ref标签
<bean id="PythonBook" class="com.citi.entity.Book">
<property name="bookName" value="Python21天跑路"></property>
<property name="author" value="佚名"></property>
</bean>
<!--List属性赋值-->
<bean id="stark03" class="com.citi.entity.Person">
<property name="bookList">
<list>
<bean id="book01" class="com.citi.entity.Book">
<property name="bookName" value="Java从入门到跑路"></property>
<property name="author" value="佚名"></property>
</bean>
<!--引用外部-->
<ref bean="PythonBook"></ref>
</list>
</property>
</bean>
增加测试方法
@Test
public void testAssign2List(){
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:assign_value.xml");
Book pythonBook = context.getBean(Book.class);
Person stark03 = context.getBean("stark03",Person.class);
List<Book> bookList = stark03.getBookList();
for (Book book : bookList) {
System.out.println(book);
}
System.out.println(stark03);
System.out.println(pythonBook);
}
执行测试,控制台输出
尝试获取Person bookList属性中的另一本书,测试方法中增加代码
Book book01 = context.getBean("book01",Book.class);
System.out.println(book01);
执行测试方法报错,说明bean标签内部的bean是无法直接通过容器获取的,只有最外层定义的bean可以被容器直接获取
Map属性赋值
增加xml配置,给map属性赋值需要使用entry标签,通过key和value标签定义map结构中的key和map,也可用过key-ref和value-ref引用外部的key和value,map中可以在通过entry再嵌套map
<!--Map属性赋值-->
<bean id="stark04" class="com.citi.entity.Person">
<property name="map">
<map>
<!--key,value,一个entry代表一个简直对-->
<entry key="name" value="Peter"></entry>
<entry key="book" value-ref="PythonBook"></entry>
<entry key="car">
<bean class="com.citi.entity.Car">
<property name="carName" value="Model Y"></property>
</bean>
</entry>
<entry key="mapKey">
<map>
<entry key="key01" value="value01"></entry>
</map>
</entry>
</map>
</property>
</bean>
新增测试方法
@Test
public void testAssign2Map(){
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:assign_value.xml");
Person stark04 = context.getBean("stark04",Person.class);
Map<String, Object> map = stark04.getMap();
for (String key : map.keySet()) {
System.out.println("key:" + key);
}
for (Object value : map.values()) {
System.out.println("value:" + value);
}
System.out.println(stark04);
}
执行测试方法,控制台成功打印出map数据结构
Properties属性赋值
增加xml配置,为Properties属性赋值需要使用props标签,prop标签表示properties配置文件中的每一行key-value
<!--Properties属性赋值-->
<bean id="stark05" class="com.citi.entity.Person">
<property name="properties">
<props>
<prop key="username">root</prop>
<prop key="password">12345</prop>
</props>
</property>
</bean>
增加测试方法
@Test
public void testAssign2Properties(){
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:assign_value.xml");
Person stark05 = context.getBean("stark05",Person.class);
System.out.println(stark05);
}
执行测试方法,控制台成功输出properties内容
namespace名称空间
名称空间是用来防止标签重复的,通过增加前缀(名称空间)区分名字相同的标签,如
<car>
<name>F-TYPE</name>
<price>580000</price>
<owner>
<name>Stark</name>
<age>40</age>
</owner>
</car>
car下面的name和owner下面的name出现了重复,此时需要通过增加前缀即命名空间来区分,将xml格式数据修改为如下形式
<car>
<c:name>F-TYPE</c:name>
<price>580000</price>
<owner>
<o:name>Stark</o:name>
<age>40</age>
</owner>
</car>
Spring配置文件中本身就有默认的命名空间,即表头中的
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.xsd"
它表示默认的命名空间,不需要添加前缀
使用自定义的名称空间需要导入,放在表头
xmlns:p = "http://www.springframework.org/schema/p"
使用时会有很多提示
在xml中增加使用前缀的配置
<bean id="stark06" class="com.citi.entity.Person" p:lastName="stark06">
</bean>
增加测试方法
@Test
public void testAssignByNamespace(){
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:assign_value.xml");
Person stark06 = context.getBean("stark06",Person.class);
System.out.println(stark06);
}
控制台成功打印出lastName为stark06
利用util名称空间为Map属性赋值
首先导入名称空间,修改表头为
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:p = "http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-4.3.xsd">
</beans>
接着利用util名称空间创建一个map,id为mapSample,供id为stark07的bean标签引用
<util:map id="mapSample">
<!--key,value,一个entry代表一个简直对-->
<entry key="name" value="Thor"></entry>
<entry key="book" value-ref="PythonBook"></entry>
<entry key="car">
<bean class="com.citi.entity.Car">
<property name="carName" value="Model Y"></property>
</bean>
</entry>
</util:map>
<!--引用util名称空间为Map属性赋值-->
<bean id="stark07" class="com.citi.entity.Person">
<property name="map" ref="mapSample">
</property>
</bean>
增加测试方法
@Test
public void testAssignMapByUtilNamespace(){
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:assign_value.xml");
Person stark07 = context.getBean("stark07",Person.class);
System.out.println(stark07);
}
控制台日志显示,已成功赋值
利用util名称空间为List属性赋值
xml中增加util:list配置,并增加一个bean标签引用util list标签
<util:list id="listSample">
<bean id="book02" class="com.citi.entity.Book">
<property name="bookName" value="Java从入门到跑路"></property>
<property name="author" value="佚名"></property>
</bean>
<!--引用外部-->
<ref bean="PythonBook"></ref>
</util:list>
<!--引用util名称空间为List属性赋值-->
<bean id="stark08" class="com.citi.entity.Person">
<property name="bookList" ref="listSample">
</property>
</bean>
增加测试方法
@Test
public void testAssignListByUtilNamespace(){
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:assign_value.xml");
Person stark08 = context.getBean("stark08",Person.class);
System.out.println(stark08);
}
控制台显示list已被成功赋值
级联属性赋值
Person有Car属性,Car属性又有carName属性,从Person端来看,carName就是级联属性,即属性的属性
增加xml配置
<!--级联属性赋值-->
<bean id="stark09" class="com.citi.entity.Person">
<property name="car" ref="JAGUAR"></property>
<!--修改引用的Car的价格-->
<property name="car.price" value="400000"></property>
</bean>
增加测试代码
@Test
public void testAssignCascadeProperty(){
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:assign_value.xml");
Person stark09 = context.getBean("stark09",Person.class);
Car car = context.getBean(Car.class);
System.out.println(stark09);
System.out.println(car);
}
控制台日志显示价格已经被成功修改,由原来的580000变为400000,并且容器中的原来的car的价格也被修改