Spring学习笔记4——Bean
六、Spring Bean的配置和属性
什么是Bean?
组成应用程序并且由IOC容器管理的对象称之为Bean,Bean由Spring容器初始化、加载和管理
Spring支持两种配置文件格式:XML
和Properties
格式,一般用XML
注册和管理Bean间的依赖关系XML
配置文件的根元素是<beans>
,里面包含多个子元素<bean>
去定义不同的Bean,这些元素描述了Bean如何被装载进Spring容器
常用属性
-
id
唯一标识符 -
name
可有多个名称,用逗号/分号隔开 -
class
具体实现类,用全限定名 -
scope
设置作用域,其属性值有:默认值singleton(单例)、prototype(原型)、request、session和global Session -
constructor-arg
子元素,可用其传入构造参数进行实例化,index从0开始 -
property
子元素,用于调用 Bean 实例中的 Set 方法完成属性赋值,从而完成依赖注入。该元素的 name 属性指定 Bean 实例中的相应属性名 -
ref
和 等元素的子元索,该元素中的 bean 属性用于指定对 Bean 工厂中某个 Bean 实例的引用 -
value
和 等元素的子元素,用于直接指定一个常量值 -
list
、set
、map
分别用于封装List、Set、和Map类型属性的依赖注入 -
entry
Bean的实例化
Bean的实例化有三种方法:
- 构造器实例化
- 静态工厂方式实例化
- 实例工厂方式实例化
Bean的作用域(五种)
- singleton:单例模式,是Bean默认作用域,该模式下的Bean只有一个实例。只要id和该Bean定义相同了,就会返回同一个实例,常用于无会话状态的Bean(如DAO层、Service层)
- prototype:原型模式,该模式下通过Spring获取Bean时,容器都会创建新的实例
- request:在一次HTTP请求中,容器会返回该Bean的同一个实例,不同的HTTP请求返回不同的实例,该作用域只在当前HTTP Request内有效
- session:在一次HTTP Session中,容器会返回该Bean的同一个实例,不同的HTTP请求返回不同的实例,该作用域只在当前HTTP Session内有效
- global Session:在一个全局的HTTP Sesion中,容器会返回该Bean的同一个实例,该作用域仅在使用portlet context时有效
Bean的装配
Bean的装配相当是依赖注入,Spring容器有三种装配方式,继续XML、基于Annotation和自动装配。
- 基于XML
通常由两种实现方式,设值注入和构造注入。
- 设值注入:要求Bean的对应类必须有默认的无参构造方法和必须为要注入的属性提供setter方法。因为Spring实例化Bean时,先调用默认的构造方法实例化Bean对象,然后通过反射机制调用
setXxx()
进行属性的注入。在Spring配置文件中的<bean>
的<prototype>
为每个属性注入值
<bean id="stu" class="com.web.di.ba01.Student">-->
<property name="name" value="tt"/>-->
<property name="age" value="23"/>-->
<property name="school" ref="myschool"/>-->
</bean>-->
<!--引用类型的设值注入-->
<bean id="myschool" class="com.web.di.ba01.School">
<property name="name" value="清北"/>
<property name="address" value="西京"/>
</bean>
- 构造注入:在Spring配置文件中用
<constructor-arg>
定义构造方法的参数,可用value(或子元素)设置该参数的值
<!--使用name属性实现构造注入-->
<bean id="stu" class="com.web.di.ba01.Student">
<constructor-arg name="name" value="构造"/>
<constructor-arg name="age" value="13"/>
<constructor-arg name="school" ref="myschool"/>
</bean>
<!--使用index属性实现构造注入-->
<bean id="stu1" class="com.web.di.ba01.Student">
<constructor-arg index="0" value="0"/>
<constructor-arg index="1" value="1"/>
<constructor-arg index="2" ref="myschool"/>
</bean>
<!--构造注入创建文件对象-->
<bean id="myfile" class="java.io.File">
<constructor-arg name="parent" value="D:\xxx\yyy"/>
<constructor-arg name="child" value="zzz.txt"/>
</bean>
多配置文件
在开发中,可以有多个配置文件
优势:
- 减小配置文件大小,提高效率
- 避免多名开发人员调用时发生冲突
分配方式:
- 按功能模块:1*model=1*配置文件
- 按类的功能:如数据库相关、做事务、做service
注意:1、classpath表示类路径(class文件所在的目录)2、主次配置文件要放在同一个目录下,不然无法读取3、使用通配符时注意命名,不要主配置文件读取自己,导致死循环
- 基于Annotation
当Bean对象过多时,为了防止XML配置文件过于臃肿,我们还可以选择Annotation对Bean进行装配,常用的注解如下:
-
@Component
是一个泛化的概念,仅仅代表一个组件(Bean),可作用在任何层次,使用时将其标注在对应类上即可,有以下属性
- name:用于创建对象,相当于的name,唯一的,单例的;相当于
<bean id="myStudent" class="com.xxx.xxx.Student"/>
-
@Repository
作用与数据访问层(DAO层),功能同上 -
@Service
作用于业务层(Service层),功能同上 -
@Controller
作用于控制层(如Struts2的Action),功能同上 -
Autowired
对Bean的属性变量、属性的set方法和构造方法函数进行标注,配合对应的注解处理器完成Bean的自动配置工作。默认按照Bean的类型进行装配 -
Resource
作用和Autowired一样。但是默认按照Bean实例名称进行装配的。其中有两个重要的属性:
1、name
Spring将name解析为Bean实例名称,如果指定name属性,则按实例名称进行装载
2、type
Spring将type解析为实例类型,如果指定type属性,则按Bean类型进行装载
如果都不指定,则先按Bean实例名称装配,如匹配失败,再按Bean类型装配,如再匹配失败,则抛出NoSuchBeanDefintionException异常 -
Qualifier
和Autowired
配合使用,会将默认的按Bean类型装配改为按Bean实例名称装配,其实例名称有Qualifier
的参数指定
@Component、@Repository、@Service和@Controlle的区别:
@Repository
用于持久层、放在dao的实现类上,表示创建dao对象(可访问数据库)@Service
用于业务层,放在service的实现类上,表示创建service对象(做业务处理,有事务等功能)@Controlle
用于控制器,放在控制器(处理器)的实现类上,创建controlle对象(能接收用户提交的数据,显示请求处理结果)@Component
当无法确定是哪个层或具体对象时,用@Component
@Repository、@Service和@Controlle是给项目的对象分层的
实现步骤
- 加依赖:略
- 创建类、类中加注解
@Component(value = "myStudent")
public class Student {
//你要的代码
}
-
创建spring配置文件:声明组件扫描器的标签,指明注解在项目中的位置
<context:component-scan base-package="com.spring.ba01"/>
当扫描多个目标包时,有以下几种写法:
1.<context:component-scan base-package="com.spring.ba01"/><context:component-scan base-package="com.spring.ba02"/>
2.<context:component-scan base-package="com.spring.ba01;com.spring.ba02"/>
冒号可以换成逗号
3.base-package直接等于多个目标类的共同父包,但不建议写到com,包越多,越深都会导致扫描的速度下降 -
使用注解创建对象,创建容器ApplicationContext:略
简单类型赋值
@Value(value = "uzi")
private String name;
@Value(value = "23")
private Integer age;
注意:1、括号中的value
是String类型的;2、放在属性定义上时无需set方法;3、这个也可以放在set方法之上
也可以通过${}来对属性赋值
- 首先在项目中创建一个properties配置文件,在里面设置属性的键值对,如:
myname=lisi
myage=23
- 然后在xml中设置扫描其位置
<context:property=placeholder location="classpath:xxx.properties"/>
3.最后在对应的属性上通过注解来赋值
@Value("${myname}")
private String name;
@Value("${myage}")
private int age;
引用类型赋值
我们在Student中引用School
@Autowired
@Autowired
private School school;
@Autowired
是spring框架提供的注解;使用自动注入原理;默认使用byType自动注入;位置和简单类型赋值一致
byName:
@Autowired
@Qualifier(value = "mySchool")
private School school;
byName不但要@Autowired,还要再加入一个@Qualifier(value=“bean的id”)
别忘了School也要创建对象哦
@Autowired的属性——required
-
@Autowired(required = true)
是@Autowired的默认值,当引用类型赋值失败,程序报错并且终止执行,最好用这个,以便我们知道程序的问题 -
@Autowired(required = false)
当引用类型赋值失败,程序正常执行,但是其引用类型是null
@Resource
@Resource
:来自jdk,原理和@Autowired一致;默认byName;当byName注入赋值失败,则转换成byType
指定只使用byName的话: @Resource(name="bean的id")
//@Resource
@Resource(name="mySchool")
private School school;
3、自动装配
Spring容器自动装配相互写作的Bean间的关联关系,将一个Bean注入其他Bean的Property中。
使用时需要配置<bean>
的autowire
属性,其属性有如下五个值:
-
byName
根据Property的name自动装配,如果其name和另一个Bean的Property的name相同,则自动装配这个Bean到Property
<!--自动注入byName-->
<bean id="stu3" class="com.web.di.ba01.Student" autowire="byName">
<constructor-arg name="name" value="构造"/>
<constructor-arg name="age" value="13"/>
</bean>
<bean id="school" class="com.web.di.ba01.School" >
<property name="name" value="中科院"/>
<property name="address" value="广州1"/>
</bean>
应用类型的属性名和bean的id一致,且数据类型也是一致
-
byType
根据Property的type自动装配,如果type键注入另一个Bean的Property的type,则自动装配
<!--自动注入byType-->
<bean id="stu4" class="com.web.di.ba01.Student" autowire="byType">
<property name="name" value="aaa"/>
<property name="age" value="22"/>
</bean>
<bean id="primaryschool" class="com.web.di.ba01.PrimarySchool">
<property name="name" value="小学鸡"/>
<property name="address" value="机场"/>
</bean>
应用类型的数据类型和bean的class属性为同源(同源:引用类型的数据类型和bean的class值是一致的/是父子类关系/是接口和实现类关系)
primaryschool是school的子类哦~
需要注意的是,使用byType时,只能有一个符合条件的bean,不然会报异常,即声明了primaryschool就不要再声明school了
-
constructor
根据构造方法的参数的数据类型进行byType模式的自动装配 -
autodetect
如发现默认的构造方法,则用该模式,反之用byType模式 -
no
默认下,不使用自动装配,Bean依赖必须通过ref元素定义
下一篇: Android动画机制与使用技巧