网站首页 > 精选教程 正文
配置文件:
<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)**
复制代码
作者:JVM调优资料
猜你喜欢
- 2024-11-14 Java项目实战-01-单体架构案例分析实现
- 2024-11-14 java 设计模式实战,建造者模式之生产线
- 2024-11-14 Github霸榜的SpringBoot全套学习教程,从入门到实战,内容超详细
- 2024-11-14 Spring Boot 缓存开发实战 springboot开启缓存
- 2024-11-14 价值32k!阿里顶级架构师深度解析SpringBoot进阶原理实战手册
- 2024-11-14 阿里爆款SpringBoot项目实战PDF+源码+视频分享
- 2024-11-14 Java网络编程实战:手撸简单的Web服务器
- 2024-11-14 Java高并发编程实战,那些年学过的锁
- 2024-11-14 神了!阿里P8纯手写出了这份10W字的MyBatis技术原理实战开发手册
- 2024-11-14 HR说你没有实战能力?100套Java项目集合,实践完以后让你变大神
你 发表评论:
欢迎- 最近发表
- 标签列表
-
- nginx反向代理 (57)
- nginx日志 (56)
- nginx限制ip访问 (62)
- mac安装nginx (55)
- java和mysql (59)
- java中final (62)
- win10安装java (72)
- java启动参数 (64)
- java链表反转 (64)
- 字符串反转java (72)
- java逻辑运算符 (59)
- java 请求url (65)
- java信号量 (57)
- java定义枚举 (59)
- java字符串压缩 (56)
- java中的反射 (59)
- java 三维数组 (55)
- java插入排序 (68)
- java线程的状态 (62)
- java异步调用 (55)
- java中的异常处理 (62)
- java锁机制 (54)
- java静态内部类 (55)
- java怎么添加图片 (60)
- java 权限框架 (55)
本文暂时没有评论,来添加一个吧(●'◡'●)