InitializingBean

记住一点:InitializingBean接口为bean提供了初始化方法的方式,它只包括afterPropertiesSet方法,凡是继承该接口的子类,在初始化bean的时候会执行该方法。

下面看下简单的例子:(环境是用Spring Boot搭建,直接用SpringtestApplication启动即可)

<bean id="myInitializingBean" class="com.paic.phssp.springtest.init.MyInitializingBean" init-method="testInit"></bean>
package com.paic.phssp.springtest.init;

import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component; import javax.annotation.PostConstruct; /**
* 继承InitializingBean接口的类,在初始化bean的时候会执行该方法
*/
//@Component
public class MyInitializingBean implements InitializingBean { public MyInitializingBean() {
System.out.println("MyInitializingBean....");
} @Override
public void afterPropertiesSet() throws Exception {
System.out.println("ceshi MyInitializingBean>>>>>>>>>>>>>>>>>>>");
} @PostConstruct //功能上近似init-method,但加载时机不同
public void test(){
System.out.println("PostConstruct >>>>>>>>>>>>");
} public void testInit(){
System.out.println("ceshi init-method");
}
}

结果:

MyInitializingBean....
PostConstruct >>>>>>>>>>>>
ceshi MyInitializingBean>>>>>>>>>>>>>>>>>>>
ceshi init-method

说明:

通过上述输出结果,三者的先后顺序也就一目了然了:

Constructor > @PostConstruct > InitializingBean > init-method

(1)通过查看spring的加载bean的源码类(AbstractAutowireCapableBeanFactory)可看出其中奥妙:

AbstractAutowireCapableBeanFactory.invokeInitMethods

protected void invokeInitMethods(String beanName, Object bean, @Nullable RootBeanDefinition mbd) throws Throwable {
boolean isInitializingBean = bean instanceof InitializingBean;
if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
if (this.logger.isTraceEnabled()) {
this.logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
} if (System.getSecurityManager() != null) {
try {
AccessController.doPrivileged(() -> {
((InitializingBean)bean).afterPropertiesSet();
return null;
}, this.getAccessControlContext());
} catch (PrivilegedActionException var6) {
throw var6.getException();
}
} else {
((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)) {
this.invokeCustomInitMethod(beanName, bean, mbd);
}
} }

说明:

a、spring为bean提供了两种初始化bean的方式,实现InitializingBean接口,实现afterPropertiesSet方法,或者在配置文件中同过init-method指定,两种方式可以同时使用
b、实现InitializingBean接口是直接调用afterPropertiesSet方法,比通过反射调用init-method指定的方法效率相对来说要高点。但是init-method方式消除了对spring的依赖
c、如果调用afterPropertiesSet方法时出错,则不调用init-method指定的方法。
d、@PostConstruct注解后的方法在BeanPostProcessor前置处理器中就被执行了,所以当然要先于InitializingBean和init-method执行了。
 
下面看@PostConstruct加载过程,主要看CommonAnnotationBeanPostProcessor.class。看下面UML图:
 

看下源码:InitDestroyAnnotationBeanPostProcessor.class

public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
InitDestroyAnnotationBeanPostProcessor.LifecycleMetadata metadata = this.findLifecycleMetadata(bean.getClass()); try {
        //利用反射,执行注解方法
metadata.invokeInitMethods(bean, beanName);
return bean;
} catch (InvocationTargetException var5) {
throw new BeanCreationException(beanName, "Invocation of init method failed", var5.getTargetException());
} catch (Throwable var6) {
throw new BeanCreationException(beanName, "Failed to invoke init method", var6);
}
} private InitDestroyAnnotationBeanPostProcessor.LifecycleMetadata findLifecycleMetadata(Class<?> clazz) {
if (this.lifecycleMetadataCache == null) {
return this.buildLifecycleMetadata(clazz);
} else {
InitDestroyAnnotationBeanPostProcessor.LifecycleMetadata metadata = (InitDestroyAnnotationBeanPostProcessor.LifecycleMetadata)this.lifecycleMetadataCache.get(clazz);
if (metadata == null) {
Map var3 = this.lifecycleMetadataCache;
synchronized(this.lifecycleMetadataCache) {
metadata = (InitDestroyAnnotationBeanPostProcessor.LifecycleMetadata)this.lifecycleMetadataCache.get(clazz);
if (metadata == null) {
metadata = this.buildLifecycleMetadata(clazz);
this.lifecycleMetadataCache.put(clazz, metadata);
} return metadata;
}
} else {
return metadata;
}
}
} private InitDestroyAnnotationBeanPostProcessor.LifecycleMetadata buildLifecycleMetadata(Class<?> clazz) {
List<InitDestroyAnnotationBeanPostProcessor.LifecycleElement> initMethods = new ArrayList();
List<InitDestroyAnnotationBeanPostProcessor.LifecycleElement> destroyMethods = new ArrayList();
Class targetClass = clazz; do {
List<InitDestroyAnnotationBeanPostProcessor.LifecycleElement> currInitMethods = new ArrayList();
List<InitDestroyAnnotationBeanPostProcessor.LifecycleElement> currDestroyMethods = new ArrayList();
ReflectionUtils.doWithLocalMethods(targetClass, (method) -> {
       //判断是否是指定的注解类型
if (this.initAnnotationType != null && method.isAnnotationPresent(this.initAnnotationType)) {
InitDestroyAnnotationBeanPostProcessor.LifecycleElement element = new InitDestroyAnnotationBeanPostProcessor.LifecycleElement(method);
currInitMethods.add(element);
if (this.logger.isTraceEnabled()) {
this.logger.trace("Found init method on class [" + clazz.getName() + "]: " + method);
}
} if (this.destroyAnnotationType != null && method.isAnnotationPresent(this.destroyAnnotationType)) {
currDestroyMethods.add(new InitDestroyAnnotationBeanPostProcessor.LifecycleElement(method));
if (this.logger.isTraceEnabled()) {
this.logger.trace("Found destroy method on class [" + clazz.getName() + "]: " + method);
}
} });
initMethods.addAll(0, currInitMethods);
destroyMethods.addAll(currDestroyMethods);
targetClass = targetClass.getSuperclass();
} while(targetClass != null && targetClass != Object.class); return new InitDestroyAnnotationBeanPostProcessor.LifecycleMetadata(clazz, initMethods, destroyMethods);
}

方法:buildLifecycleMetadata(),判断是否是指定的注解类型,而这个属性,在CommonAnnotationBeanPostProcessor.class构造方法中被初始化为PostConstruct。

public CommonAnnotationBeanPostProcessor() {
this.setOrder(2147483644);
this.setInitAnnotationType(PostConstruct.class);
this.setDestroyAnnotationType(PreDestroy.class);
this.ignoreResourceType("javax.xml.ws.WebServiceContext");
}

那么问题来了,以上只能说明实现了BeanPostProcessor的postProcessBeforeInitialization()方法,不足说明@PostConstruct 先InitializingBean 。

再看AbstractAutowireCapableBeanFactory.class 的initializeBean()方法。

protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged(() -> {
this.invokeAwareMethods(beanName, bean);
return null;
}, this.getAccessControlContext());
} else {
this.invokeAwareMethods(beanName, bean);
} Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = this.applyBeanPostProcessorsBeforeInitialization(bean, beanName);
} try {
this.invokeInitMethods(beanName, wrappedBean, mbd);
} catch (Throwable var6) {
throw new BeanCreationException(mbd != null ? mbd.getResourceDescription() : null, beanName, "Invocation of init method failed", var6);
} if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = this.applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
} return wrappedBean;
}

这下明显了,下面小结下:

BeanPostProcessor的实现类注册到Spring IOC容器后,对于该Spring IOC容器所创建的每个bean实例在初始化方法(如afterPropertiesSet和任意已声明的init方法)调用前,将会调用BeanPostProcessor中的postProcessBeforeInitialization方法,而在bean实例初始化方法调用完成后,则会调用BeanPostProcessor中的postProcessAfterInitialization方法,整个调用顺序可以简单示意如下:
--> Spring IOC容器实例化Bean
--> 调用BeanPostProcessor的postProcessBeforeInitialization方法 (@PostConstruct在此)
--> 调用bean实例的初始化方法(invokeInitMethods-> InitializingBean->init-method)
--> 调用BeanPostProcessor的postProcessAfterInitialization方法

参考:https://blog.csdn.net/zl834205311/article/details/78802584

DisposableBean
在Bean生命周期结束前调用destory()方法做一些收尾工作,亦可以使用destory-method。
前者与Spring耦合高,使用类型强转.方法名(),效率高
后者耦合低,使用反射,效率相对低
 
首先看下入口代码结构:

其中AbstractApplicationContext.refresh()

@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
// 为刷新工作做一些当前上下文 context 上的准备工作
prepareRefresh(); // Tell the subclass to refresh the internal bean factory.
// ApplicationContext 实现了 BeanFactory 接口,但是并非直接作为 Bean 容器。
// ApplicationContext 中真正直接作为 Bean 容器的是一个内部Bean工厂 BeanFactory,
// 通过其方法 getBeanFactory() 得到,此方法在 AbstractApplicationContext 中
// 被声明为 abstract, 其实现要求由实现子类提供。下面的语句 obtainFreshBeanFactory()
// 内部就是通过调用 getBeanFactory() 获得这个内部 Bean 工厂的。
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context.
// 准备当前上下文使用的Bean容器 BeanFactory,设置其标准上下文特征,比如类加载器等
// 1. BeanFactory 的类加载器设置为当前上下文的类加载器
// 2. BeanFactory 的Bean表达式解析器设置为 new StandardBeanExpressionResolver()
// 3. BeanFactory 增加 BeanPostProcessror new ApplicationListenerDetector(this)
// 4.三个单例Bean被注册 : environment,systemProperties,systemEnvironment
prepareBeanFactory(beanFactory); try {
// Allows post-processing of the bean factory in context subclasses.
// 在当前上下文使用的Bean容器BeanFactory的标准初始化完成后对其做一些修改。此时
// 所有的Bean definition都已经加载但是还没有 Bean 被创建。
// 当前上下文使用的Bean容器 BeanFactory 的 post process
// 1.当前上下文是 EmbeddedWebApplicationContext 时,
// 这个步骤中会对 beanFactory 注册一个 BeanPostProcessor :
// WebApplicationContextServletContextAwareProcessor
// 2.当前上下文是 AnnotationConfigEmbeddedWebApplicationContext 时,
// 如果设置了 basePackages,
// 这里会使用 AnnotatedBeanDefinitionReader扫描basePackages;
// 如果设置了 annotatedClasses,
// 这里会使用 ClassPathBeanDefinitionScanner登记annotatedClasses;
postProcessBeanFactory(beanFactory); // Invoke factory processors registered as beans in the context.
// 在 beanFactory 上调用 BeanFactoryPostProcessors,
// 当前上下文可能会有多个 BeanFactoryPostProcessor 需要应用在 beanFactory 上
// ****************************************************************
// 这里需要尤其注意区别 BeanFactoryPostProcessor 和 BeanPostProcessor
// BeanFactoryPostProcessor : 作用在 Bean定义 上,用来定制修改 Bean定义
// BeanPostProcessor :作用在 Bean实例 上,用来修改或者包装 Bean实例
// **************************************************************** // 该方法实际上将实现委托出去 :
// PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors()
invokeBeanFactoryPostProcessors(beanFactory); // Register bean processors that intercept bean creation.
// 注册 BeanPostProcessor
// 该步骤实际工作委托给工具类 PostProcessorRegistrationDelegate 的静态方法
// void registerBeanPostProcessors(
// ConfigurableListableBeanFactory beanFactory,
// AbstractApplicationContext applicationContext)
registerBeanPostProcessors(beanFactory); // Initialize message source for this context.
initMessageSource(); // Initialize event multicaster for this context.
// 初始化当前上下文ApplicationContext要使用的 事件多播器
// ApplicationEventMulticaster applicationEventMulticaster。
//
// 如果容器中已经注册类型为ApplicationEventMulticaster并且名称为
// applicationEventMulticaster 的Bean,则直接使用;否则,
// 新建一个SimpleApplicationEventMulticaster实例并注册到
// Bean容器,Bean名称使用 applicationEventMulticaster。
initApplicationEventMulticaster(); // Initialize other special beans in specific context subclasses.
// AbstractApplicationContext 中 onRefresh() 方法实现为空,其目的就是
// 留给实现子类一个机会做一些上下文相关的刷新工作。在一些特殊Bean初始化时,单
// 例 singleton Bean 初始化之前该方法被调用。
// 1. 当前上下文是 EmbeddedWebApplicationContext 时,该步骤会创建一个
// 内置的 Servlet 容器, 具体参考 EmbeddedWebApplicationContext 的
// 方法 void createEmbeddedServletContainer()
onRefresh(); // Check for listener beans and register them.
// 1. 将外部指定到当前上下文的 ApplicationListener 实例关联到上下文多播器
// Q : 什么时候外部给当前上下文指定 ApplicationListener ?
// A : 举例说明,Springboot 应用 SpringApplication 的情况下,是在
// prepareContext()结尾时SpringApplicationRunListeners的
// contextLoaded() 调用中发生的,此时正在广播事件
// ApplicationPreparedEvent
// 2. 将实现了 ApplicationListener 接口的所有 Bean 关联到上下文多播器
// 3. 如果上下文属性earlyApplicationEvents中有要通知的事件,广播出去
registerListeners(); // Instantiate all remaining (non-lazy-init) singletons.
// 完成 BeanFactory 的初始化工作
// 1.BeanFactory冻结所有的Bean定义:不再可以修改或者做post process操作
// 2.确保所有的non-lazy-init单例Bean被初始化,也包括FactoryBean
// 3.如果所初始化的单例Bean实现了接口SmartInitializingSingleton,调用
// 其方法 afterSingletonsInstantiated()
finishBeanFactoryInitialization(beanFactory); // Last step: publish corresponding event.
// 1. 初始化生命周期处理器 LifecycleProcessor, 使用已经存在的Bean或者
// 一个新的DefaultLifecycleProcessor实例;
// 2. 生命周期处理器 LifecycleProcessor 上传播 refresh 事件
// 3. 发布事件 ContextRefreshedEvent
// 4. 如果存在 LiveBeansView MBean 的话,关联到当前上下文
// 当前上下文是EmbeddedWebApplicationContext的情况下,还会:
// 5. 启动EmbeddedServletContainer,比如启动内置 tomcat容器
// 6. 发布事件 EmbeddedServletContainerInitializedEvent
finishRefresh();
} catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
} // Destroy already created singletons to avoid dangling resources.
destroyBeans(); // Reset 'active' flag.
cancelRefresh(ex); // Propagate exception to caller.
throw ex;
} finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}

org.springframework.context.support.AbstractApplicationContext#refresh的这一行代码

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
refreshBeanFactory();
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (logger.isDebugEnabled()) {
logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
}
return beanFactory;
}

org.springframework.context.support.AbstractRefreshableApplicationContext#refreshBeanFactory

 protected final void refreshBeanFactory() throws BeansException {
if (this.hasBeanFactory()) {
this.destroyBeans();
this.closeBeanFactory();
} try {
DefaultListableBeanFactory beanFactory = this.createBeanFactory();
beanFactory.setSerializationId(this.getId());
this.customizeBeanFactory(beanFactory);
this.loadBeanDefinitions(beanFactory);
Object var2 = this.beanFactoryMonitor;
synchronized(this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
} catch (IOException var5) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + this.getDisplayName(), var5);
}
}

进入到这个方法org.springframework.context.support.AbstractApplicationContext#destroyBeans

protected void destroyBeans() {
this.getBeanFactory().destroySingletons();
}

org.springframework.beans.factory.support.DefaultListableBeanFactory#destroySingletons

@Override
public void destroySingletons() {
super.destroySingletons();
// 清除记录的单例beanName的缓存
this.manualSingletonNames.clear();
clearByTypeCache();
}
org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#destroySingletons
@Override
public void destroySingletons() {
super.destroySingletons();
// 清空beanFactory缓存
this.factoryBeanObjectCache.clear();
} public void destroySingletons() {
if (logger.isDebugEnabled()) {
logger.debug("Destroying singletons in " + this);
}
// 这里使用ConcurrentHashMap本地缓存单例的bean实例,访问次数比较多,提搞并发量
synchronized (this.singletonObjects) {
this.singletonsCurrentlyInDestruction = true;
} String[] disposableBeanNames;
// 这里是用LinkedHashMap本地缓存销毁的bean实例
synchronized (this.disposableBeans) {
disposableBeanNames = StringUtils.toStringArray(this.disposableBeans.keySet());
}
for (int i = disposableBeanNames.length - 1; i >= 0; i--) {
// 销毁单例的bean
destroySingleton(disposableBeanNames[i]);
} this.containedBeanMap.clear();
this.dependentBeanMap.clear();
this.dependenciesForBeanMap.clear(); // 同步清空缓存
synchronized (this.singletonObjects) {
this.singletonObjects.clear();
this.singletonFactories.clear();
this.earlySingletonObjects.clear();
this.registeredSingletons.clear();
this.singletonsCurrentlyInDestruction = false;
}
} public void destroySingleton(String beanName) {
// Remove a registered singleton of the given name, if any.删除单例的bean,从本地缓存中删除
removeSingleton(beanName); // Destroy the corresponding DisposableBean instance.
DisposableBean disposableBean;
synchronized (this.disposableBeans) {
// 从本地缓存中删除
disposableBean = (DisposableBean) this.disposableBeans.remove(beanName);
}
// bean销毁的逻辑
destroyBean(beanName, disposableBean);
} protected void destroyBean(String beanName, @Nullable DisposableBean bean) {
// Trigger destruction of dependent beans first... 先触发依赖的bean销毁,从本地缓存中删除
Set<String> dependencies = this.dependentBeanMap.remove(beanName);
if (dependencies != null) {
if (logger.isDebugEnabled()) {
logger.debug("Retrieved dependent beans for bean '" + beanName + "': " + dependencies);
}
for (String dependentBeanName : dependencies) {
// 这里用了一个递归删除单例bean,当这个bean没有依赖的bean要删除的时候,递归结束
destroySingleton(dependentBeanName);
}
} // Actually destroy the bean now... 这里开始删除单例bean
if (bean != null) {
try {
// bean可以实现DisposableBean这个接口,重写父类的bean destory的方法
bean.destroy();
}
catch (Throwable ex) {
logger.error("Destroy method on bean with name '" + beanName + "' threw an exception", ex);
}
} // Trigger destruction of contained beans...从本地缓存中销毁内部bean
Set<String> containedBeans = this.containedBeanMap.remove(beanName);
if (containedBeans != null) {
for (String containedBeanName : containedBeans) {
// 这个地方还是递归调用,删除单例bean,当这个bean没有内部bean时递归结束
destroySingleton(containedBeanName);
}
} // Remove destroyed bean from other beans' dependencies. 从其他bean依赖中删除销毁的bean
synchronized (this.dependentBeanMap) {
for (Iterator<Map.Entry<String, Set<String>>> it = this.dependentBeanMap.entrySet().iterator(); it.hasNext();) {
Map.Entry<String, Set<String>> entry = it.next();
Set<String> dependenciesToClean = entry.getValue();
dependenciesToClean.remove(beanName);
if (dependenciesToClean.isEmpty()) {
it.remove();
}
}
} // Remove destroyed bean's prepared dependency information.删除销毁的bean准备的依赖信息
this.dependenciesForBeanMap.remove(beanName);
}
bean可以实现DisposableBean这个接口,重写父类的bean destory的方法
 注意:此处destroyBean将会被字类重写,用适配器模式销毁
org.springframework.beans.factory.support.DisposableBeanAdapter#destroy
@Override
public void destroy() {
// 执行beanPostProcessors,beanPostProcessors用对对bean的过程进行处理的抽象
if (!CollectionUtils.isEmpty(this.beanPostProcessors)) {
for (DestructionAwareBeanPostProcessor processor : this.beanPostProcessors) {
// 在bean销毁之前进行一些处理
processor.postProcessBeforeDestruction(this.bean, this.beanName);
}
} if (this.invokeDisposableBean) {
if (logger.isDebugEnabled()) {
logger.debug("Invoking destroy() on bean with name '" + this.beanName + "'");
}
try {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
((DisposableBean) bean).destroy();
return null;
}, acc);
}
else {
// bean实现DisposableBean接口的方式,注解调用子类destroy方法
((DisposableBean) bean).destroy();
}
}
catch (Throwable ex) {
String msg = "Invocation of destroy method failed on bean with name '" + this.beanName + "'";
if (logger.isDebugEnabled()) {
logger.warn(msg, ex);
}
else {
logger.warn(msg + ": " + ex);
}
}
} if (this.destroyMethod != null) {
// 执行bean定义中指定的bean销毁方法
invokeCustomDestroyMethod(this.destroyMethod);
}
else if (this.destroyMethodName != null) {
Method methodToCall = determineDestroyMethod(this.destroyMethodName);
if (methodToCall != null) {
invokeCustomDestroyMethod(methodToCall);
}
}
}

具体结构如下:

参考:
https://my.oschina.net/u/3775437/blog/1810419
 
 
 
 

InitializingBean和DisposableBean的更多相关文章

  1. Spring InitializingBean and DisposableBean example

    In Spring, InitializingBean and DisposableBean are two marker interfaces, a useful way for Spring to ...

  2. Spring中Bean的生命中期与InitializingBean和DisposableBean接口

    Spring提供了一些标志接口,用来改变BeanFactory中的bean的行为.它们包括InitializingBean和DisposableBean.实现这些接口将会导致BeanFactory调用 ...

  3. Spring Bean InitializingBean和DisposableBean实例

    在Spring中,InitializingBean和DisposableBean是两个标记接口,为Spring执行时bean的初始化和销毁某些行为时的有用方法. 对于Bean实现 Initializi ...

  4. InitializingBean 和 DisposableBean 指定初始化和销毁方法

    通过实现 InitializingBean 和 DisposableBean 接口,也可以指定 bean 的初始化和销毁方法 二.Student 类 public class Student impl ...

  5. 13、生命周期-InitializingBean和DisposableBean

    13.生命周期-InitializingBean和DisposableBean InitializingBean接口 package org.springframework.beans.factory ...

  6. 【Spring注解驱动开发】使用InitializingBean和DisposableBean来管理bean的生命周期,你真的了解吗?

    写在前面 在<[Spring注解驱动开发]如何使用@Bean注解指定初始化和销毁的方法?看这一篇就够了!!>一文中,我们讲述了如何使用@Bean注解来指定bean初始化和销毁的方法.具体的 ...

  7. spring InitializingBean和DisposableBean init-method 和destroy-method @PostConstruct @PreDestroy

    对于初始化函数: @PostConstruct 注解的方法 InitializingBean接口定义的回调afterPropertiesSet() Bean配置中自定义的初始化函数 对于析构则与上相同 ...

  8. Spring的InitializingBean与DisposableBean方法

    在bean初始化的时候,将所有显示提供的属性设置完毕后调用这个方法 org.springframework.beans.factory.InitializingBean#afterProperties ...

  9. Spring bean 实现InitializingBean和DisposableBean接口实现初始化和销毁前操作

    # InitializingBean接口> Spring Bean 实现这个接口,重写afterPropertiesSet方法,这样spring初始化完这个实体类后会调用这个方法```@Over ...

随机推荐

  1. 守护进程,互斥锁,IPC,队列,生产者与消费者模型

    小知识点:在子进程中不能使用input输入! 一.守护进程 守护进程表示一个进程b 守护另一个进程a 当被守护的进程结束后,那么守护进程b也跟着结束了 应用场景:之所以开子进程,是为了帮助主进程完成某 ...

  2. Java1.7 HashMap 实现原理和源码分析

    HashMap 源码分析是面试中常考的一项,下面一篇文章讲得很好,特地转载过来. 本文转自:https://www.cnblogs.com/chengxiao/p/6059914.html 参考博客: ...

  3. spring配置jax-ws

    在spring配置文件中新建bean(或者是在配置文件中添加bean),在该bean中添加指定的访问地址. @Bean public static SimpleJaxWsServiceExporter ...

  4. How to Rerun Failed Tests in JUnit?

    该帖转自其他出处 Sometimes due to some temporarily problems such as connection problems, server problems, br ...

  5. Oracle SQL——varchar2() 和 char()关联查询 存在空格

    背景 表dbcontinfo 字段loanid,类型为varchar2(60) 表dbloanbal 字段loanid,类型为char(60) loanid字段实际长度为24位 问题 两张表dbloa ...

  6. 枚举+排序|神奇算式|2014年蓝桥杯A组题解析第三题-fishers

    标题:神奇算式 由4个不同的数字,组成的一个乘法算式,它们的乘积仍然由这4个数字组成. 比如: 210 x 6 = 1260 8 x 473 = 3784 27 x 81 = 2187 都符合要求. ...

  7. POJ 3903 Stock Exchange(LIS || 线段树)题解

    题意:求最大上升子序列 思路:才发现自己不会LIS,用线段树写的,也没说数据范围就写了个离散化,每次查找以1~a[i]-1结尾的最大序列答案,然后更新,这样遍历一遍就行了.最近代码总是写残啊... 刚 ...

  8. ProgrammingError: You must not use 8-bit bytestrings...

    问题出现: You must not use 8-bit bytestrings unless you use a text_factory that can interpret 8-bit byte ...

  9. Css下拉菜单设置

    <style type="text/css"> *{margin:0px;padding:0px;}设置所有标签属性<初始化页面属性> #nav{backg ...

  10. LightOJ 1258 Making Huge Palindromes(KMP)

    题意 给定一个字符串 \(S\) ,一次操作可以在这个字符串的右边增加任意一个字符.求操作之后的最短字符串,满足操作结束后的字符串是回文. \(1 \leq |S| \leq 10^6\) 思路 \( ...