Spring Bean
本小记中学习的目标
-
Spring Bean如何配置
-
Bean的实例的过程
-
Bean的作用域有哪些
-
Bean的生命周期
-
Bean如何装配有哪些装配方式
一、Spring Bean的配置简单介绍
Spring可以看作一个工厂,这个工厂用来生产和管理Spring容器中的Bean。如果需要交由Spring来生产和管理Bean,需要先定义好规则,这个规则则是在Spring的配置文件中定义。
Spring的配置文件支持两种方式,一是XML文件(常用),另一个是Properties文件
回顾一下原来定义的xml配置文件
<?
xml
version=
"1.0"
encoding=
"UTF-8"
?>
xsi:schemaLocation=
"
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
"
>
<!-- 把
Dao
的实现类交由Spring容器进行管理,让Spring来创建它 -->
<
bean
class=
"com.xiaoxie.dao.impl.TestDIDaoImpl"
id=
"testDIDao"
/>
<!-- 在Service中使用构造方法进行注入依赖有对象 -->
<
bean
class=
"com.xiaoxie.service.impl.TestDIServiceImpl"
id=
"testDIService"
>
<
constructor-arg
name=
"testDIDao"
ref=
"testDIDao"
/>
</
bean
>
<!-- 在Service中使用setter方法进行注入依赖的对象 -->
<
bean
class=
"com.xiaoxie.service.impl.TestDIServiceImpl1"
id=
"testDIService1"
>
<
property
name=
"
tesDIDao1"
ref=
"testDIDao"
></
property
>
</
bean
>
</
beans
>
我们可以看一下这个配置文件中的结构
根标签:<beans>
定义具体bean的标签<bean>,可以有多个,每一个<bean>会对应一个Bean,在这个标签上会描述Bean是怎样装配到Spring容器中的
<bean>标签内的子元素及其属性就是用来对Bean进行描述的
<bean>标签中常用的属性及其子元素
id:这个要保证唯一,在代码中通过这个唯一的id来指向具体的Bean
class:Bean对应的具体实现类,这里必须是类的全路径名称
scope:指定了Bean实例的作用域
<constructor-arg>:使用构造方法注入,这里用来指定构造方法的参数
<property>:设置一个属性
<list>:<property>元素的子元素,用来封装list或数组类型的依赖注入
<map>:<property>元素的子元素,用来封装map类型的依赖注入
<entry>:<map>元素的子元素,用来设置一个键值对
<set>:<property>元素的子元素,用来封装set类型的依赖注入
二、Bean的实例化
我们在编程时如果要使用某个对象,首先要对它进行实例化同样地在Spring中如果要使用某人Bean也必须要实例化它,这个实例化的过程通过Spring的容器完成。
Spring实例化Bean有三种方式:构造方法实例化(常用)、静态工厂实例化、实例工厂实例化
构造方法实例化
何为构造方法实例化,也就是说Spring容器调用Bean对应类的无参构造函数,从而实现对Bean的实例化。
实列
1.建立Maven的jar工程
2.在pom.xml中添加相关的核心依赖
<
dependencies
>
<!-- 添加Spring核心依赖包 Context -->
<
dependency
>
<
groupId
>org.springframework
</
groupId
>
<
artifactId
>spring-context
</
artifactId
>
<
version
>5.0.2.RELEASE
</
version
>
</
dependency
>
<!-- commons-logging-1.2 -->
<
dependency
>
<
groupId
>commons-logging
</
groupId
>
<
artifactId
>commons-logging
</
artifactId
>
<
version
>1.2
</
version
>
</
dependency
>
</
dependencies
>
3.新建一个bean类,在src/main/java下新建类:com.xiaoxie.dao.Person.java
package com.xiaoxie.dao;
public
class Person {
private String
name;
private Integer
age;
public Person() {
System.
out.println(
"调用无参构造函数");
}
public Person(String
name,Integer
age){
System.
out.println(
"调用有参的构造函数");
this.
name =
name;
this.
age =
age;
}
public String getName() {
return
name;
}
public
void setName(String
name) {
this.
name =
name;
}
public Integer getAge() {
return
age;
}
public
void setAge(Integer
age) {
this.
age =
age;
}
@Override
public String toString() {
return
"[Person:name= " +
this.
name +
" ,age=" +
this.
age +
"]";
}
}
4.新增Spring容器的xml配置文件,在src/main/resources下新增beans.xml的Spring配置文件beans.xml
<?
xml
version=
"1.0"
encoding=
"UTF-8"
?>
xsi:schemaLocation=
"
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
"
>
<
bean
class=
"com.xiaoxie.dao.Person"
id=
"person"
>
<
property
name=
"
name"
value=
"小谢"
/>
<
property
name=
"
age"
value=
"18"
/>
</
bean
>
</
beans
>
5.建立测试类进行测试,在src/test/java下,建立测试类com.xiaoie.test.InstanceTest.java
package com.xiaoxie.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.xiaoxie.dao.Person;
public
class InstanceTest {
public
static
void main(String[]
args) {
instanceByDefaultConsturct();
}
private
static
void instanceByDefaultConsturct() {
ApplicationContext
context =
new ClassPathXmlApplicationContext(
"beans.xml");
Person
person = (Person)
context.getBean(
"person");
System.
out.println(
person);
}
}
6.运行测试类,在控制台打印的结果如下:
调用无参构造函数
[Person:name= 小谢 ,age=18]
从运行的结果可以看出来Spring容器在实例化的时候会调用Bean类的无参构造函数
静态工厂实例化
静态工厂实例化,需要新增一个工厂类,使用一个静态方法来创建Bean的实例,在Spring的配置文件中需要指定工厂类,且需要在factory-method属性中指定工帮类中的静态实例化方法
实例
1.在工程中添加一个静态工厂类:com.xiaoxie.dao.factory.PersonStaticFactory
package com.xiaoxie.dao.factory;
import com.xiaoxie.dao.Person;
public
class PersonStaticFactory {
private
static Person
person =
new Person(
"张三",20);
public
static Person getInstance() {
System.
out.println(
"调用静态工厂类实例化Bean");
return
person;
}
}
2.修改Spring的配置文件,把调用静态工厂类配置为对应的bean
<?
xml
version=
"1.0"
encoding=
"UTF-8"
?>
xsi:schemaLocation=
"
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
"
>
<
bean
class=
"com.xiaoxie.dao.Person"
id=
"person"
>
<
property
name=
"
name"
value=
"小谢"
/>
<
property
name=
"
age"
value=
"18"
/>
</
bean
>
<!-- 静态实例化bean -->
<
bean
class=
"com.xiaoxie.dao.factory.PersonStaticFactory"
id=
"personStaticFactory"
factory-method=
"
getInstance"
/>
</
beans
>
从这里的配置可以看到这里的bean配置了工厂类,并且在配置bean的属性中添加factory-method属性,这个属性用来指定静态实例化的方法(返回实例的方法)
3.在测试类中添加新的方法,并在main方法中调用测试
package com.xiaoxie.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.xiaoxie.dao.Person;
public
class InstanceTest {
public
static
void main(String[]
args) {
//instanceByDefaultConsturct();
instanceByStaticFactory();
}
/**
* 无参构造函数实例化
*/
private
static
void
instanceByDefaultConsturct() {
ApplicationContext
context =
new ClassPathXmlApplicationContext(
"beans.xml");
Person
person = (Person)
context.getBean(
"person");
System.
out.println(
person);
}
/**
* 静态工厂实列化
*/
private
static
void instanceByStaticFactory() {
ApplicationContext
context =
new ClassPathXmlApplicationContext(
"beans.xml");
Person
person = (Person)
context.getBean(
"personStaticFactory");
System.
out.println(
person);
}
4.运行测试类,在控制台打印结果如下
调用无参构造函数
调用有参的构造函数
调用静态工厂类实例化Bean
[Person:name= 张三 ,age=20]
从这里可以看到,第一个调用无参构造函数是第一个bean配置的调用,第二个调用有参构造函数是由于在实例化的工厂类中创建对象的是使用的是有参构造函数进行的,第三个输出表示确实是调用了静态的工厂实例化方法来获取bean的实例
实例工厂实例化
这个方式与静态静态工厂实例化类似,只是我们这个时候需要创建一个工厂类,在这个工厂类中有一个方法直接返回创建好的实列对象。
实例
1.创建一个工厂类,com.xiaoxie.dao.factory.PersonFactory
package com.xiaoxie.dao.factory;
import com.xiaoxie.dao.Person;
public
class PersonFactory {
public Person getInstance() {
System.
out.println(
"调用实例化方法");
return
new Person(
"李四",22);
}
}
2.在Spring配置文件中进行实例化Bean的配置
<?
xml
version=
"1.0"
encoding=
"UTF-8"
?>
xsi:schemaLocation=
"
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
"
>
<
bean
class=
"com.xiaoxie.dao.Person"
id=
"person"
>
<
property
name=
"
name"
value=
"小谢"
/>
<
property
name=
"
age"
value=
"18"
/>
</
bean
>
<!-- 静态实例化bean -->
<
bean
class=
"com.xiaoxie.dao.factory.PersonStaticFactory"
id=
"personStaticFactory"
factory-method=
"
getInstance"
/>
<!-- 配置工厂 -->
<
bean
class=
"com.xiaoxie.dao.factory.PersonFactory"
id=
"personFactory"
/>
<!-- 配置实例化bean,factory-bean指定配置的工厂;factory-method指定实例化的方法 -->
<
bean
class=
"com.xiaoxie.dao.factory.PersonFactory"
factory-bean=
"personFactory"
factory-method=
"
getInstance"
id=
"personFactoryInstance"
/>
</
beans
>
这里配置时需要先配置一个工厂,再配置实例化bean的信息
3.在测试类中新增方法进行测试
package com.xiaoxie.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.xiaoxie.dao.Person;
public
class InstanceTest {
public
static
void main(String[]
args) {
//instanceByDefaultConsturct();
//instanceByStaticFactory();
instanceByFactory();
}
/**
* 无参构造函数实例化
*/
private
static
void
instanceByDefaultConsturct() {
ApplicationContext
context =
new ClassPathXmlApplicationContext(
"beans.xml");
Person
person = (Person)
context.getBean(
"person");
System.
out.println(
person);
}
/**
* 静态工厂实列化
*/
private
static
void
instanceByStaticFactory() {
ApplicationContext
context =
new ClassPathXmlApplicationContext(
"beans.xml");
Person
person = (Person)
context.getBean(
"personStaticFactory");
System.
out.println(
person);
}
/**
* 实例化bean
*/
private
static
void instanceByFactory() {
ApplicationContext
context =
new ClassPathXmlApplicationContext(
"beans.xml");
Person
person = (Person)
context.getBean(
"personFactoryInstance");
System.
out.println(
person);
}
}
4.运行测试类,在控制台打印结果如下
调用无参构造函数
调用有参的构造函数
调用静态工厂类实例化Bean
调用实例化方法
调用有参的构造函数
[Person:name= 李四 ,age=22]
可以看到,第一句打印的第一个配置bean的时候调用无参的构造函数,第二句打印是在配置静态工厂类实例化bean时创建对象调用了有参的构造函数,第三句打印是表示调用了静态工厂实例化指定的方法时打印的结果,第四句打印是在配置实例化bean时调用了工厂类指定的实例化方法,第五句打印是在工厂类实例化方法中调用了有参的构造方法
三、Bean的作用域
在Spring中不仅仅可以实例化Bean,同时也可以指定Bean的作用域(也可以理解为它的生效范围)。
Spring中Bean的作用域有如下:
singleton:这个是默认的,使用它表示使用Spring定义的Bean在Spring容器中只有一个Bean实例
prototype:这个与singleton相反,每次获取由它来定义的Bean时,容器都会创建一个新的Bean实例
request:仅在web Spring应用程序上下文中使用,每次请求时返回一个Bean实例,不同的请求返回不同的Bean实例
session:仅在web Spring应用程序上下文中使用,在HTTP Session中,容器返回同一个Bean实例
application:仅在web Spring应用程序上下文中使用,为每个ServletContext对象创建一个实例
websocket:仅在web Spring应用程序上下文中使用,为每个WebSocket对象创建一个Bean实例
后面的四种都是在Web Spring应用程序上下文中使用的,先重点了解下前两种
singleton作用域
这个时候Spring IoC容器生成和管理的Bean实例是共享的Bean实例,有一点要注意,当在配置文件中不指定作用域时,默认则为singleton
我们可以建立一个Bean的类,让它什么都不做
package com.xiaoxie.dao;
public
class BeanDao {
}
在Spring配置文件中新增如下bean配置
<!--
指定bean的作用域为singleton,当不做指定配置时默认也为singleton,表示是单列每次返回的是同一实例
指定bean的作用域为prototype,表示Spring每次会返回一个新的对象
-->
<
bean
class=
"com.xiaoxie.dao.BeanDao"
id=
"beanDao"
scope=
"singleton"
/>
在测试类中新增方法进行测试
/**
* 作用域的测试方法
*/
private
static
void scopeTest() {
ApplicationContext
context =
new ClassPathXmlApplicationContext(
"beans.xml");
BeanDao
beanDao = (BeanDao)
context.getBean(
"beanDao");
System.
out.println(
"beanDao对象:" +
beanDao);
BeanDao
beanDao1 = (BeanDao)
context.getBean(
"beanDao");
System.
out.println(
"beanDao1对象:" +
beanDao1);
}
在main方法中调用这个方法,控制台打印结果如下
beanDao对象:com.xiaoxie.dao.BeanDao@4d0f2471
beanDao1对象:com.xiaoxie.dao.BeanDao@4d0f2471
我们可以看到当我们两次获取同一个bean时,返回的对象是完全一样的,说明singleton指定的作用域Spring容器会返回唯一共享的Bean
prototype作用域
按归照上面的例子我们把配置文件中的bean的配置,修改为如下
<!--
指定bean的作用域为singleton,当不做指定配置时默认也为singleton,表示是单列每次返回的是同一实例
指定bean的作用域为prototype,表示Spring每次会返回一个新的对象
-->
<
bean
class=
"com.xiaoxie.dao.BeanDao"
id=
"beanDao"
scope=
"prototype"
/>
在不修改测试方法的情况下再次运行测试类,结果在控制台打印的结果如下:
beanDao对象:com.xiaoxie.dao.BeanDao@4d0f2471
beanDao1对象:com.xiaoxie.dao.BeanDao@7133da86
明细的可以看到这次在两次请求获取对象实例时得到的是不同的对象,说明在使用prototype这个作用域时Spring会每次创建新的对象返回
四、Bean生命周期简介
对于一个对象的生命周期,一般包含创建(实例化,初始化)、使用、销毁等阶段。在Spring中Bean对象生命周期也分别有这几个阶段,并且Spring中提供了对外接口,允许我们 在实例化、初始化、销毁的前后添加一些自己定义的操作。
Spring容器对于作用域为singleton的Bean,Spring可以精确地地知Bean是何时被创建、何时初始化、何时被销毁,但是对于作用域是prototype的Bean,Spring只负责创建Bean,当容器完成了Bean的创建后,Bean的实例就会交由客户的代码作管理,Spring容器不会再负责跟踪它的使用过程。
Bean生命周期的过程如下
1.根据Spring Bean的配置文件,实例化一个bean
2.对实例化的Bean进行依赖注入(对bean的属性进行初始化)
3.Bean如果实现了BeanNameAware接口,会调用实现的方法setBeanName(String beanId),这里的参数传入的是Spring Bean配置文件中配置的bean的id
4.Bean如果实现了BeanFactoryAware接口,会调用实现的方法setBeanFactory,这个方法传入的参数是当前Spring工厂实例的引用
5.Bean如果实现了ApplicationContextAware接口,会调用实现的方法setApplicationContext(ApplicationContext)方法,这个方法传入的是Spring上下文实例的引用
6.Bean关联了BeanPostProcessor接口,会调用初始化方法PostProcessBeforeInitialization(Object obj,String s)对Bean进行相应的操作
7.Bean实现了InitializingBean接口,会调用afterPropertiesSet方法
8.Bean的配置文件中配置了init-method属性,会自动调用配置的初始化方法
9.Bean关联了BeanPostProcessor接口,会调用postProcessAfterInitialization(Object obj,String s)方法,这里是在Bean初始化结束之后调用。
到这里Bean就已经初始化完成了,可以正常使用Bean了
10.当Bean不再需要时会进入销毁阶段,如果Bean实现了DisposableBean接口,则会调用实现方法destory方法将Spring中的Bean销毁
11.如果在Bean的配置文件中通过destory-method属性指定了Bean的销毁方法,会调用其配置的销毁方法进行销毁
在Spring中,通过实现指定的接口或在Bean的配置文件中对指定bean设置具体的元素,可以对Bean的生命周期过程产生额外需要的影响。但是在实际的使用过程中尽量不要太过多地去使用Bean实现接口,这样的话使得自己的代码与Spring联系的太过紧密。
实例
1.新增一个Bean类:com.xiaoxie.dao.LifeBean.java
package com.xiaoxie.dao;
public
class LifeBean {
public
void initLifeBean() {
System.
out.println(
this.getClass().getName() +
"执行自定义的初始化方法!");
}
public
void destroyLifeBean() {
System.
out.println(
this.getClass().getName() +
"执行自定义的销毁方法!");
}
}
2.新增Spring配置文件lifebeans.xml,在scr/main/resources下新增
<?
xml
version=
"1.0"
encoding=
"UTF-8"
?>
xsi:schemaLocation=
"
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
"
>
<!-- 配置了对应的bean,并指定了初始化要执行的初始化方法和销毁方法 -->
<
bean
class=
"com.xiaoxie.dao.LifeBean"
id=
"lifeBean"
init-method=
"
initLifeBean"
destroy-method=
"
destroyLifeBean"
/>
</
beans
>
3.在测试类中新增测试方法
/**
* 作用域的测试方法
*/
private
static
void
scopeTest() {
ApplicationContext
context =
new ClassPathXmlApplicationContext(
"beans.xml");
BeanDao
beanDao = (BeanDao)
context.getBean(
"beanDao");
System.
out.println(
"beanDao对象:" +
beanDao);
BeanDao
beanDao1 = (BeanDao)
context.getBean(
"beanDao");
System.
out.println(
"beanDao1对象:" +
beanDao1);
}
4.在main方法中调用这个测试方法并运行,控制打印内容顺序如下
加载配置文件,初始化Spring容器
com.xiaoxie.dao.LifeBean执行自定义的初始化方法!
执行getBean获取对象之前
执行getBean获取对象之后:com.xiaoxie.dao.LifeBean@1757cd72
关闭容器,销毁Bean对象
com.xiaoxie.dao.LifeBean执行自定义的销毁方法!
从上面打印的结果可以看到,在加载Spring的配置文件初始化Bean时会执行自己配置的初始化方法;在关闭容器时,会执行自己配置的销毁方法
五、Bean的装配方式简介
Bean的装配,可以简单的理解为Bean的注入,那么这里说的Bean的装配方式也就是指的Bean的注入方式
Spring容器,支持Bean的装配方式有如下几种:
1.通过Spring的xml配置文件
2.基于注解的装配(常用)
3.自动装配
通过Spring的xml配置文件进行装配
Spring中提供了两种基于xml配置文件的装配方式:使用构造方法注入;使用属性的setter方法注入
使用构造方法进行注入Bean时,Bean的实现类需要提供带参的构造方法,并在配置文件中使用<bean>元素的子元素<constructor-arg>来定义构造方法的参数。
在使用setter方法注入方式装配Bean时,Bean的实现类需要提供一个默认无参的构造方法,并为需要注入的属性提供对应的setter方法
实例
1.新增一个Maven的jar工程
2.在pom.xml中添加对Spring的相关依赖
<
dependencies
>
<!-- 添加Spring核心依赖包 Context -->
<
dependency
>
<
groupId
>org.springframework
</
groupId
>
<
artifactId
>spring-context
</
artifactId
>
<
version
>5.0.2.RELEASE
</
version
>
</
dependency
>
<!-- commons-logging-1.2 -->
<
dependency
>
<
groupId
>commons-logging
</
groupId
>
<
artifactId
>commons-logging
</
artifactId
>
<
version
>1.2
</
version
>
</
dependency
>
</
dependencies
>
3.新增Bean的实现类,com.xiaoxie.dao.Student
package com.xiaoxie.dao;
import java.util.List;
import java.util.Map;
public
class Student {
private String
name;
private Integer
age;
private List<String>
hobbyList;
private Map<String,String>
tourMap;
private String[]
school;
//无参构造方法
public Student() {
System.
out.println(
"调用无参构造方法...");
}
//有参构造方法
public Student(String
name, Integer
age, List<String>
hobbyList, Map<String, String>
tourMap, String[]
school) {
System.
out.println(
"调用有参构造方法...");
this.
name =
name;
this.
age =
age;
this.
hobbyList =
hobbyList;
this.
tourMap =
tourMap;
this.
school =
school;
}
//setter和getter方法
public String getName() {
return
name;
}
public
void setName(String
name) {
System.
out.println(
"调用setName方法...");
this.
name =
name;
}
public Integer getAge() {
return
age;
}
public
void setAge(Integer
age) {
System.
out.println(
"调用setAge方法...");
this.
age =
age;
}
public List<String> getHobbyList() {
return
hobbyList;
}
public
void setHobbyList(List<String>
hobbyList) {
System.
out.println(
"调用setHobbyList方法...");
this.
hobbyList =
hobbyList;
}
public Map<String, String> getTourMap() {
return
tourMap;
}
public
void setTourMap(Map<String, String>
tourMap) {
System.
out.println(
"调用setTourMap方法...");
this.
tourMap =
tourMap;
}
public String[] getSchool() {
return
school;
}
public
void setSchool(String[]
school) {
System.
out.println(
"调用setSchool方法...");
this.
school =
school;
}
@Override
public String toString() {
return
"Student:name=" +
name +
",age=" +
age +
",hobbyList=" +
hobbyList +
"tourMap=" +
tourMap +
"school=" +
school;
}
}
4.新增Spring的Bean配置文件beans.xml
<?
xml
version=
"1.0"
encoding=
"UTF-8"
?>
xsi:schemaLocation=
"
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
"
>
<!-- 使用构造函数的方式进行注入 -->
<
bean
class=
"com.xiaoxie.dao.Student"
id=
"student1"
>
<
constructor-arg
name=
"name"
value=
"小谢"
/>
<
constructor-arg
name=
"age"
value=
"25"
/>
<
constructor-arg
name=
"hobbyList"
>
<
list
>
<
value
>看书
</
value
>
<
value
>旅游
</
value
>
<
value
>电影
</
value
>
</
list
>
</
constructor-arg
>
<
constructor-arg
name=
"tourMap"
>
<
map
>
<
entry
key=
"hunan"
value=
"湖南"
/>
<
entry
key=
"jiangxi"
value=
"江西"
/>
<
entry
key=
"shanxi"
value=
"陕西"
/>
</
map
>
</
constructor-arg
>
<
constructor-arg
name=
"school"
>
<
array
>
<
value
>湖南第一高级中学
</
value
>
<
value
>湖南大学
</
value
>
<
value
>南昌大学
</
value
>
<
value
>西安交通大学
</
value
>
</
array
>
</
constructor-arg
>
</
bean
>
<!-- 使用setter方法进行注入 -->
<
bean
class=
"com.xiaoxie.dao.Student"
id=
"student2"
>
<
property
name=
"
name"
value=
"张三"
/>
<
property
name=
"
age"
value=
"26"
/>
<
property
name=
"
hobbyList"
>
<
list
>
<
value
>唱歌
</
value
>
<
value
>旅游
</
value
>
<
value
>电影
</
value
>
</
list
>
</
property
>
<
property
name=
"
tourMap"
>
<
map
>
<
entry
key=
"hunan"
value=
"湖南"
/>
<
entry
key=
"shanxi"
value=
"陕西"
/>
</
map
>
</
property
>
<
property
name=
"
school"
>
<
array
>
<
value
>湖南第一高级中学
</
value
>
<
value
>湖南大学
</
value
>
<
value
>西安交通大学
</
value
>
</
array
>
</
property
>
</
bean
>
</
beans
>
5.建立测试类,com.xiaoxie.test.AssemblingTest
package com.xiaoxie.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.xiaoxie.dao.Student;
public
class AssemblingTest {
public
static
void main(String[]
args) {
assemblingByXml();
}
private
static
void assemblingByXml() {
ApplicationContext
context =
new ClassPathXmlApplicationContext(
"beans.xml");
System.
out.println(
"使用构造方法进行装配");
Student
student1 = (Student)
context.getBean(
"student1");
System.
out.println(
student1);
System.
out.println(
"使用setter方法进行装配");
Student
student2 = (Student)
context.getBean(
"student2");
System.
out.println(
student2);
}
}
6.运行测试类,控制台打印结果如下:
调用有参构造方法...
调用无参构造方法...
调用setName方法...
调用setAge方法...
调用setHobbyList方法...
调用setTourMap方法...
调用setSchool方法...
使用构造方法进行装配
Student:name=小谢,age=25,hobbyList=[看书, 旅游, 电影]tourMap={hunan=湖南, jiangxi=江西, shanxi=陕西}school=[Ljava.lang.String;@957e06
使用setter方法进行装配
Student:name=张三,age=26,hobbyList=[唱歌, 旅游, 电影]tourMap={hunan=湖南, shanxi=陕西}school=[Ljava.lang.String;@32502377
从上面的打印结果可知
在Spring容器初始化的时候,第一个bean为student1,它是使用构造方法进行装配,所以先调用了有参的构造方法,第二个bean为student2,它是使用setter方法进行装配,所以先调用无参的构造方法,并在之后调用了对应的setter方法进行属性的初始化
基于注解的装配
使用注解的方式装配是开发过程中常用的方式。因为使用xml配置文件的方式会导致xml配置文件过于庞大不便于维护。
关于Spring框架中常用的注解
一、@Component
这个注解它表示一个组件对象Bean(这个并不常用,为了类的标注更加清晰,一般使用二、三、四所示注解来使用)
实例
1.新增一个Bean类,com.xiaoxie.dao.annotation.Employee
package com.xiaoxie.dao.annotation;
import org.springframework.beans.factory.annotation.Value;
@Component
public
class Employee {
@Value(
"小谢")
private String
name;
@Value(
"技术部")
private String
deptName;
@Override
public String toString() {
return
"Employee[name= "+
name +
", deptName=" +
deptName +
"]";
}
}
注意:这里的@Component,相当于@Component("employee")或@Component(value="employee"), 也就是相当于在Spring的bean配置中指定bean的id为employee(类名,首字母小写)
@Value:表示在属性上注入简单的值
@Value(
"小谢")
private String
name;
相当于 private String name = "小谢";
2.依然需要Spring的Bena配置文件,但是在Spring的配置文件中不是做bean的注入配置,而是指定Spring容器扫描的包
<?
xml
version=
"1.0"
encoding=
"UTF-8"
?>
xmlns:xsi=
"http://www.w3.org/2001/XMLSchema-instance"
xmlns:context=
"http://www.springframework.org/schema/context"
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.3.xsd"
>
<
context:component-scan
base-package=
"com.xiaoxie.dao.annotation"
/>
</
beans
>
注意:在Eclipse中需要把Context命名空间加入进去

3.在测试类中新增方法如下
private
static
void annotationWithComponentTest() {
ApplicationContext
context =
new ClassPathXmlApplicationContext(
"annotationBeans.xml");
Employee
employee = (Employee)
context.getBean(
"employee");
System.
out.println(
employee);
}
4.在main方法中调用这个方法,控制台打印结果如下:
Employee[name= 小谢, deptName=技术部]
二、@Repository
这个注解是把数据访问层的类标识为bean,它的功能与@Component相同
三、@Service
这个注解是把业务逻辑组件类标识为bean,它的功能与@Component相同
四、@Controller
这个注解用于把控制器组件标识为bean,它的功能与@Component相同
五、@Autowired
这个注解可以用于类成员变量、方法及构造函数进行标注,它会完成自动装配的工作,它是默认按Bean的类型进行装配的,如果希望按名称业装配需要与@Qualifier注解一起使用
六、@Resource
这个注解与@Autowired的功有一样,区别在于这个注解是默认按名称来做装配的,当找不到名称匹配的Bean时才会使用类型来装配,它有两个属性name(指定Bean的实例名称)、type(指定Bean的类型)
注意:如果需要使用这个注解必须在pom.xml文件中依赖如下jar包
<
dependency
>
<
groupId
>javax.annotation
</
groupId
>
<
artifactId
>javax.annotation-
api
</
artifactId
>
<
version
>1.3.1
</
version
>
</
dependency
>
七、@Qualifier
这个注解与@Autowired注解配合使用,当@Autowired需要按名称来装配时与这个注解一起使用,Bean的实例名称由这个注解的参数指定
实例
1.新增一个Dao接口,com.xiaoxie.annotation.UserDao
package com.xiaoxie.annotation.dao;
public
interface UserDao {
void save();
}
2.新增一个Dao实现类,com.xiaoxie.annotation.USerDaoImplpackage
package com.xiaoxie.annotation.dao.impl;
import org.springframework.stereotype.Repository;
import com.xiaoxie.annotation.dao.UserDao;
@Repository(
"userDao")
public
class UserDaoImpl
implements UserDao {
@Override
public
void save() {
System.
out.println(
"用户保存~~~");
}
}
3.新增一个service接口,com.xiaoxie.annotation.UserService
package com.xiaoxie.annotation.service;
public
interface UserService {
void save();
}
4.新增一个service的实现类,com.xiaoxie.annotation.UserServiceImpl
package com.xiaoxie.annotation.service.impl;
import javax.annotation.Resource;
import org.springframework.stereotype.Service;
import com.xiaoxie.annotation.dao.UserDao;
import com.xiaoxie.annotation.service.UserService;
@Service(
"userService")
public
class UserServiceImpl
implements UserService{
//@Autowired:这个注解可以自动注入,按照Bean的类型装配
@Resource(name=
"userDao")
private UserDao
userDao;
@Override
public
void save() {
System.
out.println(
"service中调用dao中的save方法~~");
userDao.save();
}
}
5.在Spring的bean配置文件中设置bean扫描的包
<
context:component-scan
base-package=
"com.xiaoxie.annotation"
/>
6.新增测试方法
private
static
void annotationTest() {
ApplicationContext
context =
new ClassPathXmlApplicationContext(
"annotationBeans.xml");
UserController
userController = (UserController)
context.getBean(
"userController");
userController.save();
}
7.在测试类的main函数中调用测试方法,控制台打印结果如下
controll中调用service中的save方法~~~
service中调用dao中的save方法~~
用户保存~~~