配置文件:
<bean class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor"
/>
复制代码
2.实现*Aware 接口 在 Bean 中使用 Spring 框架的一些对象
有些时候我们需要在 Bean 的初始化中使用 Spring 框架自身的一些对象来执行一些操作,比如获取ServletContext
的一些参数,获取 ApplicaitionContext
中的 BeanDefinition
的名字,获取 Bean
在容器中的名字等等。为了让 Bean 可以获取到框架自身的一些对象,Spring 提供了一组名为*Aware
的接口。
这些接口均继承于 org.springframework.beans.factory.Aware
标记接口,并提供一个将由 Bean 实现的 set*方法,Spring 通过基于 setter 的依赖注入方式使相应的对象可以被 Bean 使用。
网上说,这些接口是利用观察者模式实现的,类似于servlet listeners
,目前还不明白,不过这也不在本文的讨论范围内。
介绍一些重要的 Aware 接口:
ApplicationContextAware: 获得ApplicationContext
对象,可以用来获取所有Bean definition
的名字。
BeanFactoryAware:获得BeanFactory
对象,可以用来检测 Bean 的作用域。
BeanNameAware:获得 Bean 在配置文件中定义的名字。
ResourceLoaderAware:获得ResourceLoader
对象,可以获得 classpath 中某个文件。
ServletContextAware:在一个 MVC 应用中可以获取ServletContext
对象,可以读取 context 中的参数。
ServletConfigAware: 在一个 MVC 应用中可以获取ServletConfig
对象,可以读取 config 中的参数。
public class GiraffeService implements ApplicationContextAware,
ApplicationEventPublisherAware, BeanClassLoaderAware, BeanFactoryAware,
BeanNameAware, EnvironmentAware, ImportAware, ResourceLoaderAware{
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
System.out.println("执行setBeanClassLoader,ClassLoader Name = " +
classLoader.getClass().getName());
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.out.println("执行setBeanFactory,setBeanFactory:: giraffe bean singleton=" + beanFactory.isSingleton("giraffeService"));
}
@Override
public void setBeanName(String s) {
System.out.println("执行setBeanName:: Bean Name defined in context=" + s);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
System.out.println("执行setApplicationContext:: Bean Definition Names="
+ Arrays.toString(applicationContext.getBeanDefinitionNames()));
}
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
System.out.println("执行setApplicationEventPublisher");
}
@Override
public void setEnvironment(Environment environment) {
System.out.println("执行setEnvironment");
}
@Override
public void setResourceLoader(ResourceLoader resourceLoader) {
Resource resource = resourceLoader.getResource("classpath:spring- beans.xml");
System.out.println("执行setResourceLoader:: Resource File Name=" + resource.getFilename());
}
@Override
public void setImportMetadata(AnnotationMetadata annotationMetadata) {
System.out.println("执行setImportMetadata");
}
}
复制代码
3.BeanPostProcessor
上面的*Aware 接口是针对某个实现这些接口的 Bean 定制初始化的过程,Spring 同样可以针对容器中的所有 Bean,或者某些 Bean 定制初始化过程,只需提供一个实现 BeanPostProcessor
接口的类即可。 该接口中包含两个方法,postProcessBeforeInitialization
和 postProcessAfterInitialization
。 postProcessBeforeInitialization
方法会在容器中的 Bean 初始化之前执行, postProcessAfterInitialization
方法在容器中的 Bean 初始化之后执行。
例子如下:
public class CustomerBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("执行BeanPostProcessor的 postProcessBeforeInitialization方法,beanName=" + beanName);
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("执行BeanPostProcessor的postProcessAfterInitialization 方法,beanName=" + beanName);
return bean;
}
}
复制代码
要将BeanPostProcessor
的 Bean 像其他 Bean 一样定义在配置文件中
<bean class="com.giraffe.spring.service.CustomerBeanPostProcessor"/>
复制代码
4.总结
所以结合第一节控制台输出的内容,Spring Bean 的生命周期是这样纸的:
Bean 容器找到配置文件中 Spring Bean 的定义。
Bean 容器利用 Java Reflection API 创建一个 Bean 的实例。
如果涉及到一些属性值 利用 set 方法设置一些属性值。
如果 Bean 实现了BeanNameAware
接口,调用setBeanName()
方法,传入 Bean 的名字。
如果 Bean 实现了BeanClassLoaderAware
接口,调用setBeanClassLoader()
方法,传入 ClassLoader 对象的实例。
如果 Bean 实现了BeanFactoryAware
接口,调用setBeanFactory()
方法,传入 BeanFactory 对象的实例。
与上面的类似,如果实现了其他*Aware
接口,就调用相应的方法。
如果有和加载这个 Bean 的 Spring 容器相关的BeanPostProcessor
对象,执行postProcessBeforeInitialization()
方法
如果 Bean 实现了InitializingBean
接口,执行afterPropertiesSet()
方法。
如果 Bean 在配置文件中的定义包含init-method
属性,执行指定的方法。
如果有和加载这个 Bean 的 Spring 容器相关的BeanPostProcessor
对象,执行postProcessAfterInitialization()
方法
当要销毁 Bean 的时候,如果 Bean 实现了DisposableBean
接口,执destroy()
方法。
当要销毁 Bean 的时候,如果 Bean 在配置文件中的定义包含destroy-method
属性,执行指定的方法。
与之比较类似的中文版本:
其实很多时候我们并不会真的去实现上面说描述的那些接口,那么下面我们就除去那些接口,针对 bean 的单例和非单例来描述下 bean 的生命周期:
5.单例管理的对象
当scope=”singleton”
,即默认情况下,会在启动容器时(即实例化容器时)时实例化。但我们可以指定 Bean 节点的lazy-init=”true”
来延迟初始化 bean,这时候,只有在第一次获取 bean 时才会初始化 bean,即第一次请求该 bean 时才初始化。如下配置:
<bean id="ServiceImpl" class="cn.csdn.service.ServiceImpl" lazy-init="true"/>
复制代码
如果想对所有的默认单例 bean 都应用延迟初始化,可以在根节点 beans 设置default-lazy-init
属性为 true,如下所示:
<beans default-lazy-init="true" …>
复制代码
默认情况下,Spring 在读取 xml 文件的时候,就会创建对象。在创建对象的时候先调用构造器,然后调用 init-method
属性值中所指定的方法。对象在被销毁的时候,会调用 destroy-method
属性值中所指定的方法(例如调用Container.destroy()
方法的时候)。写一个测试类,代码如下:
public class LifeBean {
private String name;
public LifeBean(){
System.out.println("LifeBean()构造函数");
}
public String getName() {
return name;
}
public void setName(String name) {
System.out.println("setName()");
this.name = name;
}
public void init(){
System.out.println("this is init of lifeBean");
}
public void destory(){
System.out.println("this is destory of lifeBean " + this);
}
}
复制代码
life.xml 配置如下:
<bean id="life_singleton" class="com.bean.LifeBean" scope="singleton"
init-method="init" destroy-method="destory" lazy-init="true"/>
复制代码
测试代码:
LifeBean()构造函数
this is init of lifeBean
com.bean.LifeBean@573f2bb1
……
this is destory of lifeBean com.bean.LifeBean@573f2bb1
复制代码
6.非单例管理的对象
当 scope=”prototype”
时,容器也会延迟初始化 bean,Spring 读取 xml 文件的时候,并不会立刻创建对象,而是在第一次请求该 bean 时才初始化(如调用 getBean 方法时)。在第一次请求每一个 prototype 的 bean 时,Spring 容器都会调用其构造器创建这个对象,然后调用 init-method
属性值中所指定的方法。对象销毁的时候,Spring 容器不会帮我们调用任何方法,因为是非单例,这个类型的对象有很多个,Spring 容器一旦把这个对象交给你之后,就不再管理这个对象了。
为了测试prototype bean
的生命周期 life.xml 配置如下:
<bean id="life_prototype" class="com.bean.LifeBean" scope="prototype"
init- method="init" destroy-method="destory"/>
复制代码
测试程序:
public class LifeTest {
@Test
public void test() {
AbstractApplicationContext container = new ClassPathXmlApplicationContext("life.xml");
LifeBean life1 = (LifeBean)container.getBean("life_singleton");
System.out.println(life1);
LifeBean life3 = (LifeBean)container.getBean("life_prototype");
System.out.println(life3);
container.close();
}
}
复制代码
运行结果:
LifeBean()构造函数
this is init of lifeBean
com.bean.LifeBean@573f2bb1
LifeBean()构造函数
this is init of lifeBean
com.bean.LifeBean@5ae9a829
……
# 本次面试答案,以及收集到的大厂必问面试题分享:
![字节跳动超高难度三面java程序员面经,大厂的面试都这么变态吗?](https://static001.geekbang.org/infoq/1f/1ffb14002e1ff2c719722161e68c94c5.jpeg)
**[资料领取方式:戳这里即可免费下载](https://gitee.com/vip204888/java-p7)**
复制代码
评论