Spring中Bean的配置方式:注解配置,xml配置,基于java的配置
1.注解配置(自动化装配bean)
Spring从两个角度来实现自动化装配:
1.1 组件扫描(component scanning):Spring会自动发现应用上下文中所创建的bean。
使用@Component注解表明该类会作为组件类,并告知Spring要为这个类创建bean。使用时记得启用组件扫描,方法有两种:
方法一:创建配置类,通过ComponentScan启用组件扫描
方法二:通过xml文件配置启用组件扫描<context:component-scan base-package="被扫描的组件"/>
1.2 自动装配(autowiring):Spring自动满足bean之间的依赖。
我们将bean自动添加到Spring容器中,只需用注解自动装配来满足bean之间的依赖关系。 如:@Autowired
2.基于java的配置
先介绍这个,最后着重介绍基于xml配置。、
其实在SpringBoot中就采用了Java类的配置方式。Java类的配置方式就是声明一个Java类来配置bean。
创建配置类,@Configuration注解表明这个类是一个注解类,该类包含了在Spring应用上下文中如何创建bean的细节。
简单的示例:
@Configuration
public class SpringBeanConfig{
/**
*配置bean时,在该方法上使用@Bean注解,可以自动注入到spring容器中
*相当于xml中的<bean>标签
*/
@Bean
public EmployeeDao getEmployeeDao(){
return new EmployeeDao();
}
}
3.xml配置方式:
基于xml的配置方式,我们需要借助于<bean>标签。
<bean id="唯一标识" name="别名" class="类的全路径" ></bean>
此时若要注入bean,方法有两种:
方法一:构造注入
<bean id="唯一标识" name="别名" class="类的全路径" >
<constructor-arg ref="注入的bean的标识"/>
</bean>
方法三:属性注入
<bean id="唯一标识" name="别名" class="类的全路径" >
<property name="属性名" ref="属性名所对应的对象的标识"/>
</bean>
实例化Bean的三种方式
1.1 使用构造方法
1.2 使用静态工厂方法【(直接创建)】
1.3 使用实例工厂方法【(需要先创建工厂,在创建实体)】
简单的示例:
要创建的对象:
package com.dsx.spring_bean;
public class Employee {
private Integer emp_id;
private String name;
private String phone;
private String email;
public Integer getEmp_id() {
return emp_id;
}
public void setEmp_id(Integer emp_id) {
this.emp_id = emp_id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
静态工厂
package com.dsx.spring_bean;
/**
* @ClassName: StaticFactory
* @Description: 模拟静态工厂
* @author 曰业而安
*/
public class StaticFactory {
public static Employee getEmp() {
return new Employee();
}
}
实例工厂
package com.dsx.spring_bean;
/**
* @ClassName: StaticFactory
* @Description: 模拟实例工厂
* @author 曰业而安
*/
public class InstanceFactory {
public Employee getEmp() {
return new Employee();
}
}
配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.2.xsd ">
<!--
第一种方式:使用默认构造函数创建
在spring的配置文件中使用bean标签,配以id和class属性之后,且没有其他属性和标签时
采用的就是默认构造函数创建bean对象,此时如果类中没有默认构造函数,则对象无法创建
-->
<bean id="employee_constructor" class="com.dsx.spring_bean.Employee">
<property name="phone" value="13101778369"></property>
</bean>
<!--
第二种方式: 使用普通工厂中的方法创建对象(使用某个类中的方法创建对象,并存入spring容器)
-->
<bean id="instanceFactory" class="com.dsx.spring_bean.InstanceFactory"></bean>
<bean id="employee_instanceFactory" factory-method="getEmp" factory-bean="instanceFactory"></bean>
<!--
第三种方式:使用工厂中的静态方法创建对象(使用某个类中的静态方法创建对象,并存入spring容器)
-->
<bean id="employee_staticFactory" class="com.dsx.spring_bean.StaticFactory" factory-method="getEmp"></bean>
<!--
bean的作用范围调整
bean标签的scope属性:
作用:用于指定bean的作用范围
取值:常用的就是单例的和多例的
singleton:单例的(默认值)
prototype:多例的
request: 作用于web应用的请求范围
session: 作用于web应用的会话范围
global-session:作用于集群环境的会话范围(全局会话范围),当不是集群环境时,它就是session
-->
</bean>
此时bean就被实例化并注入到了spring容器中。注意要确保有无参构造方法。
静态工厂,动态工厂(实例工厂)的介绍与区别
静态工厂直接可以通过静态方法来实例化一个对象。
动态工厂要先创建类对象,在通过工厂对象来调用创建实例对象的方法。
区别:
静态工厂初始化之前,工厂中的类已经被实例化放在工厂容器中
实例工厂在构造方法初始化时,会将类进行实例化放在工厂中。
bean属性注入的几种方式:
1. 使用构造函数注入(一般不用)
在bean标签内部使用的标签:<constructor-arg name="" ref="指定其引用的bean" .../>
标签中的属性:
type:用于指定要注入的数据的数据类型,该数据类型也是构造函数中某个或某些参数的类型
index:用于指定要注入的数据给构造函数中指定索引位置的参数赋值。索引的位置是从0开始
name(常用的):用于指定给构造函数中指定名称的参数赋值
=============以上三个用于指定给构造函数中哪个参数赋值============
value:用于提供基本类型和String类型的数据
ref:用于指定其他的bean类型数据,在spring的Ioc核心容器中出现过的bean对象
优势:
在获取bean对象时,注入数据是必须的操作,否则对象无法创建成功
弊端:
改变了bean对象的实例化方式,使我们在创建对象时,如果用不到这些数据,也必须提供
2. 使用set方法注入
bean标签内部使用标签:property
标签的属性
name:用于指定注入时所调用的set方法名称,去掉set之后首字母小写
value:用于提供基本类型和String类型的数据
ref:用于指定其他的bean类型数据。它指的就是在spring的Ioc核心容器中出现过的bean对象
优势:
创建对象时没有明确的限制,可以直接使用默认构造函数
弊端:
如果有某个成员必须有值,则获取对象时有可能set方法没有执行
3. p命名空间注入
注意:p名称空间注入,需要有无参构造方法
4. 使用注解注入
@Value、@Resource、@Qualifier
bean的作用域:
类别 | 说明 |
singleton | 默认值,在Spring容器中仅存在一个Bean实例,Bean以单例模式存在 |
prototype | 每次从容器中调用Bean时,都返回一个新的实例。 |
request | 每次HTTP请求都会创建一个新的Bean,该作用域仅适用于WebApplicationContext环境 |
session | 同一个Http Session共享一个Bean,不同Session使用不同的Bean,仅适用于WebApplicationContext环境 |
globalSession | 一般用于Protlet应用环境,该作用域仅适用于WebApplicationContext环境 |
注意:
当作用域为prototype时,Spring容器不能够对Bean的整个生命周期进行管理(当bean为多例时,其自定义的destroy方法是不会被调用的,但初始化方法会被调用),最终对象的销毁和资源回收由使用者负责。singleton则整个生命周期由容器负责。
Bean的生命周期
生命周期图解释
1.instantiate bean对象实例化
2.populate properties 封装属性
3.如果Bean实现BeanNameAware 执行 setBeanName
4.如果Bean实现BeanFactoryAware 执行setBeanFactory ,获取Spring容器
5.如果存在类实现 BeanPostProcessor(后处理Bean) ,执行postProcessBeforeInitialization
6.如果Bean实现InitializingBean 执行 afterPropertiesSet
7.调用<bean init-method="init"> 指定初始化方法 init
8.如果存在类实现 BeanPostProcessor(处理Bean) ,执行postProcessAfterInitialization执行业务处理
9.如果Bean实现 DisposableBean 执行 destroy
10.调用<bean destroy-method="customerDestroy"> 指定销毁方法 customerDestroy
Spring上下文中的Bean生命周期总结如下:
(1)实例化Bean:
对于BeanFactory容器,当客户向容器请求一个尚未初始化的bean时,或初始化bean的时候需要注入另一个尚未初始化的依赖时,容器就会调用createBean进行实例化。对于ApplicationContext容器,当容器启动结束后,通过获取BeanDefinition对象中的信息,实例化所有的bean。
(2)设置对象属性(依赖注入):
实例化后的对象被封装在BeanWrapper对象中,紧接着,Spring根据BeanDefinition中的信息 以及 通过BeanWrapper提供的设置属性的接口完成依赖注入。
(3)处理Aware接口:
接着,Spring会检测该对象是否实现了xxxAware接口,并将相关的xxxAware实例注入给Bean:
①如果这个Bean已经实现了BeanNameAware接口,会调用它实现的setBeanName(String beanId)方法,此处传递的就是Spring配置文件中Bean的id值;
②如果这个Bean已经实现了BeanFactoryAware接口,会调用它实现的setBeanFactory()方法,传递的是Spring工厂自身。
③如果这个Bean已经实现了ApplicationContextAware接口,会调用setApplicationContext(ApplicationContext)方法,传入Spring上下文;
(4)BeanPostProcessor:
如果想对Bean进行一些自定义的处理,那么可以让Bean实现了BeanPostProcessor接口,那将会调用postProcessBeforeInitialization(Object obj, String s)方法。由于这个方法是在Bean初始化结束时调用的,所以可以被应用于内存或缓存技术;
(5)InitializingBean 与 init-method(bean的初始化):
如果Bean在Spring配置文件中配置了 init-method 属性,则会自动调用其配置的初始化方法。
(6)如果这个Bean实现了BeanPostProcessor接口,将会调用postProcessAfterInitialization(Object obj, String s)方法;
以上几个步骤完成后,Bean就已经被正确创建了,之后就可以使用这个Bean了。
(7)DisposableBean:
当Bean不再需要时,会经过清理阶段,如果Bean实现了DisposableBean这个接口,会调用其实现的destroy()方法;
(8)destroy-method:
最后,如果这个Bean的Spring配置中配置了destroy-method属性,会自动调用其配置的销毁方法。
如有不足,欢迎留言指正。望不吝赐教。。。