从工作开始到现在一直都有使用Spring,日常开发中总有spring的身影,但实话实讲,对spring的认识一直停留在使用阶段,只知其然。做技术当然不能这样,柄着知其所以然的态度,想系统的学习分析一下spring,无奈懒惰让我一直没有着手做。不积跬步,无以至千里,万事得开个头,终于下定决定写下第一篇。

tip: 本系列根据spring 5.2.6.RELEASE 进行分析。

引入spring依赖

1
2
3
4
5
6
7
8
9
10
11

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.2.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.6.RELEASE</version>
</dependency>

传统应用程序可以通过new和反射方式进行实例化Bean。而Spring IOC容器则需要根据Bean定义里的配置元数据使用反射机制来创建Bean。在Spring IOC容器中根据Bean定义创建Bean主要有以下几种方式:

  1. 使用构造器或setter方法实例化Bean

这是最简单的方式,Spring IoC容器即能使用默认空构造器也能使用有参数构造器两种方式创建Bean,如以下方式指定要创建的Bean类型

使用空构造器进行定义,使用此种方式,class属性指定的类必须有空构造器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
package com.study.ioc.model;

public class People {
private String name;

private int age;

public People() {
}

public People(String name, int age) {
this.name = name;
this.age = age;
}

public String getName() {
return name;
}

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

public int getAge() {
return age;
}

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

@Override
public String toString() {
return "People{" + "name='" + name + '\'' + ", age=" + age + '}';
}
}
1
2
<!--    使用无参构造器实例化Bean-->
<bean id="people" class="com.study.ioc.model.People">

使用有参数构造器进行定义,使用此中方式,可以使用< constructor-arg>标签指定构造器参数值,其中index表示位置,value表示常量值,也可以指定引用,指定引用使用ref来引用另一个Bean定义;

1
2
3
4
5
6
<!--    使用有参构造器实例化Bean-->
<bean id="people" class="com.study.ioc.model.People">
<constructor-arg index="0" value="normPeople"/>
<constructor-arg index="1" value="18"/>
<!-- <constructor-arg index="2" ref="collection"/> -->
</bean>

或者写上对应的set、get方法,然后再bean.xml文件中利用property注入值即可。

1
2
3
4
5
<!--    使用setter 实例化bean -->
<bean id="setterPeople" class="com.study.ioc.model.People">
<property name="name" value="setterPeople"/>
<property name="age" value="18"/>
</bean>
  1. 使用静态工厂方式实例化Bean

使用这种方式除了指定必须的class属性,还要指定factory-method属性来指定实例化Bean的方法,而且使用静态工厂方法也允许指定方法参数,spring IoC容器将调用此属性指定的方法来获取Bean:

1
2
3
4
5
6
7
8
9
package com.study.ioc.model;

public class PeopleStaticFactory {

public static People newPeopleInstance(String name, int age) {
return new People(name, age);
}

}
1
2
3
4
5
 <!--    使用静态工厂方式实例化Bean-->
<bean id="factoryPeople" class="com.study.ioc.model.PeopleStaticFactory" factory-method="newPeopleInstance">
<constructor-arg index="0" value="factoryPeople"/>
<constructor-arg index="1" value="18"/>
</bean>
  1. 使用实例工厂方法实例化Bean

使用这种方式不能指定class属性,此时必须使用factory-bean属性来指定工厂Bean,factory-method属性指定实例化Bean的方法,而且使用实例工厂方法允许指定方法参数,方式和使用构造器方式一样。

1
2
3
4
5
6
7
8
package com.study.ioc.model;

public class PeopleInstanceFactory {

public People newPeopleInstance(String name, int age) {
return new People(name, age);
}
}
1
2
3
4
5
6
7
8
 <!--    使用实例工厂方法实例化bean-->
<!-- 1.先定义实例工厂Bean-->
<bean id="peopleInstanceFactory" class="com.study.ioc.model.PeopleInstanceFactory"/>
<!-- 2.使用实例工厂Bean创建Bean-->
<bean id="instancePeople" factory-bean="peopleInstanceFactory" factory-method="newPeopleInstance">
<constructor-arg index="0" value="instancePeople"/>
<constructor-arg index="1" value="18"/>
</bean>
  1. 实现FactoryBean接口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package com.study.ioc.model;

import org.springframework.beans.factory.FactoryBean;

public class PeopleFactory implements FactoryBean<People> {
public People getObject() throws Exception {
People people = new People();
people.setName("weylan");
people.setAge(18);
return people;
}

public Class<?> getObjectType() {
return People.class;
}

public boolean isSingleton() {
return true;
}

@Override
public String toString() {
return "PeopleFactory{}";
}
}

xml中只需定义FactoryBean即可

1
<bean id="peopleFactory" class="com.study.ioc.model.PeopleFactory"/>

在我们调用getBean("peopleFactory")时,会返回一个People对象,而如果需要返回FactoryBean本身,则只需要使用getBean("&peopleFactory")即可。

FactoryBean在阅读Spring源码时经常可以见到,是很重要一个接口。

测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
People people = (People) ctx.getBean("people");
System.out.println(people);

People factoryPeople = (People) ctx.getBean("factoryPeople");
System.out.println(factoryPeople);

People instancePeople = (People) ctx.getBean("instancePeople");
System.out.println(instancePeople);

People setterPeople = (People) ctx.getBean("setterPeople");
System.out.println(setterPeople);

People people = (People) ctx.getBean("peopleFactory");
System.out.println(people);

PeopleFactory peopleFactory = (PeopleFactory) ctx.getBean("&peopleFactory");
System.out.println(peopleFactory);

}

结果:

1
2
3
4
5
6
People{name='normPeople', age=18}
People{name='factoryPeople', age=18}
People{name='instancePeople', age=18}
People{name='setterPeople', age=18}
People{name='weylan', age=18}
PeopleFactory{}