写点什么

Java 中高级核心知识全面解析——常用框架 (Spring 中 -Bean- 的作用域与生命周期)

  • 2022 年 4 月 19 日
  • 本文字数:3607 字

    阅读完需:约 12 分钟

5.globalSession

global session 作用域类似于标准的 HTTP session 作用域,不过仅仅在基于 portlet 的 web 应用中才有意义。Portlet 规范定义了全局 Session 的概念,它被所有构成某个 portlet web 应用的各种不同的 portle t 所共享。在 global session 作用域中定义的 bean 被限定于全局 portlet Session 的生命周期范围内。


<bean id="user" class="com.foo.Preferences "scope="globalSession"/>

三、bean 的生命周期

Spring Bean 是 Spring 应用中最最重要的部分了。所以来看看 Spring 容器在初始化一个 bean 的时候会做那些事情,顺序是怎样的,在容器关闭的时候,又会做哪些事情。


spring 版本:4.2.3.RELEASE 鉴于 Spring 源码是用 gradle 构建的,我也决定舍弃我大 maven,尝试下洪菊推荐过的 gradle。运行 beanLifeCycle 模块下的 junit test 即可在控制台看到如下输出,可以清楚了解 Spring 容器在创建,初始化和销毁 Bean 的时候依次做了那些事情。



先来看看,Spring 在 Bean 从创建到销毁的生命周期中可能做得事情。

1.initialization 和 destroy

有时我们需要在 Bean 属性值 set 好之后和 Bean 销毁之前做一些事情,比如检查 Bean 中某个属性是否被正常的设置好值了。Spring 框架提供了多种方法让我们可以在 Spring Bean 的生命周期中执行initializationpre-destroy方法。

1)实现 InitializingBean 和 DisposableBean 接口

这两个接口都只包含一个方法。通过实现InitializingBean接口的afterPropertiesSet()方法可以在 Bean 属性值设置好之后做一些操作,实现DisposableBean接口的destroy()方法可以在销毁 Bean 之前做一些操作。


例子如下:


public class GiraffeService implements InitializingBean,DisposableBean {@Overridepublic void afterPropertiesSet() throws Exception {System.out.println("执行 InitializingBean 接口的 afterPropertiesSet 方法");}@Overridepublic void destroy() throws Exception {System.out.println("执行 DisposableBean 接口的 destroy 方法");}}


这种方法比较简单,但是不建议使用。因为这样会将 Bean 的实现和 Spring 框架耦合在一起。

2)在 bean 的配置文件中指定 init-method 和 destroy-method 方法

Spring 允许我们创建自己的 init 方法和 destroy 方法,只要在 Bean 的配置文件中指定 init-methoddestroy-method 的值就可以在 Bean 初始化时和销毁之前执行一些操作。


例子如下:


public class GiraffeService {//通过<bean>的 destroy-method 属性指定的销毁方法 public void destroyMethod() throws Exception {System.out.println("执行配置的 destroy-method");}//通过<bean>的 init-method 属性指定的初始化方法 public void initMethod() throws Exception {System.out.println("执行配置的 init-method");}}


配置文件中的配置:


<bean name="giraffeService" class="com.giraffe.spring.service.GiraffeService"init-method="initMethod" destroy-method="destroyMethod"></bean>


需要注意的是自定义的init-methodpost-method方法可以抛异常但是不能有参数。


这种方式比较推荐,因为可以自己创建方法,无需将 Bean 的实现直接依赖于 spring 的框架。

3)使用 @PostConstruct 和 @PreDestroy 注解

除了 xml 配置的方式,Spring 也支持用 @PostConstruct@PreDestroy 注解来指定 initdestroy 方法。这两个注解均在 javax.annotation 包中。为了注解可以生效,需要在配置文件中定义org.springframework.context.annotation.CommonAnnotationBeanPostProcessor或context:annotation-config


例子如下:


public class GiraffeService {@PostConstructpublic void initPostConstruct(){System.out.println("执行 PostConstruct 注解标注的方法");}@PreDestroypublic void preDestroy(){System.out.println("执行 preDestroy 注解标注的方法");}}


配置文件:


<bean class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor"/>

2.实现*Aware 接口 在 Bean 中使用 Spring 框架的一些对象

有些时候我们需要在 Bean 的初始化中使用 Spring 框架自身的一些对象来执行一些操作,比如获取ServletContext的一些参数,获取 ApplicaitionContext 中的 BeanDefinition的名字,获取 Bean 在容器中的名字等等。为了让 Bean 可以获取到框架自身的一些对象,Spring 提供了一组名为*Aware的接口。


这些接口 《一线大厂 Java 面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义》开源 均继承于 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{@Overridepublic void setBeanClassLoader(ClassLoader classLoader) {System.out.println("执行 setBeanClassLoader,ClassLoader Name = " +classLoader.getClass().getName());}@Overridepublic void setBeanFactory(BeanFactory beanFactory) throws BeansException {System.out.println("执行 setBeanFactory,setBeanFactory:: giraffe bean singleton=" + beanFactory.isSingleton("giraffeService"));}@Overridepublic void setBeanName(String s) {System.out.println("执行 setBeanName:: Bean Name defined in context=" + s);}@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {System.out.println("执行 setApplicationContext:: Bean Definition Names="


  • Arrays.toString(applicationContext.getBeanDefinitionNames()));}@Overridepublic void setApplicationEventPublisher(ApplicationEventPublishe Java 开源项目【ali1024.coding.net/public/P7/Java/git】 r applicationEventPublisher) {System.out.println("执行 setApplicationEventPublisher");}@Overridepublic void setEnvironment(Environment environment) {System.out.println("执行 setEnvironment");}@Overridepublic void setResourceLoader(ResourceLoader resourceLoader) {Resource resource = resourceLoader.getResource("classpath:spring- beans.xml");System.out.println("执行 setResourceLoader:: Resource File Name=" + resource.getFilename());}@Overridepublic void setImportMetadata(AnnotationMetadata annotationMetadata) {System.out.println("执行 setImportMetadata");}}

3.BeanPostProcessor

上面的*Aware 接口是针对某个实现这些接口的 Bean 定制初始化的过程,Spring 同样可以针对容器中的所有 Bean,或者某些 Bean 定制初始化过程,只需提供一个实现 BeanPostProcessor接口的类即可。 该接口中包含两个方法,postProcessBeforeInitializationpostProcessAfterInitializationpostProcessBeforeInitialization方法会在容器中的 Bean 初始化之前执行, postProcessAfterInitialization方法在容器中的 Bean 初始化之后执行。


例子如下:


public class CustomerBeanPostProcessor implements BeanPostProcessor {@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {System.out.println("执行 BeanPostProcessor 的 postProcessBeforeInitialization 方法,beanName=" + beanName);return bean;}@Overridepublic 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.总结

最后

由于细节内容实在太多了,为了不影响文章的观赏性,只截出了一部分知识点大致的介绍一下,每个小节点里面都有更细化的内容!



小编准备了一份 Java 进阶学习路线图(Xmind)以及来年金三银四必备的一份《Java 面试必备指南》



用户头像

还未添加个人签名 2022.04.13 加入

还未添加个人简介

评论

发布
暂无评论
Java中高级核心知识全面解析——常用框架(Spring中-Bean-的作用域与生命周期)_Java_爱好编程进阶_InfoQ写作平台