首先我们需要创建一个 bean
public class Person {
private String name;
private String gender;
private Integer age;
private String email;
// get/set 方法...
// toString ...
}
通过配置文件实现
我们需要先创建一个spring配置文件,然后在配置文件中配置我们的 需要注入的 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 http://www.springframework.org/schema/beans/spring-beans.xsd">
</beans>
创建完成之后,我们就可以开始配置我们的 bean 了
属性注入方式
通过set 方式注入
<bean id="person01" class="spring.bean.Person">
<property name="name" value="张三"></property>
<property name="age" value="18"></property>
<property name="gender" value="male"></property>
<property name="email" value="123@qq.com"></property>
</bean>
- class:填写需要注册组件的全限定类名
- id:标识这个对象的唯一标识,后面我们需要通过这个唯一表示获取实例化对象
在 bean 标签里面,我们可以通过 property 标签配置 bean 的属性。
- name:属性名
- value: 属性值
接下来,我们就可以使用开始测试,看注入是否成功
@Test
public void test() {
ApplicationContext context = new ClassPathXmlApplicationContext("ioc.xml");
Person bean = (Person) context.getBean("person01");
System.out.println(bean);
}
Person{name=‘张三’, gender=‘male’, age=18, email=‘123@qq.com’}
ClassPathXmlApplicationContext表示当前应用的 xml 配置文件在 classpath下。还有一种方式是使用 FileSystemXmlApplicationContext,传入的是磁盘中配置文件的路径,但是我们一般都不会使用这个。
下面,让我们想一下,我们得到的组件对象是由谁来创建的呢?这个不用多想,就知道时由 ioc 容器创建的。那么是什么时候开始创建的呢?是单例的还是多例的呢?我们不妨来做一个实验。
我们在bean 的构造函数中加上一个打印语句
public class Person {
...
public Person() {
System.out.println("Person 被创建了");
}
...
}
@Test
public void test() {
System.out.println("容器创建前");
ApplicationContext context = new ClassPathXmlApplicationContext("ioc.xml");
System.out.println("对象获取前");
Person bean = (Person) context.getBean("person01");
Person bean2 = (Person) context.getBean("person01");
System.out.println("对象获取后");
System.out.println(bean);
System.out.println(bean2);
System.out.println(bean == bean2);
}
容器创建前
Person 被创建了
对象获取前
对象获取后
Person{name=‘张三’, gender=‘male’, age=18, email=‘123@qq.com’}
Person{name=‘张三’, gender=‘male’, age=18, email=‘123@qq.com’}
true
由输出结果可以看出,对象是在容器创建的时候完成的。而且只打印了一句 “Person 被创建了”,且最后获取的两个对象是同一个对象,所以 ioc 容器中的组件对象是单例的。
那么,如果我们想要让 ioc 容器创建多实例对象怎么办呢?我们可以在 bean 标签中加上 scope属性,其值有四个:
- prototype: 多实例的。容器启动时不会创建bean,在获取时才创建
- singleton: 单实例的。容器启动时创建bean(默认)
- request: 在web环境下,同一个请求下创建一个 bean 实例
- session: 在web环境下,同一次会话下创建一个 bean 实例
接下来,我们再想一下,ioc 容器是如何给 组件对象的属性赋值的呢?ioc 容器在创建这个组件对象时,(property)会利用setter方法为 JavaBean的属性进行赋值。不信,我们可以再次实验一下,我们在 setter方法中添加一句打印语句,然后运行一下我们的第一个 test 用例
public void setName(String name) {
System.out.println("setName..." + name);
this.name = name;
}
Person 被创建了
setName…张三
Person{name=‘张三’, gender=‘male’, age=18, email=‘123@qq.com’}
这样,我们就有充分的证据证明 ioc 容器在创建组件对象时,(property)会利用setter方法为 JavaBean的属性进行赋值。
需要注意的是 JavaBean的属性名由 getter/setter 方法决定
其实,getBean()中除了可以传入组件的 id 外,还可以传入Person.class形式的参数。这种方式的好处是你不需要将获得的对象进行强转,但是如果 ioc 容器里面管理了两个 还可以传入Person,它就不知道你想要得到的是哪个对象,从而报错: “No qualifying bean of type[xxx] is defined:expected single matching bean but found 2:…”。想要解决这个问题,你可以传入两个参数:id 和 Person.class。
通过构造器注入
<bean id="person02" class="spring.bean.Person">
<constructor-arg name="name" value="张三"></constructor-arg>
<constructor-arg name="age" value="18"></constructor-arg>
<constructor-arg name="gender" value="male"></constructor-arg>
<constructor-arg name="email" value="123@qq.com"></constructor-arg>
</bean>
constructor-arg:
- name:属性名
- value:属性值
这种通过有参构造器的方法也可以为 ioc 的组件对象赋值。但是前提是你的 bean 中需要写构造器,而且如果你只写了一个带 4 个参数的构造器,你就必须在 标签中为四个属性都赋值。
注意,name属性可以省略,但是为参数赋值的顺序必须与构造器中的顺序一样,除非你使用 index 为参数指定索引。如果你有两个参数相同的构造器,其赋值方式就有一定的随机性了。这时你需要使用 type 来指定参数的类型。
通过 p 名称空间注入
<bean id="person03" class="spring.bean.Person"
p:age="18" p:email="123@qq.com" p:name="张三" p:gender="male"
>
在 xml 中,名称空间是用来防止标签重复的。让我们来假想以下如果一个类中有另外的一个对象属性,而这个对象里面有一个与当前类同名的属性,那么我们该如何配置这个类呢?这个时候就可以用我们的名称空间来标识他们了。
在是使用 p 名称空间之前,我们需要在 xml 中加入这样一段约束:
xmlns:p="http://www.springframework.org/schema/p"