发布时间:2025-10-15 17:09:30    次浏览
本文作者:伯乐在线-yemengying。未经作者许可,禁止转载!欢迎加入伯乐在线专栏作者。智商捉鸡?,实在没办法一下子理解SpringIoC和AOP的实现原理,看的闹心也不太懂,所以。。。决定拆成小的不能在小的一个个问题,一点点啃。今天先来看看Spring中Bean的生命周期。Spring Bean是Spring应用中最最重要的部分了。所以来看看Spring容器在初始化一个bean的时候会做那些事情,顺序是怎样的,在容器关闭的时候,又会做哪些事情。示例代码git地址:https://github.com/giraffe0813/giraffeInSpringspring版本:4.2.3.RELEASE鉴于Spring源码是用gradle构建的,我也决定舍弃我大maven,尝试下洪菊推荐过的gradle。运行beanLifeCycle模块下的junit test即可在控制台看到如下输出,可以清楚了解Spring容器在创建,初始化和销毁Bean的时候依次做了那些事情。12345678910111213141516171819202122232425Spring容器初始化=====================================调用GiraffeService无参构造函数GiraffeService中利用set方法设置属性值调用setBeanName::Bean Name defined incontext=giraffeService调用setBeanClassLoader,ClassLoader Name=sun.misc.Launcher$AppClassLoader调用setBeanFactory,setBeanFactory::giraffe bean singleton=true调用setEnvironment调用setResourceLoader::Resource File Name=spring-beans.xml调用setApplicationEventPublisher调用setApplicationContext::Bean Definition Names=[giraffeService,org.springframework.context.annotation.CommonAnnotationBeanPostProcessor#0, com.giraffe.spring.service.GiraffeServicePostProcessor#0] 执行BeanPostProcessor的postProcessBeforeInitialization方法,beanName=giraffeService调用PostConstruct注解标注的方法执行InitializingBean接口的afterPropertiesSet方法执行配置的init-method执行BeanPostProcessor的postProcessAfterInitialization方法,beanName=giraffeServiceSpring容器初始化完毕=====================================从容器中获取Beangiraffe Name=李光洙=====================================调用preDestroy注解标注的方法执行DisposableBean接口的destroy方法执行配置的destroy-methodSpring容器关闭参考文档life cycle management of a spring beanSpring Bean Life CycleSpring Bean的生命周期先来看看,Spring在Bean从创建到销毁的生命周期中可能做得事情。一、initialization 和 destroy有时我们需要在Bean属性值set好之后和Bean销毁之前做一些事情,比如检查Bean中某个属性是否被正常的设置好值了。Spring框架提供了多种方法让我们可以在Spring Bean的生命周期中执行initialization和pre-destroy方法。1.实现InitializingBean和DisposableBean接口这两个接口都只包含一个方法。通过实现InitializingBean接口的afterPropertiesSet()方法可以在Bean属性值设置好之后做一些操作,实现DisposableBean接口的destroy()方法可以在销毁Bean之前做一些操作。例子如下:Java123456789101112publicclassGiraffeService implementsInitializingBean,DisposableBean{@OverridepublicvoidafterPropertiesSet()throwsException{System.out.println('执行InitializingBean接口的afterPropertiesSet方法');}@Overridepublicvoiddestroy()throwsException{System.out.println('执行DisposableBean接口的destroy方法');}}这种方法比较简单,但是不建议使用。因为这样会将Bean的实现和Spring框架耦合在一起。2.在bean的配置文件中指定init-method和destroy-method方法Spring允许我们创建自己的init方法和destroy方法,只要在Bean的配置文件中指定init-method和destroy-method的值就可以在Bean初始化时和销毁之前执行一些操作。?如下:Java123456789101112publicclassGiraffeService{//通过bean的destroy-method属性指定的销毁方法publicvoiddestroyMethod()throwsException{System.out.println('执行配置的destroy-method');}//通过bean的init-method属性指定的初始化方法publicvoidinitMethod()throwsException{System.out.println('执行配置的init-method');}}配置文件中的配置:Java12bean name='giraffeService' class='com.giraffe.spring.service.GiraffeService'init-method='initMethod'destroy-method='destroyMethod'/bean需要注意的是自定义的init-method和post-method方法可以抛异常但是不能有参数。这种方式比较推荐,因为可以自己创建方法,无需将Bean的实现直接依赖于spring的框架。3.使用@PostConstruct和@PreDestroy注解除了xml配置的方式,Spring也支持用@PostConstruct和 @PreDestroy注解来指定init和destroy方法。这两个注解均在javax.annotation包中。为了注解可以生效,需要在配置文件中定义org.springframework.context.annotation.CommonAnnotationBeanPostProcessor或context:annotation-config?如下:Java123456789101112publicclassGiraffeService{@PostConstructpublicvoidinitPostConstruct(){System.out.println('执行PostConstruct注解标注的方法');}@PreDestroypublicvoidpreDestroy(){System.out.println('执行preDestroy注解标注的方法');}}配置文件:Java1bean class='org.springframework.context.annotation.CommonAnnotationBeanPostProcessor'/二、实现*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中的参数。?如下:Java1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950publicclassGiraffeService implements ApplicationContextAware,ApplicationEventPublisherAware,BeanClassLoaderAware,BeanFactoryAware,BeanNameAware,EnvironmentAware,ImportAware,ResourceLoaderAware{@OverridepublicvoidsetBeanClassLoader(ClassLoader classLoader){System.out.println('执行setBeanClassLoader,ClassLoader Name = '+classLoader.getClass().getName());}@OverridepublicvoidsetBeanFactory(BeanFactory beanFactory)throwsBeansException{System.out.println('执行setBeanFactory,setBeanFactory:: giraffe bean singleton='+ beanFactory.isSingleton('giraffeService'));}@OverridepublicvoidsetBeanName(Strings){System.out.println('执行setBeanName:: Bean Name defined in context='+s);}@OverridepublicvoidsetApplicationContext(ApplicationContext applicationContext)throwsBeansException{System.out.println('执行setApplicationContext:: Bean Definition Names='+Arrays.toString(applicationContext.getBeanDefinitionNames()));}@OverridepublicvoidsetApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher){System.out.println('执行setApplicationEventPublisher');}@OverridepublicvoidsetEnvironment(Environment environment){System.out.println('执行setEnvironment');}@OverridepublicvoidsetResourceLoader(ResourceLoader resourceLoader){Resource resource=resourceLoader.getResource('classpath:spring-beans.xml');System.out.println('执行setResourceLoader:: Resource File Name='+resource.getFilename());}@OverridepublicvoidsetImportMetadata(AnnotationMetadata annotationMetadata){System.out.println('执行setImportMetadata');}}三、BeanPostProcessor上面的*Aware接口是针对某个实现这些接口的Bean定制初始化的过程,Spring同样可以针对容器中的所有Bean,或者某些Bean定制初始化过程,只需提供一个实现BeanPostProcessor接口的类即可。 该接口中包含两个方法,postProcessBeforeInitialization和postProcessAfterInitialization。 postProcessBeforeInitialization方法会在容器中的Bean初始化之前执行, postProcessAfterInitialization方法在容器中的Bean初始化之后执行。?如下:Java12345678910111213141516publicclassCustomerBeanPostProcessorimplementsBeanPostProcessor{@OverridepublicObjectpostProcessBeforeInitialization(Objectbean,StringbeanName)throwsBeansException{System.out.println('执行BeanPostProcessor的postProcessBeforeInitialization方法,beanName='+beanName);returnbean;}@OverridepublicObjectpostProcessAfterInitialization(Objectbean,StringbeanName)throwsBeansException{System.out.println('执行BeanPostProcessor的postProcessAfterInitialization方法,beanName='+beanName);returnbean;}}要将BeanPostProcessor的Bean像其他Bean一样定义在配置文件中Java1bean class='com.giraffe.spring.service.CustomerBeanPostProcessor'/总结所以。。。结合第一节控制台输出的内容,Spring Bean的生命周期是这样纸的:Bean容器找到配置文件中Spring Bean的定义。Bean容器利用Java Reflection API创建一个Bean的实例。如果涉及到一些属性值 利用set方法设置一些属性值。如果Bean实现了BeanNameAware接口,调用setBeanName()方法,传入Bean的名字。如果Bean实现了BeanClassLoaderAware接口,调用setBeanClassLoader()方法,传入ClassLoader对象的实例。如果Bean实现了BeanFactoryAware接口,调用setBeanClassLoader()方法,传入ClassLoader对象的实例。与上面的类似,如果实现了其他*Aware接口,就调用相应的方法。如果有和加载这个Bean的Spring容器相关的BeanPostProcessor对象,执行postProcessBeforeInitialization()方法如果Bean实现了InitializingBean接口,执行afterPropertiesSet()方法。如果Bean在配置文件中的定义包含init-method属性,执行指定的方法。如果有和加载这个Bean的Spring容器相关的BeanPostProcessor对象,执行postProcessAfterInitialization()方法当要销毁Bean的时候,如果Bean实现了DisposableBean接口,执行destroy()方法。当要销毁Bean的时候,如果Bean在配置文件中的定义包含destroy-method属性,执行指定的方法。打赏支持我写出更多好文章,谢谢!打赏作者 打赏支持我写出更多好文章,谢谢!任选一种支付方式 1赞收藏评论关于作者:yemengying普通程序员,毕业于东中国正常大学(校友都懂哈),目前在点评,曾在某家外卖订餐平台从事Java开发,对python和搜索也有所了解。生活大爆炸和Running man脑残粉。没什么宏伟的目标,只希望每天都能有所收获,add more ing into my life。 个人主页· 我的文章· 1·