配置文件:
<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 ……
# 本次面试答案,以及收集到的大厂必问面试题分享:

**[资料领取方式:戳这里即可免费下载](https://gitee.com/vip204888/java-p7)**
复制代码
评论