文章目录

  • 生命周期回调
    • 1、Bean初始化回调
    • 2、Bean销毁回调
    • 3、配置默认的初始化及销毁方法
    • 4、执行顺序
    • 5、容器启动或停止回调
      • Lifecycle 接口
      • LifecycleProcessor
      • SmartLifecycle
      • 源码分析
        • 启动阶段
        • 停止阶段
  • Aware接口
  • 初始化过程源码分析
    • 第一步:执行部分aware接口中的方法
    • 第二步:完成Aware接口方法的执行,以及@PostConstructor,@PreDestroy注解的处理
    • 第三步:完成初始化方法执行
    • 第四步:完成AOP代理
  • 总结

在之前的文章中,我们一起学习过了官网上容器扩展点相关的知识,包括FactoryBeanBeanFactroyPostProcessor,BeanPostProcessor,其中BeanPostProcessor还剩一个很重要的知识点没有介绍,就是相关的BeanPostProcessor中的方法的执行时机。之所以在之前的文章中没有介绍是因为这块内容涉及到Bean的生命周期。在这篇文章中我们开始学习Bean的生命周期相关的知识,整个Bean的生命周期可以分为以下几个阶段:

  • 实例化(得到一个还没有经过属性注入跟初始化的对象)
  • 属性注入(得到一个经过了属性注入但还没有初始化的对象)
  • 初始化(得到一个经过了初始化但还没有经过AOP的对象,AOP会在后置处理器中执行)
  • 销毁

在上面几个阶段中,BeanPostProcessor将会穿插执行。而在初始化跟销毁阶段又分为两部分:

  • 生命周期回调方法的执行
  • aware相关接口方法的执行

这篇文章中,我们先完成Bean生命周期中,整个初始化阶段的学习,对于官网中的章节为1.6小结

生命周期回调

1、Bean初始化回调

实现初始化回调方法,有以下三种形式

  • 实现InitializingBean接口

如下:

public class AnotherExampleBean implements InitializingBean {public void afterPropertiesSet() {// do some initialization work}
}
  • 使用Bean标签中的init-method属性

配置如下:

<bean id="exampleInitBean" class="examples.ExampleBean" init-method="init"/>
public class ExampleBean {public void init() {// do some initialization work}
}
  • 使用@PostConstruct注解

配置如下:

public class ExampleBean {@PostConstructpublic void init() {// do some initialization work}
}

2、Bean销毁回调

实现销毁回调方法,有以下三种形式

  • 实现DisposableBean接口
public class AnotherExampleBean implements DisposableBean {public void destroy() {// do some destruction work (like releasing pooled connections)}
}
  • 使用Bean标签中的destroy-method属性
<bean id="exampleInitBean" class="examples.ExampleBean" destroy-method="cleanup"/>
public class ExampleBean {public void cleanup() {// do some destruction work (like releasing pooled connections)}
}
  • 使用@PreDestroy注解
public class ExampleBean {@PreDestroypublic void cleanup() {// do some destruction work (like releasing pooled connections)}
}

3、配置默认的初始化及销毁方法

我们可以通过如下这种配置,为多个Bean同时指定初始化或销毁方法

<beans default-init-method="init" default-destroy-method="destory"><bean id="blogService" class="com.something.DefaultBlogService"><property name="blogDao" ref="blogDao" /></bean>
</beans>

在上面的XML配置中,Spring会将所有处于beans标签下的Bean的初始化方法名默认为init,销毁方法名默认为destory

但是如果我们同时在bean标签中也指定了init-method属性,那么默认的配置将会被覆盖。

4、执行顺序

如果我们在配置中同时让一个Bean实现了回调接口,又在Bean标签中指定了初始化方法,还进行了
@PostContruct注解的配置的话,那么它们的执行顺序如下:

  1. @PostConstruct所标记的方法
  2. InitializingBean 接口中的afterPropertiesSet() 方法
  3. Bean标签中的 init()方法

对于销毁方法执行顺序如下:

  1. @PreDestroy所标记的方法
  2. destroy() DisposableBean 回调接口中的destroy()方法
  3. Bean标签中的 destroy()方法

我们可以总结如下:

注解的优先级 > 实现接口的优先级 > XML配置的优先级

同时我们需要注意的是,官网推荐我们使用注解的形式来定义生命周期回调方法,这是因为相比于实现接口,采用注解这种方式我们的代码跟Spring框架本身的耦合度更加低。

5、容器启动或停止回调

Lifecycle 接口
public interface Lifecycle {// 当容器启动时调用void start();// 当容器停止时调用void stop();// 当前组件的运行状态boolean isRunning();
}

编写一个Demo如下:

public class Main {public static void main(String[] args) {AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(LifeCycleConfig.class);ac.start();ac.stop();}
}@Component
public class LifeCycleService implements Lifecycle {boolean isRunning;@Overridepublic void start() {isRunning = true;System.out.println("LifeCycleService start");}@Overridepublic void stop() {isRunning = false;System.out.println("LifeCycleService stop");}@Overridepublic boolean isRunning() {return isRunning;}
}

运行上面的代码可以发现程序正常打印启动跟停止的日志,在上面的例子中需要注意的时,一定要在start方法执行时将容器的运行状态isRunning置为true,否则stop方法不会调用


在Spring容器中,当接收到start或stop信号时,容器会将这些传递到所有实现了Lifecycle的组件上,在Spring内部是通过LifecycleProcessor接口来完成这一功能的。其接口定义如下:

LifecycleProcessor
public interface LifecycleProcessor extends Lifecycle {// 容器刷新时执行void onRefresh();// 容器关闭时执行void onClose();
}

从上面的代码中我们可以知道,LifecycleProcessor本身也是Lifecycle接口的扩展,它添加了两个额外的方法在容器刷新跟关闭时执行。

我们需要注意以下几点:

  1. 当我们实现Lifecycle接口时,如果我们想要其start或者stop执行,必须显式的调用容器的start()或者stop()方法。
  2. stop方法不一定能保证在我们之前介绍的销毁方法之前执行

当我们在容器中对多个Bean配置了在容器启动或停止时的调用时,那么这些Bean中start方法跟stop方法调用的顺序就很重要了。如果两个Bean之间有明确的依赖关系,比如我们通过@DepnedsOn注解,或者@AutoWired注解向容器表明了Bean之间的依赖关系,如下:

@Component
@DependsOn("b")
class A{//  @AutoWired
//   B b;
}@Component
class B{}

这种情况下,b作为被依赖项,其start方法会在a的start方法前调用,stop方法会在a的stop方法后调用

但是,在某些情况下Bean直接并没有直接的依赖关系,可能我们只知道实现了接口一的所有Bean的方法的优先级要高于实现了接口二的Bean。在这种情况下,我们就需要用到SmartLifecycle这个接口了

SmartLifecycle

其继承关系如下:

它本身除了继承了Lifecycle接口还继承了一个Phased接口,其接口定义如下:

public interface Phased { /**    * Return the phase value of this object.    */int getPhase();
}

通过上面接口定义的方法,我们可以指定不同Bean方法回调方法执行的优先级。

再来看看SmartLifecycle本身这个接口的定义

public interface SmartLifecycle extends Lifecycle, Phased {int DEFAULT_PHASE = Integer.MAX_VALUE;// 不需要显示的调用容器的start方法及stop方法也可以执行Bean的start方法跟stop方法default boolean isAutoStartup() {return true;}// 容器停止时调用的方法default void stop(Runnable callback) {stop();callback.run();}// 优先级,默认最低@Overridedefault int getPhase() {return DEFAULT_PHASE;}}

一般情况下,我们并不会复写isAutoStartup以及stop方法,但是为了指定方法执行的优先级,我们通常会覆盖其中的getPhase()方法,默认情况下它的优先级是最低的。我们需要知道的是,当我们启动容器时,如果有Bean实现了SmartLifecycle接口,其getPhase()方法返回的值越小,那么对于的start方法执行的时间就会越早,stop方法执行的时机就会越晚。因此,一个实现SmartLifecycle的对象,它的getPhase()方法返回Integer.MIN_VALUE将是第一个执行start方法的Bean和最后一个执行Stop方法的Bean。

另外我们可以看到

源码分析

源码分析,我们需要分为两个阶段:

启动阶段

整个流程图如下:

我们主要分析的代码在其中的3-12-23-12-3步骤中

3-12-2解析,代码如下:

 protected void initLifecycleProcessor() {ConfigurableListableBeanFactory beanFactory = getBeanFactory();if (beanFactory.containsLocalBean(LIFECYCLE_PROCESSOR_BEAN_NAME)) {this.lifecycleProcessor =beanFactory.getBean(LIFECYCLE_PROCESSOR_BEAN_NAME, LifecycleProcessor.class);if (logger.isTraceEnabled()) {logger.trace("Using LifecycleProcessor [" + this.lifecycleProcessor + "]");}}else {DefaultLifecycleProcessor defaultProcessor = new DefaultLifecycleProcessor();defaultProcessor.setBeanFactory(beanFactory);this.lifecycleProcessor = defaultProcessor;beanFactory.registerSingleton(LIFECYCLE_PROCESSOR_BEAN_NAME, this.lifecycleProcessor);if (logger.isTraceEnabled()) {logger.trace("No '" + LIFECYCLE_PROCESSOR_BEAN_NAME + "' bean, using " +"[" + this.lifecycleProcessor.getClass().getSimpleName() + "]");}}}

这段代码很简单,就是做了一件事:判断当前容器中是否有一个lifecycleProcessor的Bean或者BeanDefinition。如果有的话,采用这个提供的lifecycleProcessor,如果没有的话自己new一个DefaultLifecycleProcessor。这个类主要负载将启动或停止信息传播到具体的Bean当中,我们稍后分析的代码基本都在这个类中。

3-12-3解析:

其中的getLifecycleProcessor(),就是获取我们上一步提供的lifecycleProcessor,然后调用其onRefresh方法,代码如下:

public void onRefresh() {// 将start信号传递到BeanstartBeans(true); // 这个类本身也是一个实现了Lifecycle的接口的对象,将其running置为true,标记为运行中this.running = true;
}

之后调用了startBeans方法

private void startBeans(boolean autoStartupOnly) {// 获取所有实现了Lifecycle接口的Bean,如果采用了factroyBean的方式配置了一个LifecycleBean,那么factroyBean本身也要实现Lifecycle接口// 配置为懒加载的LifecycleBean必须实现SmartLifeCycle才能被调用start方法Map<String, Lifecycle> lifecycleBeans = getLifecycleBeans();// key:如果实现了SmartLifeCycle,则为其getPhase方法返回的值,如果只是实现了Lifecycle,则返回0// value:相同phase的Lifecycle的集合,并将其封装到了一个LifecycleGroup中Map<Integer, LifecycleGroup> phases = new HashMap<>();// 遍历所有的lifecycleBeans,填充上面申明的maplifecycleBeans.forEach((beanName, bean) -> {// 我们可以看到autoStartupOnly这个变量在上层传递过来的// 这个参数意味着是否只启动“自动”的Bean,这是什么意思呢?就是说,不需要手动调用容器的start方法// 从这里可以看出,实现了SmartLifecycle接口的类并且其isAutoStartup如果返回true的话,会在容器启动过程中自动调用,而仅仅实现了Lifecycle接口的类并不会被调用。// 如果我们去阅读容器的start方法的会发现,当调用链到达这个方法时,autoStartupOnly这个变量写死的为falseif (!autoStartupOnly || (bean instanceof SmartLifecycle && ((SmartLifecycle) bean).isAutoStartup())) {// 获取这个Bean执行的阶段,实际上就是调用SmartLifecycle中的getPhase方法// 如果没有实现SmartLifecycle,而是单纯的实现了Lifecycle,那么直接返回0int phase = getPhase(bean);// 下面就是一个填充Map的操作,有的话add,没有的话直接new一个,比较简单LifecycleGroup group = phases.get(phase);if (group == null) {// LifecycleGroup构造函数需要四个参数// phase:代表这一组lifecycleBeans的执行阶段// timeoutPerShutdownPhase:因为lifecycleBean中的stop方法可以在另一个线程中运行,所以为了确保当前阶段的所有lifecycleBean都执行完,Spring使用了CountDownLatch,而为了防止无休止的等待下去,所有这里设置了一个等待的最大时间,默认为30秒// lifecycleBeans:所有的实现了Lifecycle的Bean// autoStartupOnly: 手动调用容器的start方法时,为false。容器启动阶段自动调用时为true,详细的含义在上面解释过了group = new LifecycleGroup(phase, this.timeoutPerShutdownPhase, lifecycleBeans, autoStartupOnly);phases.put(phase, group);}group.add(beanName, bean);}});if (!phases.isEmpty()) {List<Integer> keys = new ArrayList<>(phases.keySet());// 升序排序Collections.sort(keys);for (Integer key : keys) {// 获取每个阶段下所有的lifecycleBean,然后调用其start方法phases.get(key).start();}}
}

跟踪代码可以发现,start方法最终调用到了doStart方法,其代码如下

private void doStart(Map<String, ? extends Lifecycle> lifecycleBeans, String beanName, boolean autoStartupOnly) {Lifecycle bean = lifecycleBeans.remove(beanName);if (bean != null && bean != this) {// 获取这个Bean依赖的其它Bean,在启动时先启动其依赖的BeanString[] dependenciesForBean = getBeanFactory().getDependenciesForBean(beanName);for (String dependency : dependenciesForBean) {doStart(lifecycleBeans, dependency, autoStartupOnly);}if (!bean.isRunning() &&(!autoStartupOnly || !(bean instanceof SmartLifecycle) || ((SmartLifecycle) bean).isAutoStartup())) {try {bean.start();}catch (Throwable ex) {throw new ApplicationContextException("Failed to start bean '" + beanName + "'", ex);}}}
}

上面的逻辑可以归结为一句话:获取这个Bean依赖的其它Bean,在启动时先启动其依赖的Bean,这也验证了我们从官网上得出的结论。

停止阶段

停止容器有两种办法,一种时显式的调用容器的stop或者close方法,如下:

public static void main(String[] args) {AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext();ac.register(LifeCycleConfig.class);ac.refresh();ac.stop();//       ac.close();
}

而另外一个中是注册一个JVM退出时的钩子,如下:

public static void main(String[] args) {AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext();ac.register(LifeCycleConfig.class);// 当main函数运行完成后,会调用容器doClose方法ac.registerShutdownHook();ac.refresh();
}

不论是上面哪一种方法,最终都会调用到DefaultLifecycleProcessoronClose方法,代码如下:

public void onClose() {// 传递所有的停止信号到BeanstopBeans();// 跟启动阶段一样,因为它本身是一个实现了Lifecycle接口的Bean,所有需要更改它的运行标志this.running = false;
}
private void stopBeans() {// 获取容器中所有的实现了Lifecycle接口的BeanMap<String, Lifecycle> lifecycleBeans = getLifecycleBeans();Map<Integer, LifecycleGroup> phases = new HashMap<>();lifecycleBeans.forEach((beanName, bean) -> {int shutdownPhase = getPhase(bean);LifecycleGroup group = phases.get(shutdownPhase);if (group == null) {group = new LifecycleGroup(shutdownPhase, this.timeoutPerShutdownPhase, lifecycleBeans, false);phases.put(shutdownPhase, group);}// 同一阶段的Bean放到一起group.add(beanName, bean);});if (!phases.isEmpty()) {List<Integer> keys = new ArrayList<>(phases.keySet());// 跟start阶段不同的是,这里采用的是降序// 也就是阶段越后的Bean,越先stopkeys.sort(Collections.reverseOrder());for (Integer key : keys) {phases.get(key).stop();}}
}
public void stop() {if (this.members.isEmpty()) {return;}this.members.sort(Collections.reverseOrder());// 创建了一个CountDownLatch,需要等待的线程数量为当前阶段的所有ifecycleBean的数量CountDownLatch latch = new CountDownLatch(this.smartMemberCount);// stop方法可以异步执行,这里保存的是还没有执行完的lifecycleBean的名称Set<String> countDownBeanNames = Collections.synchronizedSet(new LinkedHashSet<>());// 所有lifecycleBeans的名字集合Set<String> lifecycleBeanNames = new HashSet<>(this.lifecycleBeans.keySet());for (LifecycleGroupMember member : this.members) {if (lifecycleBeanNames.contains(member.name)) {doStop(this.lifecycleBeans, member.name, latch, countDownBeanNames);}else if (member.bean instanceof SmartLifecycle) {// 按理说,这段代码永远不会执行,可能是版本遗留的代码没有进行删除// 大家可以自行对比4.x的代码跟5.x的代码latch.countDown();}}try {// 最大等待时间30s,超时进行日志打印latch.await(this.timeout, TimeUnit.MILLISECONDS);if (latch.getCount() > 0 && !countDownBeanNames.isEmpty() && logger.isInfoEnabled()) {logger.info("Failed to shut down " + countDownBeanNames.size() + " bean" +(countDownBeanNames.size() > 1 ? "s" : "") + " with phase value " +this.phase + " within timeout of " + this.timeout + ": " + countDownBeanNames);}}catch (InterruptedException ex) {Thread.currentThread().interrupt();}
}
}
private void doStop(Map<String, ? extends Lifecycle> lifecycleBeans, final String beanName,final CountDownLatch latch, final Set<String> countDownBeanNames) {Lifecycle bean = lifecycleBeans.remove(beanName);if (bean != null) {// 获取这个Bean所被依赖的Bean,先对这些Bean进行stop操作String[] dependentBeans = getBeanFactory().getDependentBeans(beanName);for (String dependentBean : dependentBeans) {doStop(lifecycleBeans, dependentBean, latch, countDownBeanNames);}try {if (bean.isRunning()) {if (bean instanceof SmartLifecycle) {if (logger.isTraceEnabled()) {logger.trace("Asking bean '" + beanName + "' of type [" +bean.getClass().getName() + "] to stop");}countDownBeanNames.add(beanName);// 还记得到SmartLifecycle中的stop方法吗?里面接受了一个Runnable参数// 就是在这里地方传进去的。主要就是进行一个操作latch.countDown(),标记当前的lifeCycleBean的stop方法执行完成((SmartLifecycle) bean).stop(() -> {latch.countDown();countDownBeanNames.remove(beanName);if (logger.isDebugEnabled()) {logger.debug("Bean '" + beanName + "' completed its stop procedure");}});}else {if (logger.isTraceEnabled()) {logger.trace("Stopping bean '" + beanName + "' of type [" +bean.getClass().getName() + "]");}bean.stop();if (logger.isDebugEnabled()) {logger.debug("Successfully stopped bean '" + beanName + "'");}}}else if (bean instanceof SmartLifecycle) {// Don't wait for beans that aren't running...latch.countDown();}}catch (Throwable ex) {if (logger.isWarnEnabled()) {logger.warn("Failed to stop bean '" + beanName + "'", ex);}}}
}

整个stop方法跟start方法相比,逻辑上并没有很大的区别,除了执行时顺序相反外。

  • start方法,先找出这个Bean的所有依赖,然后先启动这个Bean的依赖
  • stop方法,先找出哪些Bean依赖了当前的Bean,然后停止这些被依赖的Bean,之后再停止当前的Bean

Aware接口

在整个Bean的生命周期的初始化阶段,有一个很重要的步骤就是执行相关的Aware接口,而整个Aware接口执行又可以分为两个阶段:

  • 第一阶段,执行BeanXXXAware接口
  • 执行其它Aware接口

至于为什么需要这样分,我们在进行源码分析的时候就明白了

我们可以发现,所有的Aware接口都是为了能让我们拿到容器中相关的资源,比如BeanNameAware,可以让我们拿到Bean的名称,ApplicationContextAware 可以让我们拿到整个容器。但是使用Aware接口也会相应的带来一些弊病,当我们去实现这些接口时,意味着我们的应用程序跟Spring容器发生了强耦合,违背了IOC的原则。所以一般情况下,并不推荐采用这种方式,除非我们在编写一些整个应用基础的组件。

Spring内部提供了如下这些Aware接口

初始化过程源码分析

回顾我们之前的流程图,我们可以看到,创建Bean的动作主要发生在3-11-6-4步骤中,主要分为三步:

  1. createBeanInstance ,创建实例
  2. populateBean,属性注入
  3. initializeBean,初始化

我们今天要分析的代码主要就是第3-11-6-4-3步,其完成的功能主要就是初始化,相对于我们之前分析过的代码来说,这段代码算比较简单的:

 protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {if (System.getSecurityManager() != null) {AccessController.doPrivileged((PrivilegedAction<Object>) () -> {invokeAwareMethods(beanName, bean);return null;}, getAccessControlContext());}else {// 第一步:执行aware接口中的方法,需要主要的是,不是所有的Aware接口都是在这步执行了invokeAwareMethods(beanName, bean);}Object wrappedBean = bean;if (mbd == null || !mbd.isSynthetic()) {// 第二步:完成Aware接口方法的执行,以及@PostConstructor,@PreDestroy注解的处理wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);}try {// 第三步:完成初始化方法执行invokeInitMethods(beanName, wrappedBean, mbd);}catch (Throwable ex) {throw new BeanCreationException((mbd != null ? mbd.getResourceDescription() : null),beanName, "Invocation of init method failed", ex);}if (mbd == null || !mbd.isSynthetic()) {// 第四步:完成AOP代理wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);}return wrappedBean;}

第一步:执行部分aware接口中的方法

private void invokeAwareMethods(final String beanName, final Object bean) {if (bean instanceof Aware) {if (bean instanceof BeanNameAware) {((BeanNameAware) bean).setBeanName(beanName);}if (bean instanceof BeanClassLoaderAware) {ClassLoader bcl = getBeanClassLoader();if (bcl != null) {((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);}}if (bean instanceof BeanFactoryAware) {((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);}}
}

可以看到,在invokeAwareMethods这个方法中,并不是所有的Aware接口都会被执行,只有BeanNameAware,BeanClassLoaderAware,BeanFactoryAware这三个接口会被执行,这也是为什么我单独将BeanXXXAware这一类的接口划分为一组的原因。这三个Aware接口分别实现的功能为:

BeanNameAware:获取Bean的名字

BeanClassLoaderAware:获取加载这个Bean的类加载器

BeanFactoryAware:获取当前的BeanFactory

第二步:完成Aware接口方法的执行,以及@PostConstructor,@PreDestroy注解的处理

  • Aware接口执行,出了我们上面介绍的三个Aware接口,其余的接口都会在这个阶段执行,例如我们之前说到的ApplicationContextAware 接口,它会被一个专门的后置处理器ApplicationContextAwareProcessor处理。其余的接口也是类似的操作,这里就不在赘述了
  • @PostConstructor,@PreDestroy两个注解的处理。这两个注解会被CommonAnnotationBeanPostProcessor这个后置处理器处理,需要注意的是@Resource注解也是被这个后置处理器进行处理的。关于注解的处理逻辑,我们后面的源码阅读相关文章中再做详细分析。

第三步:完成初始化方法执行

protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)throws Throwable {// 是否实现了 InitializingBean接口boolean isInitializingBean = (bean instanceof InitializingBean);if (isInitializingBean && (mbd == null || // 这个判断基本恒成立,除非手动改变了BD的属性!mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {if (logger.isTraceEnabled()) {logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");}if (System.getSecurityManager() != null) {try {AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {// 调用afterPropertiesSet方法((InitializingBean) bean).afterPropertiesSet();return null;}, getAccessControlContext());}catch (PrivilegedActionException pae) {throw pae.getException();}}else {// 调用afterPropertiesSet方法((InitializingBean) bean).afterPropertiesSet();}}if (mbd != null && bean.getClass() != NullBean.class) {String initMethodName = mbd.getInitMethodName();if (StringUtils.hasLength(initMethodName) &&!(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&!mbd.isExternallyManagedInitMethod(initMethodName)) {invokeCustomInitMethod(beanName, bean, mbd);}}
}

整段代码的逻辑还是很简单的,先判断是否实现了对应的生命周期回调的接口(InitializingBean),如果实现了接口,先调用接口中的afterPropertiesSet方法。之后在判断是否提供了initMethod,也就是在XML中的Bean标签中提供了init-method属性。

第四步:完成AOP代理

AOP代理实现的具体过程放到之后的文章中分析,我们暂时只需要知道AOP是在Bean完成了所有初始化方法后完成的即可。这也不难理解,在进行AOP之前必须保证我们的Bean已经被充分的”装配“了。

总结

就目前而言,我们可以将整个Bean的生命周期总结如下:


在上图中,实例话跟属性注入的过程我们还没有分析,在后续的文章中,我们将对其进行详细的分析。销毁阶段并不复杂,所以这里也不做分析了,直接给出结论,大概可以自己阅读代码,入口在容器的close方法中。

另外,我这里并没有将实现了LifeCycle接口的Bean中的start方法跟stop方法算入到整个Bean的生命周期中,大家只要知道,如果实现了SmartLifeCyle接口,那么在容器启动时也会默认调用其start方法,并且调用的时机在Bean完成初始化后,而stop方法将在Bean销毁前调用。

扫描下方二维码,关注我的公众号,更多精彩文章在等您!~~

Spring官网阅读(九)Spring中Bean的生命周期(上)相关推荐

  1. Spring官网阅读 | 总结篇

    接近用了4个多月的时间,完成了整个<Spring官网阅读>系列的文章,本文主要对本系列所有的文章做一个总结,同时也将所有的目录汇总成一篇文章方便各位读者来阅读. 下面这张图是我整个的写作大 ...

  2. 快速下载Spring官网下载dist.zip中所有jar,例如spring-5.2.10.RELEASE-dist.zip

    下载Spring官网下载dist.zip中所有jar,例如spring-5.2.10.RELEASE-dist.zip 下载地址:http://repo.spring.io/libs-release- ...

  3. Spring 官网阅读指南

    一.概述 Spring官网:https://spring.io/,界面如下: 二.各模块介绍 进入首页如上图,在首页官网会展示一些当前Spring比较流行的技术.可以看见导航栏有几个模块,信息如下: ...

  4. (十)Spring中Bean的生命周期(下)

    Spring官网阅读(十)Spring中Bean的生命周期(下) 在上篇文章中,我们已经对Bean的生命周期做了简单的介绍,主要介绍了整个生命周期中的初始化阶段以及基于容器启动停止时LifeCycle ...

  5. 如果你每次面试前都要去背一篇Spring中Bean的生命周期,请看完这篇文章

    前言 当你准备去复习Spring中Bean的生命周期的时候,这个时候你开始上网找资料,很大概率会看到下面这张图: 先不论这张图上是否全面,但是就说这张图吧,你是不是背了又忘,忘了又背? 究其原因在于, ...

  6. 最新的Spring官网如何下载Spring框架

    最新的Spring官网如何下载Spring框架.特此写一篇简单的教程,供大家分享. 1. 首先打开Spring官网  https://spring.io/ 2. 点击页头 PROGECTS 选项 3. ...

  7. Spring第三天,详解Bean的生命周期,学会后让面试官无话可说!

    点击下方链接回顾往期 不要再说不会Spring了!Spring第一天,学会进大厂! Spring第二天,你必须知道容器注册组件的几种方式!学废它吊打面试官! 今天讲解Spring中Bean的生命周期. ...

  8. IoC基础篇(一)--- Spring容器中Bean的生命周期

    IoC基础篇(一)--- Spring容器中Bean的生命周期 日出日落,春去秋来,花随流水,北雁南飞,世间万物皆有生死轮回.从调用XML中的Bean配置信息,到应用到具体实例中,再到销毁,Bean也 ...

  9. Spring 中 Bean 的生命周期

    本文作者: 伯乐在线 - yemengying 智商捉鸡?,实在没办法一下子理解Spring IoC和AOP的实现原理,看的闹心也不太懂,所以...决定拆成小的不能在小的一个个问题,一点点啃.今天先来 ...

  10. 面试问题:Spring中Bean 的生命周期

    Spring Bean生命周期执行流程 在传统的 Java 应用中,Bean 的生命周期很简单,使用关键字 new 实例化 Bean,当不需要该 Bean 时,由 Java 自动进行垃圾回收. Spr ...

最新文章

  1. hexdump——Linux系统的二进制文件查看工具
  2. linux存储--inode详解(五)
  3. mongodb指南(翻译)(二十二) - developer zone - 索引(六)多键
  4. 转:Oracle SQL 内置函数大全 (一)
  5. 记录 FreeBSD
  6. char* 和char[] 内存分配的区别(转载)
  7. 将数组的列表结构转成树结构
  8. MyBatis 入门到精通(一) 了解MyBatis获取SqlSession
  9. python 检查代码规范_Python代码规范检测
  10. 大学生活的真实写照(经典)
  11. Mac上java开发工具
  12. 音视频多媒体开发基础概述之颜色空间(1)CIE色度模型 RGB颜色空间
  13. zblog模板php免费三栏,天兴工作室三栏布局zblog模板 自定义配色
  14. 集合20210801
  15. 碱性溶液中HER动力学分析
  16. 叶问【转自知数堂微信公众号】
  17. 摄影口诀--针对不同情景
  18. Python学习(1)——小甲鱼零基础入门python学习笔记(更新-ing)
  19. 北大计算机专硕学费,北京大学专业硕士学费被曝高达2.2万元/年
  20. 2020研究生数学建模E题--AlexNet深度网络解法(大雾能见度估计与预测)(含代码)

热门文章

  1. 1.1.1信息特性及定义,数据、信息、知识,信息处理系统
  2. 【数据结构与算法】二叉树(下)
  3. 在手机上就能修改PDF中出现的错误,手机怎么修改PDF文本?
  4. 【直播预告】3月17日从上云到云原生,如何用新技术应对突发事件
  5. [exceptions]如何排查can not find symbol的编译错误
  6. 阿里小蜜人工智能助理,唯一入选麻省理工十大突破性技术的中国代表
  7. 学习笔记:树和二叉树的初步学习1
  8. SSM框架之mybaitis框架详解
  9. joomla+连接不上mysql_配置joomla数据库mysql
  10. 2048小游戏及改进