Spring IoC容器可以创建、装配、配置应用组件对象,这里的组件对象称为Bean。
1.Bean 的配置
Spring可以看作一个工厂,用于生产和管理Spring容器中的Bean。
如果要使用这个工厂生产和管理Bean,需要将Bean配置在Spring的配置文件中。支持 XML 和 Properties 两种格式的配置文件,常用 XML格式。
属性或子元素 | 描述 |
---|---|
id | Bean在BeanFactory中的唯一标识,在代码中通过BeanFactory获取Bean实例时需要依次作为索引名称 |
class | Bean的具体实现类,例如dao.TestDIDaoImpl |
scope | 指定Bean实例的作用域 |
< property> | 用于设置一个属性。name 指定Bean实例中相应的属性名称、value 指定Bean的属性值、ref 指定属性对BeanFactory中其他Bean的引用关系 |
< constructor-arg> | 使用构造方法注入,指定构造方法的参数。index指定参数的序号,ref指定对BeanFactory中其他Bean的引用关系,type指定参数类型,value指定参数的常量值 |
< map>、 < set> | |
< list> | |
< entry> |
2.Bean 的实例化
在面向对象编程时,如果要使用某个对象,需要事先实例化该对象。Spring中,也需要先实例化Bean。
有3种方式:构造方法实例化、静态工厂实例化、实例工厂实例化。最常用构造方法实例化。
2.1构造方法实例化
Spring容器调用Bean对应类中的无参数构造方法来实例化Bean。
创建BeanClass类
package instance;
public class BeanClass {
public String message;
public BeanClass() {
message = "构造方法实例化Bean";
}
public BeanClass(String s) {
message = s;
}
}
创建配置文件applicationContext.xml
<!-- 构造方法实例化Bean -->
<bean id="demo" class="instance.BeanClass"/>
创建测试类
package test;
public class TestInstance {
public static void mani(String[] args) {
ApplicationContext appCon = new ClassPathXmlApplicationContext("applicationContext.xml");
BeanClass b = (BeanClass)appCon.getBean("demo");
System.out.println(b1 + b1.message);
}
}
结果:instance.BeanClass@490ab905构造方法实例化Bean
3.Bean的作用域
scope参数 | 描述 |
---|---|
singleton | 默认的作用域,定义的Bean在Spring容器中只有一个Bean实例(返回同一个) |
prototype | Spring容器每次获取Bean,都将创建一个新的Bean实例(每次都返回新的) |
request | 每次HTTP请求都会返回一个Bean实例 |
session | 在一个session中,将返回同一个Bean实例 |
application | 为每个ServletContext对象创建一个实例,即同一个应用共享一个 |
websocket | 为每个WebSocket对象创建一个实例 |
singleton 与 prototype是最常用的,后面4种仅在Web Spring应用上下文中使用。
4.Bean的生命周期
一个对象的生命周期包括:创建(实例化与初始化)、使用、销毁。Bean也遵循这一过程。但是Spring通过了许多对外接口,允许开发者对 实例化(开辟空间)、初始化(属性初始化)、销毁 3个过程的前后做一些操作。
Spring容器可以管理singleton作用域下Bean的生命周期,能够精确知道Bean何时被创建,何时初始化完成,何时被销毁。而对于prototype作用域下的Bean,Spring只负责创建。创建之后Bean实例就交给客户端的代码管理,Spring将不再跟踪其生命周期,也不会管理这些Bean。
Bean的生命周期:
根据Bean的配置情况实例化一个Bean。
根据Spring上下文对实例化的Bean进行依赖注入,即对Bean的属性进行初始化。
如果Bean实现了 BeanNameAware接口,将调用它实现的 setBeanName(String beanId)方法,此处参数传递的是Bean的id,让实现这个接口的Bean知道自己在Spring容器中的的名字。
如果Bean实现了 BeanFactoryAware接口,将调用它实现的 setBeanFactory方法,此处参数传递的是当前Spring工厂实例的引用。此接口是在Bean实例化后、Setter方法之前调用。可以使得Bean获取容器的内部信息,从而进行某些定制化的操作。
如果Bean实现了 ApplicationContextAware接口,将调用它实现的setApplicationContext(ApplicationContext)方法,此处参数传递的是Spring上下文实例的引用。该方法会将容器本身作为参数传给该方法,将Spring传入的参数赋给该类对象的applicationContext实例变量,接下来可以通过该变量来访问容器本身。
如果Bean关联了 BeanPostProcessor接口,将调用初始化方法 postProcessBeforeInitialization(Object obj, String beanName)对Bean进行前置处理。BeanFactoryPostProcessor是Bean属性处理容器,管理所有未实例化的数据(修改属性)。
如果Bean实现了 InitializingBean接口,将调用 afterPropertiesSet方法。
如果Bean在Spring配置文件中配置了 init-method属性,将自动调用其配置的初始化方法。
注意:Spring为Bean提供了两种初始化方式:实现InitializingBean接口、init-method指定。
两种方式可以同时使用,但如果调用afterPropertiesSet时出错,则不会调用init-method指定的方法。
通过反射调用init-method指定的方法效率相对较低,但是消除了对Spring的依赖。
如果Bean关联了 BeanPostProcessor接口,将调用 postProcessAfterInitialization(Object obj, String beanName)方法进行后置处理,由于是在Bean初始化结束时调用After方法,也可用于内存或缓存技术。
注意:此时已经可以使用该Bean,由于该Bean的作用域是singleton,所以调用的是同一个Bean实例。
当Bean不再需要时将进入销毁阶段,如果Bean实现了 DisposableBean接口,则调用其实现的destroy方法将Bean销毁
如果在配置文件中通过 destroy-method属性指定了Bean的销毁方法,将调用其配置的销毁方法进行销毁
实例演示:
package life;
public class BeanLife {
public void initMyself() {
System.out.println(this.getClass().getName() + "执行自定义的初始化方法");
}
public void destroyMyself() {
System.out.println(this.getClass().getName() + "执行自定义的销毁方法");
}
}
<!-- 使用init-method属性指定初始化方法,使用destroy-method属性指定销毁方法-->
<bean id="beanLife" class="life.BeanLife" init-method="initMyself" destroy-method="destroyMyself"/>
package test;
public class TestLife {
public static void main(String[] args) {
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
BeanLife blife = (BeanLife)ctx.genBean("beanLife");
System.out.println("获得对象后" + blife);
// 关闭容器,销毁Bean对象
ctx.close();
}
}
5.Bean的装配
Bean的装配可以理解为将Bean依赖注入到Spring容器中。Spring容器支持:基于XML配置、基于注解、自动装配等多种装配方式,最常见的是基于注解。
5.1基于注解的装配
尽管使用XML配置文件可以很简单的装配Bean,但如果有大量的Bean,会导致XML配置文件过于庞大,不方便升级与维护,因此更推荐使用注解(annotation)。
@Repository
将数据访问层(DAO)的类标识为Bean。
@Service
将业务逻辑组件类(Service层)标注为Bean。
@Controller
将控制器组件类标注为Bean。
@Component
可以作用在任何层次上,标注一个Bean。为了更加层次化,不推荐使用。
@Autowired
对类成员变量、方法、构造方法进行标注,完成自动装配工作。可以消除setter和getter方法。默认按照Bean的类型进行装配,如果想按照名称装配,需要和@Qualifier 一起使用
@Resource(name=” “)
与@Autowired 功能一样,区别在于该注解默认是按照名称来装配注入的,只有找不到与名称匹配的Bean时才会按照Bean的类型来装配注入。@Resource有两个属性:name、type。name指定Bean实例名称,即按照名称来装配;type指定类型,即按照类型来装配。
@Qualifier
与@Autowired配合使用,当需要按照名称装配时。Bean的实例名称由@Qualifier 的参数指定。