likes
comments
collection
share

Spring Bean生命周期详解和应用(下)

作者站长头像
站长
· 阅读数 12

前言

《Spring Bean生命周期详解和应用(上)》开始我们整体了解了spring bean生命周期并有了一定的感知,到《Spring Bean生命周期详解和应用(中)》我们从顶层思维开始通过阅读源码对spring bean生命周期进一步深入。

从了解到深入,还差最后一步,就是应用。通过《Spring Bean生命周期详解和应用(中)》中的顶层思维图,我们很容易清楚spring bean生命周期的本质是在bean实例化、属性赋值、初始化、销毁各个阶段中提供了包裹它们的扩展点。

Spring Bean生命周期详解和应用(下)

下面我们就来看看不同扩展点该如何应用以及何时应用。

BeanFactoryPostProcessor#postProcessBeanFactory

用于在Spring应用程序启动期间修改Bean Factory的Bean定义,它通常被用于以下场景:

  1. 对Bean Definition进行自定义修改,例如更改其属性值、添加新的属性等。
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
    log.info("调用BeanFactoryPostProcessor#postProcessBeanFactory");
    BeanDefinition bd = beanFactory.getBeanDefinition("person");
    bd.getPropertyValues().addPropertyValue("phone", "110");
}
  1. 注册新的Bean定义,将对象纳入Spring的管理范畴。
 @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        // 1. 获取 AbstractOrderHandler 接口的实现类
        Map<String, AbstractOrderHandler> orderHandlerMap = beanFactory.getBeansOfType(AbstractOrderHandler.class);
        // 2. 订单类别 对应的 具体实现类
        Map<OrderTypeEnum, Class<?>> map = new HashMap<>();

        orderHandlerMap.forEach((k,v) -> {
            OrderHandlerType orderHandlerType = v.getClass().getDeclaredAnnotation(OrderHandlerType.class);
            OrderTypeEnum orderTypeEnum = orderHandlerType.value();
            map.put(orderTypeEnum, v.getClass());
        });
        // 将 订单类别 对应的 具体实现类 的 map 存储到 applicationContext 中
        beanFactory.registerSingleton(OrderHandlerType.class.getName(), map);
    }
  1. 配置Bean的AOP代理。
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
    BeanNameAutoProxyCreator proxyCreator = new BeanNameAutoProxyCreator();
    proxyCreator.setBeanNames("*Service"); // 匹配所有以"Service"结尾的bean名称 
    proxyCreator.setInterceptorNames("myInterceptor");
    beanFactory.addBeanPostProcessor(proxyCreator);
}

源码例子-配置Bean的AOP代理

在AbstractApplicationContext#refrsh中就有invokeBeanFactoryPostProcessors(beanFactory)我们可以直接看看源码种是如何使用的:

Spring Bean生命周期详解和应用(下)

看到有三个,ConfigurationClassPostProcessor比较熟悉,可以进去看看它的使用:

/**
 * Prepare the Configuration classes for servicing bean requests at runtime
 * by replacing them with CGLIB-enhanced subclasses.
 */
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
   int factoryId = System.identityHashCode(beanFactory);
   if (this.factoriesPostProcessed.contains(factoryId)) {
      throw new IllegalStateException(
            "postProcessBeanFactory already called on this post-processor against " + beanFactory);
   }
   this.factoriesPostProcessed.add(factoryId);
   if (!this.registriesPostProcessed.contains(factoryId)) {
      // BeanDefinitionRegistryPostProcessor hook apparently not supported...
      // Simply call processConfigurationClasses lazily at this point then.
      processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory);
   }

   enhanceConfigurationClasses(beanFactory);
   beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
}

核心是enhanceConfigurationClasses(beanFactory)

public void enhanceConfigurationClasses(ConfigurableListableBeanFactory beanFactory) {
   Map<String, AbstractBeanDefinition> configBeanDefs = new LinkedHashMap<>();
   for (String beanName : beanFactory.getBeanDefinitionNames()) {
      BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName);
      Object configClassAttr = beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE);
      MethodMetadata methodMetadata = null;
      if (beanDef instanceof AnnotatedBeanDefinition) {
         methodMetadata = ((AnnotatedBeanDefinition) beanDef).getFactoryMethodMetadata();
      }
      if ((configClassAttr != null || methodMetadata != null) && beanDef instanceof AbstractBeanDefinition) {
         // Configuration class (full or lite) or a configuration-derived @Bean method
         // -> resolve bean class at this point...
         AbstractBeanDefinition abd = (AbstractBeanDefinition) beanDef;
         if (!abd.hasBeanClass()) {
            try {
               abd.resolveBeanClass(this.beanClassLoader);
            }
            catch (Throwable ex) {
               throw new IllegalStateException(
                     "Cannot load configuration class: " + beanDef.getBeanClassName(), ex);
            }
         }
      }
      if (ConfigurationClassUtils.CONFIGURATION_CLASS_FULL.equals(configClassAttr)) {
         if (!(beanDef instanceof AbstractBeanDefinition)) {
            throw new BeanDefinitionStoreException("Cannot enhance @Configuration bean definition '" +
                  beanName + "' since it is not stored in an AbstractBeanDefinition subclass");
         }
         else if (logger.isInfoEnabled() && beanFactory.containsSingleton(beanName)) {
            logger.info("Cannot enhance @Configuration bean definition '" + beanName +
                  "' since its singleton instance has been created too early. The typical cause " +
                  "is a non-static @Bean method with a BeanDefinitionRegistryPostProcessor " +
                  "return type: Consider declaring such methods as 'static'.");
         }
         configBeanDefs.put(beanName, (AbstractBeanDefinition) beanDef);
      }
   }
   if (configBeanDefs.isEmpty()) {
      // nothing to enhance -> return immediately
      return;
   }

   ConfigurationClassEnhancer enhancer = new ConfigurationClassEnhancer();
   for (Map.Entry<String, AbstractBeanDefinition> entry : configBeanDefs.entrySet()) {
      AbstractBeanDefinition beanDef = entry.getValue();
      // If a @Configuration class gets proxied, always proxy the target class
      beanDef.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);
      // Set enhanced subclass of the user-specified bean class
      Class<?> configClass = beanDef.getBeanClass();
      Class<?> enhancedClass = enhancer.enhance(configClass, this.beanClassLoader);
      if (configClass != enhancedClass) {
         if (logger.isTraceEnabled()) {
            logger.trace(String.format("Replacing bean definition '%s' existing class '%s' with " +
                  "enhanced class '%s'", entry.getKey(), configClass.getName(), enhancedClass.getName()));
         }
         beanDef.setBeanClass(enhancedClass);
      }
   }
}

这里会把BeanDefinition的设置为enhancedClass,就是使用了代理,符合第三个使用场景

增强的类做了一些处理,比如处理@Bean方法,并将他们添加到对应的BeanDefinition中,并将其返回值作为bean的实例。

enhance方法主要实现以下几个步骤:

  1. 创建Enhancer对象:Enhancer是CGLIB中用于生成动态代理类的类,它继承了ASM库的功能,并实现了很多高级特效。在创建Enhancer对象时,需要指定被代理类和类加载器。
  2. 设置CllbackFilter、Interceptors和Callback数组:CallbackFilter是用于确定哪些方法使用哪种拦截器的过滤器,Interceptors是拦截器集合,Callback数组则为每个被拦截的方法分配一个对应的拦截器。
  3. 创建代理类:通过调用Enhancer#create()方法,动态创建代理类,并设置相应的拦截器。
  4. 注册到BeanDefinitionRegistry:将生成的代理类注册到Spring的BeanDefinitionRegistry中,使其成为Spring管理的Bean。

InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation

在实例化目标bean之前执行,如果返回不为null那返回的就是代理bean,可以有效的抑制target bean的默认实例化。

这个用的较少,目前只看到ScriptFactoryPostProcessor使用,比如实现类用groovy,用于生成代理执行脚本。感兴趣可以参考《Spring中集成Groovy的四种方式》试下。

InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation

在Bean实例化之后,在Spring属性填充之前,执行自定义字段注入。如果返回true属性正常填充,返回false跳过属性填充还将阻止在bean实例上调用后续的InstantiationAwareBeanPostProcessor实例。

打个断点来看看有哪些InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation:

Spring Bean生命周期详解和应用(下)

看了下几乎所有源码都是返回true,因为一般的bean都需要完成属性的注入和填充。

InstantiationAwareBeanPostProcessor#postProcessProperties

在工厂将给定的属性应用于给定的bean之前对其进行后处理。它可以让开发者有机会在bean初始化之前对属性进行最后的修改和校验。可以修改或替换pvs参数中的PropertyValue对象来改变bean实例中的属性值。还可以返回一个新的PropertyValues对象,以完全替换原始的属性值列表。如果返回null,则原始值属性列表不变。

源码中找找,在AbstractAutowireCapableBeanFactory的populateBean方法上打个断点: Spring Bean生命周期详解和应用(下)

可以发现org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor,比较眼熟,可以用于把带有 @Autowired 或者 @Value的属性或方法的注入属性

源码例子-完成带有 @Autowired 或者 @Value的属性或方法注入属性

@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
   InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
   try {
      metadata.inject(bean, beanName, pvs);
   }
   catch (BeanCreationException ex) {
      throw ex;
   }
   catch (Throwable ex) {
      throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
   }
   return pvs;
}

这里就不详细介绍,下次单独出篇文章讲讲。

BeanNameAware#setBeanName

在Spring容器启动时,当一个bean实例被创建后,并且如果该bean实现了BeanNameAware接口,Spring容器会自动调用该实例的setBeanName(String beanName)方法,beanName为Spring容器中注册的名称,获得了beanName后可以用于其他用途。

public class MyBean implements BeanNameAware {

    private String beanName;

    public void doSomething() {
        System.out.println("This is " + beanName);
    }

    @Override
    public void setBeanName(String beanName) {
        this.beanName = beanName;
    }
}

如上doSomething方法使用回调后填充的beanName进行打印。

下面看看源码中使用的例子: Spring Bean生命周期详解和应用(下) 看到比较熟悉的PlaceholderConfigurerSupport

源码中的例子-PlaceholderConfigurerSupport#setBeanName

PlaceholderConfigurerSupport用于处理属性文件中的占位符。在Spring中,我们可以使用$(...)语法将属性定义为占位符,并使用PropertyPlaceholder或其子类属性来解析或替换这些占位符。

@Override
public void setBeanName(String beanName) {
   this.beanName = beanName;
}

用于检查避免解析自己的bean定义,以避免在属性文件位置中无法解析占位符。后一种情况可能发生在资源位置中的系统属性占位符上。

protected void doProcessProperties(ConfigurableListableBeanFactory beanFactoryToProcess,
      StringValueResolver valueResolver) {

   BeanDefinitionVisitor visitor = new BeanDefinitionVisitor(valueResolver);

   String[] beanNames = beanFactoryToProcess.getBeanDefinitionNames();
   for (String curName : beanNames) {
      // Check that we're not parsing our own bean definition,
      // to avoid failing on unresolvable placeholders in properties file locations.
      if (!(curName.equals(this.beanName) && beanFactoryToProcess.equals(this.beanFactory))) {
         BeanDefinition bd = beanFactoryToProcess.getBeanDefinition(curName);
         try {
            visitor.visitBeanDefinition(bd);
         }
         catch (Exception ex) {
            throw new BeanDefinitionStoreException(bd.getResourceDescription(), curName, ex.getMessage(), ex);
         }
      }
   }

   // New in Spring 2.5: resolve placeholders in alias target names and aliases as well.
   beanFactoryToProcess.resolveAliases(valueResolver);

   // New in Spring 3.0: resolve placeholders in embedded values such as annotation attributes.
   beanFactoryToProcess.addEmbeddedValueResolver(valueResolver);
}

和上面的setBeanName类似

BeanFactoryAware#setFactory

将拥有的工厂提供给bean实例的回调。可以使用回调提供的BeanFactory用于后续操作。

例如:

@Service
public class MyService {
    // service implementation
}
@Component
public class MyComponent implements BeanFactoryAware {
 
    private BeanFactory beanFactory;
 
    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
    }
 
    public void someMethod(){
        MyService myService = (MyService) beanFactory.getBean("myService");
        // use myService
    }
}

源码例子-PlaceholderConfigurerSupport#setBeanName

@Override
public void setBeanFactory(BeanFactory beanFactory) {
  this.beanFactory = beanFactory;
}
@Component
public class MyComponent implements BeanFactoryAware {
 
    private BeanFactory beanFactory;
 
    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
    }
 
    public void someMethod(){
        MyService myService = (MyService) beanFactory.getBean("myService");
        // use myService
    }
}

BeanPostProcessor#postProcessBeforeInitialization

在实例化后,在执行初始化方法(比如被@PostConstruct注释的方法)之前,调用它对bean进行自定义处理,比如修改Bean属性、注册代理对象等。

  • 修改Bean属性:
public class MyBeanPostProcessor implements BeanPostProcessor {
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if (bean instanceof MyService) {
            ((MyService) bean).setSomeProperty("custom");
        }
        return bean;
    }
}

  • 注册代理对象:
public class MyBeanPostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if (bean instanceof MyService) { // 判断当前处理的Bean是否是 MyService 类型
            MyService myService = (MyService) bean;
            return Proxy.newProxyInstance(
                    myService.getClass().getClassLoader(),
                    myService.getClass().getInterfaces(),
                    new MyInvocationHandler(myService)
            );
        }
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }
}

public class MyInvocationHandler implements InvocationHandler {

    private Object target; // 被代理的对象

    public MyInvocationHandler(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("Before " + method.getName() + "()"); // 执行目标方法前的逻辑
        Object result = method.invoke(target, args); // 执行目标方法
        System.out.println("After " + method.getName() + "()"); // 执行目标方法后的逻辑
        return result;
    }
}

实际例子-修改bean的属性

根据之前的源码解析在AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsBeforeInitialization打个断点看看有哪些BeanPostProcessor: Spring Bean生命周期详解和应用(下) 找到比较熟悉的 ConfigurationClassPostProcessor$ImportAwareBeanPostProcessor#postProcessBeforeInitialization:

@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
   if (bean instanceof ImportAware) {
      ImportRegistry ir = this.beanFactory.getBean(IMPORT_REGISTRY_BEAN_NAME, ImportRegistry.class);
      //获得通过Import引入的类
      AnnotationMetadata importingClass = ir.getImportingClassFor(ClassUtils.getUserClass(bean).getName());
      if (importingClass != null) {
         ((ImportAware) bean).setImportMetadata(importingClass);
      }
   }
   return bean;
}

获得了importingClass之后执行了setImportMetadata方法。比如这里的beanName为org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration

@Override
public void setImportMetadata(AnnotationMetadata importMetadata) {
   this.enableTx = AnnotationAttributes.fromMap(
         importMetadata.getAnnotationAttributes(EnableTransactionManagement.class.getName(), false));
   if (this.enableTx == null) {
      throw new IllegalArgumentException(
            "@EnableTransactionManagement is not present on importing class " + importMetadata.getClassName());
   }
}

对其属性enableTx进行了设置。

@PostConstruct

此时bean依赖注入已经完成,可以使用该注解注释方法进行任何初始化。

生产中使用的例子

自定义beanMap

private static Map<ContentVendorApp, ImageRiskHandle> imageAppMap;

@PostConstruct
public void init() {
    imageAppMap = new HashMap<>();
    imageAppMap.put(aImageRiskHandle.vendorApp(), aImageRiskHandle);
    imageAppMap.put(bImageRiskHandle.vendorApp(), bImageRiskHandle);
}

拿到实例化后的bean进行一些处理

@PostConstruct
public void init() {
    EventBusCenter.register(this);
}

做一些后续配置

在中《apollo更改配置刷新@ConfigurationProperties配置类》提到的apollo自动刷新配置类

/**
 * 注册configChangeListener监听指定的NameSpace,默认的业务配置都在与应用名命名的nameSpace,当然了如果希望监听到更多的自己去拿到配置的nameSpace也可以的
 */
@PostConstruct
public void registerApolloConfigChangeListener() {

    //从env中拿到所有已从Apollo加载的propertySource,获取监听的nameSpace
    CompositePropertySource apolloPropertySources = (CompositePropertySource) configurableEnvironment.getPropertySources().get("ApolloPropertySources");
    if (Objects.isNull(apolloPropertySources)) {
        return;
    }
    Collection<PropertySource<?>> propertySourceList = apolloPropertySources.getPropertySources();

    //注册监听所有加载的nameSpace
    propertySourceList.forEach(propertySource -> {

        ConfigChangeListener configChangeListener = changeEvent -> {
            for (String changedKey : changeEvent.changedKeys()) {
                log.info("apollo changed namespace:{} Key:{} value:{}", changeEvent.getNamespace(), changedKey, changeEvent.getChange(changedKey));
                String beanName = getBeanName(changedKey);
                configurationPropertiesBindingPostProcessor.postProcessBeforeInitialization(applicationContext.getBean(beanName), beanName);
            }
        };

        Config config = ConfigService.getConfig(propertySource.getName());
        config.addChangeListener(configChangeListener);
    });

}

InitializingBean#afterPropertiesSet

所有的bean属性都被设置。可以用于执行总体配置校验和最终初始化。 例子:

import org.springframework.beans.factory.InitializingBean;

public class OrderService implements InitializingBean {
    
    private InventoryService inventoryService;
    private PaymentService paymentService;
    
    public void setInventoryService(InventoryService inventoryService) {
        this.inventoryService = inventoryService;
    }
    
    public void setPaymentService(PaymentService paymentService) {
        this.paymentService = paymentService;
    }
    
    @Override
    public void afterPropertiesSet() throws Exception {
        if (inventoryService == null || paymentService == null) {
            throw new IllegalArgumentException("InventoryService and PaymentService must be set!");
        }
    }
    
    public void createOrder(Order order) {
        // Check inventory
        if (!inventoryService.checkInventory(order)) {
            throw new RuntimeException("Not enough inventory!");
        }
        
        // Pay for the order
        if (!paymentService.payForOrder(order)) {
            throw new RuntimeException("Payment failed!");
        }
        
        // Complete the order
        inventoryService.confirmOrder(order);
    }
}

源码例子

com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceWrapper#afterPropertiesSet

@Override
public void afterPropertiesSet() throws Exception {
    //if not found prefix 'spring.datasource.druid' jdbc properties ,'spring.datasource' prefix jdbc properties will be used.
    if (super.getUsername() == null) {
        super.setUsername(basicProperties.determineUsername());
    }
    if (super.getPassword() == null) {
        super.setPassword(basicProperties.determinePassword());
    }
    if (super.getUrl() == null) {
        super.setUrl(basicProperties.determineUrl());
    }
    if(super.getDriverClassName() == null){
        super.setDriverClassName(basicProperties.getDriverClassName());
    }

}

org.mybatis.spring.mapper.MapperFactoryBean

@Override
protected void checkDaoConfig() {
  super.checkDaoConfig();

  notNull(this.mapperInterface, "Property 'mapperInterface' is required");

  Configuration configuration = getSqlSession().getConfiguration();
  if (this.addToConfig && !configuration.hasMapper(this.mapperInterface)) {
    try {
      configuration.addMapper(this.mapperInterface);
    } catch (Exception e) {
      logger.error("Error while adding the mapper '" + this.mapperInterface + "' to configuration.", e);
      throw new IllegalArgumentException(e);
    } finally {
      ErrorContext.instance().reset();
    }
  }
}


# init-method指定的方法
是@PostConstructInitializingBean#afterPropertiesSet的平替,具体参考上面两个。

# BeanPostProcessor#postProcessAfterInitialization
在实例化后由BeanFactory或者BeanFactory创建的对象调用。可以对Bean实例做出进一步的操作或者修饰。

在`AbstractAutowireCapableBeanFactory#applyBeanPostProcessorAfterInitialization`中打个断点看看:
![image.png](https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/21fcaf34172940edab8dfc93f27f4b51~tplv-k3u1fbpfcp-watermark.image?)
可以看到熟悉的AnnotationAwareAspectJAutoProxyCreator:基于注解创建代理对象,并将代理对象注册到容器中,其主要作用是实现AOP切面功能,比如我们常使用的@Transactional@Aspect等。


## 源码例子-AnnotationAwareAspectJAutoProxyCreator
AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsAfterInitialization:
@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
		throws BeansException {

	Object result = existingBean;
	for (BeanPostProcessor processor : getBeanPostProcessors()) {
		Object current = processor.postProcessAfterInitialization(result, beanName);
		if (current == null) {
			return result;
		}
		result = current;
	}
	return result;
}

AbstractAutoProxyCreator#postProcessAfterInitialization:
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
	if (bean != null) {
		Object cacheKey = getCacheKey(bean.getClass(), beanName);
		if (this.earlyProxyReferences.remove(cacheKey) != bean) {
			return wrapIfNecessary(bean, beanName, cacheKey);
		}
	}
	return bean;
}
AbstractAutoProxyCreator#wrapIfNecessary:

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) { if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) { return bean; } if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) { return bean; } if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) { this.advisedBeans.put(cacheKey, Boolean.FALSE); return bean; }

// Create proxy if we have advice. Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null); if (specificInterceptors != DO_NOT_PROXY) { this.advisedBeans.put(cacheKey, Boolean.TRUE); Object proxy = createProxy( bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean)); this.proxyTypes.put(cacheKey, proxy.getClass()); return proxy; }

this.advisedBeans.put(cacheKey, Boolean.FALSE); return bean; }

具体可以参考[《Transaction Management源码阅读路径》](https://juejin.cn/post/7026715770650361869#heading-8)
# @PreDestory
用于标记在对象销毁之前需要进行清理操作的方法。常用于清理资源或执行一些必要的收尾工作,例如关闭数据库、释放文件句柄等。

public class DatabaseConnectionManager {

private Connection connection;

@PostConstruct
public void init() {
    // 初始化数据库连接
    connection = DriverManager.getConnection(url, username, password);
}

@PreDestroy
public void close() throws SQLException {
    // 关闭数据库连接
    connection.close();
}

}

## 实际例子

/**

  • 删除server表中记录,删除本服务器登陆的用户记录,防止其他服务器继续转发 */ @PreDestroy public void destroy(){ logger.info("SessionManager destroy begin"); chatServerService.offline(); logger.info("SessionManager destroy ok"); }
# DisposableBean#destory、destory-method
当实现DisposableBean#destory的Bean对象被Spring容器销毁时,destroy()方法会被自动调用。

和@PreDestory类型




转载自:https://juejin.cn/post/7243067221999271991
评论
请登录