Spring源码二IOC容器源码

server/2024/10/9 9:04:36/

文章目录

    • Spring IOC初始化
    • 源码剖析
      • 1.prepareRefresh
      • 2.obtainFreshBeanFactory
      • 3.prepareBeanFactory
      • 4.postProcessBeanFactory
      • 5.invokeBeanFactoryPostProcessors
      • 6.registerBeanPostProcessors
      • 7.initMessageSource
      • 8.initApplicationEventMulticaster
      • 9.onRefresh
      • 10.registerListeners
      • 11.finishBeanFactoryInitialization
        • 11.1createBeanInstance
        • 11.2populateBean
        • 11.3initializeBean
      • 12.finishRefresh
      • 13.销毁阶段

Spring IOC初始化

ApplicationContext 是 Spring 的核心接口,表示 Spring 的 IOC 容器,以下三个类是ApplicationContext 接口的常用实现类:ClassPathXmlApplicationContext,AnnotationConfigApplicationContext,FileSystemXmlApplicationContext。

  • ClassPathXmlApplicationContext:这个实现类用于从 classpath 中加载 XML 配置文件来初始化 IoC 容器。
  • AnnotationConfigApplicationContext:这个实现类用于从 Java 配置类如带有@Configuration 注解的类中加载配置信息来初始化 IoC 容器。
  • FileSystemXmlApplicationContext:这个实现类用于从文件系统的指定路径加载 XML 配置文件来初始化 IoC容器。

本文采用第一种方式来初始化IOC容器,首先引入Spring5.3.27版本的依赖,不同版本的实现略有差异,但整体实现逻辑是相同的。

java">    <dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.3.27</version></dependency>

创建一个接口CourseService

java">@Service
public interface CourseService {String getCourseName();
}

接口的实现类CourseServiceImpl

java">public class CourseServiceImpl implements CourseService {@Overridepublic String getCourseName() {return "Spring IOC源码";}
}

配置文件application.xml

java"><?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="courseService" class="com.czl.spring.CourseServiceImpl"/>
</beans>

启动测试类TestSpring

java">public class TestSpring {public static void main(String[] args) {ApplicationContext applicationContext = new ClassPathXmlApplicationContext("application.xml");System.out.println("启动Spring IOC");CourseService courseService = applicationContext.getBean(CourseService.class);System.out.println(courseService.getCourseName());}
}

运行结果
在这里插入图片描述

源码剖析

首先从这行代码ApplicationContext applicationContext = new ClassPathXmlApplicationContext("application.xml");进行debug,

java">	public ClassPathXmlApplicationContext(String configLocation) throws BeansException {this(new String[] {configLocation}, true, null);}

主要执行以下三个方法

java">	public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)throws BeansException {super(parent);setConfigLocations(configLocations);if (refresh) {refresh();}}
  1. super(parent):调用父类的构造方法super(parent),通过创建PathMatchingResourcePatternResolver来设置Bean的资源加载器。
  2. setConfigLocations(configLocations):将Bean的定义资源文件添加到当前的执行程序中。
java">//解析配置文件的路径,处理多个资源文件可以用字符串数组  
public void setConfigLocations(@Nullable String... locations) {if (locations != null) {Assert.noNullElements(locations, "Config locations must not be null");this.configLocations = new String[locations.length];for (int i = 0; i < locations.length; i++) {this.configLocations[i] = resolvePath(locations[i]).trim();}}else {this.configLocations = null;}}

通过源码可以看出,可以使用一个字符串数组来配置多个Spring 的配置文件,比如下面通过字符串数组可以直接配置两个XML配置文件。

java"> String []strXML ={"application.xml","application2.xml"};
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(strXML);
  1. refresh():用于初始化和刷新IoC容器,实现bean的注册、实例化和初始化等过程,最终创建出一个完整的Bean对象。

所有的核心方法都在refresh()中实现。

java">public void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");//执行容器刷新前的方法prepareRefresh();// 将BeanDefinition注册到DefaultListableBeanFactory的beanDefinitionMap中ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();// 为beanFactory设置一些默认的属性和方法prepareBeanFactory(beanFactory);try {// 子类对Bean工厂进行后处理postProcessBeanFactory(beanFactory);// 调用注册为Bean的工厂处理器invokeBeanFactoryPostProcessors(beanFactory);// 解析Bean创建的Bean前后处理器registerBeanPostProcessors(beanFactory);// 结束Bean工厂后处理器的处理beanPostProcess.end();// 初始化消息源initMessageSource();// 初始化事件多播器initApplicationEventMulticaster();// 没有具体实现,在上下文子类中可以初始化其他特殊的BeanonRefresh();// 检查并注册监听器registerListeners();// 实例化所有剩余的非懒加载的单例BeanfinishBeanFactoryInitialization(beanFactory);// 发布相应的刷新事件finishRefresh();}// 结束刷新上下文contextRefresh.end();}
}

1.prepareRefresh

该方法主要执行容器刷新前的操作。

  • 设置容器启动时间:this.startupDate = System.currentTimeMillis();
  • 设置关闭状态为false:this.closed.set(false);
  • 设置活跃状态为true:this.active.set(true);
  • 获取environment对象,并将系统的属性值加到environment对象:getEnvironment().validateRequiredProperties();
  • 创建监听器和事件的集合:this.earlyApplicationEvents = new LinkedHashSet<>();
java">protected void prepareRefresh() {
//...this.startupDate = System.currentTimeMillis();this.closed.set(false);this.active.set(true);getEnvironment().validateRequiredProperties();this.earlyApplicationEvents = new LinkedHashSet<>();}

2.obtainFreshBeanFactory

该方法主要执行以下两个方法

  • refreshBeanFactory:如果当前已经存在Bean工厂,则先销毁已有的Bean并关闭Bean工厂,再解析application.xml配置文件得到bean的定义信息BeanDefinition注册到DefaultListableBeanFactory 的 beanDefinitionMap 中

  • getBeanFactory:返回 DefaultListableBeanFactory

java">	protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {refreshBeanFactory();return getBeanFactory();}
java">protected final void refreshBeanFactory() throws BeansException {// 如果当前已经存在Bean工厂,则先销毁已有的Bean并关闭Bean工厂if (hasBeanFactory()) {destroyBeans();closeBeanFactory();}try {// 创建一个新的DefaultListableBeanFactory实例作为Bean工厂DefaultListableBeanFactory beanFactory = createBeanFactory();// 设置Bean工厂的序列化IDbeanFactory.setSerializationId(getId());customizeBeanFactory(beanFactory);// 将Bean定义信息从配置文件加载到Bean工厂中loadBeanDefinitions(beanFactory);// 将刚创建的Bean工厂赋值给当前容器的beanFactory属性this.beanFactory = beanFactory;}
}

关键方法 loadBeanDefinitions(beanFactory);

java">protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {// 创建XmlBeanDefinitionReader实例,用于读取XML配置文件的Bean定义XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);beanDefinitionReader.setEnvironment(this.getEnvironment());beanDefinitionReader.setResourceLoader(this);beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));initBeanDefinitionReader(beanDefinitionReader);// 加载Bean定义loadBeanDefinitions(beanDefinitionReader);
}

通过loadBeanDefinitions(beanDefinitionReader)去加载beanDefinition

java">protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {// 获取XML配置文件的数组Resource[] configResources = getConfigResources();// 如果数组不为空,则去加载配置文件的Bean定义if (configResources != null) {reader.loadBeanDefinitions(configResources);}// 获取XML配置文件的路径String[] configLocations = getConfigLocations();// 如果数组不为空,则加载这些配置文件中的Bean定义if (configLocations != null) {reader.loadBeanDefinitions(configLocations);}
}

继续执行loadBeanDefinitions(configResources);

java">	public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {try (InputStream inputStream = encodedResource.getResource().getInputStream()) {InputSource inputSource = new InputSource(inputStream);if (encodedResource.getEncoding() != null) {inputSource.setEncoding(encodedResource.getEncoding());}//加载配置文件的Bean定义return doLoadBeanDefinitions(inputSource, encodedResource.getResource());}}
java">protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)throws BeanDefinitionStoreException {try {// 将XML配置文件封装成doc文档Document doc = doLoadDocument(inputSource, resource);// 注册Bean定义,并返回注册的数量int count = registerBeanDefinitions(doc, resource);if (logger.isDebugEnabled()) {logger.debug("Loaded " + count + " bean definitions from " + resource);}return count;}}

执行registerBeanDefinitions(doc, resource);

java">	public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();int countBefore = getRegistry().getBeanDefinitionCount();//使用documentReader注册Bean的定义信息documentReader.registerBeanDefinitions(doc, createReaderContext(resource));// 返回注册的Bean数量return getRegistry().getBeanDefinitionCount() - countBefore;}public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {this.readerContext = readerContext;//从XML文档的根节点开始注册Bean定义doRegisterBeanDefinitions(doc.getDocumentElement());}protected void doRegisterBeanDefinitions(Element root) {//...// 先对XML文档进行预处理preProcessXml(root);// 解析XML中的bean定义parseBeanDefinitions(root, this.delegate);// 解析bean之后,对XML进行后置处理postProcessXml(root);this.delegate = parent;}
java">protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {//...// 解析XML中的bean定义parseDefaultElement(ele, delegate);}
// 根据不同的标签进行解析,有以下四种标签import、alias、bean、beans,重点关注bean
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {// 如果元素属于import标签if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {// 处理import的元素importBeanDefinitionResource(ele);}// 如果元素属于alias标签else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {// 处理alias的元素processAliasRegistration(ele);}// 如果元素是bean标签else if (delegate.nodeName转向ele, BEAN_ELEMENT)) {// 处理bean元素processBeanDefinition(ele, delegate);}// 如果元素是nested-beans标签else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {// 递归处理nested-beans元素doRegisterBeanDefinitions(ele);}
}

重点关注bean标签的处理方法processBeanDefinition(ele, delegate);

java">protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {// 解析当前元素,得到BeanDefinitionHolderBeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);// 如果bdHolder不为空if (bdHolder != null) {bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);try {// 开始注册BeanDefinition实例BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());}getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));}
}public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)throws BeanDefinitionStoreException {// 获取bean定义的名称String beanName = definitionHolder.getBeanName();//在注册表中注册bean定义registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());// 获取bean定义的所有别名String[] aliases = definitionHolder.getAliases();// 如果存在别名if (aliases != null) {// 遍历所有别名,并在注册表中为每个别名注册对应的bean名称for (String alias : aliases) {registry.registerAlias(beanName, alias);}}
}

真正注册bean的定义方法registerBeanDefinition

java">public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)throws BeanDefinitionStoreException {// 断言beanName不为空Assert.hasText(beanName, "Bean name must not be empty");// 断言beanDefinition不为空Assert.notNull(beanDefinition, "BeanDefinition must not be null");// 获取已存在的bean定义BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);//如果已存在bean定义if (existingDefinition != null) {// Spring不允许覆盖bean定义,会抛出BeanDefinitionOverrideExceptionif (!isAllowBeanDefinitionOverriding()) {throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);} // 更新bean定义映射信息this.beanDefinitionMap.put(beanName, beanDefinition);}else {// 将beanName和beanDefinition存储到beanDefinitionMap中this.beanDefinitionMap.put(beanName, beanDefinition);this.beanDefinitionNames.add(beanName);removeManualSingletonName(beanName);}}

总结:首先获取xml 配置文件的路径,通过 documentLoader 将文件封装成 Doc 格式,再通过BeanDefinitionDocumentReader 来解析 xml 文件,从xml文件的根节点开始遍历,根据不同的标签(import、alias、bean、beans)组装成 beanDefinition,再根据 BeanName 查询 beanDefinition 是否已经注册,如果注册过,则直接抛出异常,如果没有注册,则将 BeanName 作为key, beanDefinition作为value 注册到 DefaultListableBeanFactory 的 beanDefinitionMap 中。

3.prepareBeanFactory

该方法主要为DefaultListableBeanFactory类型的beanFactory设置一些默认的属性和方法。

4.postProcessBeanFactory

该方法没有具体实现,不过子类通过该方法对Bean工厂进行处理。

5.invokeBeanFactoryPostProcessors

该方法可以对 beanFactory 的 BeanDefinition 进行修改。

6.registerBeanPostProcessors

该方法会解析Bean创建的Bean前后处理器,前后处理器会在 Bean 初始化方法前后调用,比如下面的例子

java">public class ExampleBeanPostProcessor implements BeanPostProcessor {@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {// 前置处理System.out.println("bean初始化的前置操作");return bean;}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {// 后置处理System.out.println("bean初始化的后置操作");return bean;}
}

执行结果

java">bean初始化的前置操作
bean初始化
bean初始化的后置操作

另外,AOP的功能也是在这个方法里实现的。

7.initMessageSource

该方法主要初始化信息源,与实现Spring中国际化的功能有关。

8.initApplicationEventMulticaster

该方法主要初始化容器的事件传播器。

9.onRefresh

该方法默认没有具体实现,在子类中可以初始化其他特殊的Bean。

10.registerListeners

该方法主要为事件传播器注册事件监听器,为广播事件服务。

11.finishBeanFactoryInitialization

该方法是IOC容器中最核心的方法,主要实例化所有剩余的非懒加载的单例Bean,包括实例化,属性填充,初始化等操作。

java">protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {// 实例化所有的单例beanbeanFactory.preInstantiateSingletons();
}public void preInstantiateSingletons(){// 从beanDefinitions获取所有的beanName集合List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);		// 遍历集合,初始化beanfor (String beanName : beanNames) {// 通过beanName获取beangetBean(beanName);}
}
public Object getBean(String name) throws BeansException {// 获取bean,依赖注入也是在该方法实现的return doGetBean(name, null, null, false);
}protected <T> T doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly){// 根据name得到beanNameString beanName = transformedBeanName(name);// 检查缓存中是否有单例对象Object sharedInstance = getSingleton(beanName);//如果bean是单例的,会解决循环依赖,如果是原型模式,则会直接抛出异常if (isPrototypeCurrentlyInCreation(beanName)) {throw new BeanCurrentlyInCreationException(beanName);}if (mbd.isSingleton()) {// 得到beanName的对应的单例对象sharedInstance = getSingleton(beanName, () -> {try {//创建bean实例 return createBean(beanName, mbd, args);}});
}protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args){//创建bean实例Object beanInstance = doCreateBean(beanName, mbdToUse, args);
}protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args){// 实例化beanBeanWrapper instanceWrapper = createBeanInstance(beanName, mbd, args);// 填充bean的属性populateBean(beanName, mbd, instanceWrapper);// 执行初始化bean的方法exposedObject = initializeBean(beanName, exposedObject, mbd);
}

总结:创建bean实例主要有以下步骤,首先遍历beanDefinitionNames得到每一个beanName,根据BeanName到单例缓存中查找是否已经存在实例,如果存在直接返回,如果不存在,则根据beanName的 beanDefinition 生成bean实例, 实例的生成分为三个步骤:

  1. createBeanInstance 创建实例。
  2. populateBean 进行属性填充。
  3. initializeBean 进行初始化操作:先执行 BeanPostProcessor 的前置方法,再执行bean对象的初始化方法,最后执行 BeanPostProcessor 的后置方法。
11.1createBeanInstance

首先是创建实例的方法

java">BeanWrapper instanceWrapper = createBeanInstance(beanName, mbd, args);protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {// 根据beanName得到ClassClass<?> beanClass = resolveBeanClass(mbd, beanName);// 通过无参构造创建实例return instantiateBean(beanName, mbd);
}protected BeanWrapper instantiateBean(String beanName, RootBeanDefinition mbd) {// 实例化操作beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, this);
}public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {// 加锁保证线程安全synchronized (bd.constructorArgumentLock) {// 得到bean的ClassClass<?> clazz = bd.getBeanClass();// 通过class得到构造方法constructorToUse = clazz.getDeclaredConstructor();// 反射方式创建实例 return BeanUtils.instantiateClass(constructorToUse);}
}public static <T> T instantiateClass(Constructor<T> ctor, Object... args) {// 通过反射的方式创建实例return ctor.newInstance(argsWithDefaultValues);
}
11.2populateBean

属性填充就是将property标签的value注入给对象的属性name。

java"><bean id="messageService" class="com.mashibing.hls.MessageServiceImpl"><property name="example" value="value"/>
</bean>
java">protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {// 得到BeanDefinition的属性valuePropertyValues pvs = mbd.getPropertyValues();if (pvs != null) {// 将value注入给属性nameapplyPropertyValues(beanName, mbd, bw, pvs);}
}protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs){// 获取PropertyValue对象数组存储到列表List<PropertyValue> original = Arrays.asList(pvs.getPropertyValues());    for (PropertyValue pv : original) {// 获取属性的nameString propertyName = pv.getName();// 获取valueObject originalValue = pv.getValue();      // 设置属性值bw.setPropertyValues(new MutablePropertyValues(deepCopy));}
}public void setPropertyValues(PropertyValues pvs){setPropertyValues(pvs, false, false);
}public void setPropertyValues(PropertyValues pvs, boolean ignoreUnknown, boolean ignoreInvalid){// 通过反射的方式进行赋值setPropertyValue(pv);
}
11.3initializeBean

初始化的过程就是在执行 BeanPostProcessor 的前后置方法过程中穿插执行init方法。

java">// 初始化方法
exposedObject = initializeBean(beanName, exposedObject, mbd);protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {//调用postProcessBeforeInitialization方法,返回原始Bean包装器wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);//调用初始化方法invokeInitMethods(beanName, wrappedBean, mbd);// 调用postProcessAfterInitialization方法,再返回Bean包装器wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);//返回包装后的Beanreturn wrappedBean;
}// 执行BeanPostProcessors接口下的类
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName){Object result = existingBean;//遍历BeanPostProcessors列表for (BeanPostProcessor processor : getBeanPostProcessors()) {// 返回给定的BeanObject current = processor.postProcessBeforeInitialization(result, beanName);// 如果 current为nullif (current == null) {//直接返回resultreturn result;}result = current;}//返回经过后置处理后的resultreturn result;
}protected void invokeInitMethods(String beanName, Object bean, @Nullable RootBeanDefinition mbd){// 如果mbd不为空且bean不是NullBeanif (mbd != null && bean.getClass() != NullBean.class) {// 获取初始化方法名String initMethodName = mbd.getInitMethodName();// 调用自定义的init方法invokeCustomInitMethod(beanName, bean, mbd);// 反射执行方法Method methodToInvoke = ClassUtils.getInterfaceMethodIfPossible(initMethod);methodToInvoke.invoke(bean);}
}// 执行所有的BeanPostProcessors接口下的类
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName){//初始化结果对象为result,默认引用existingBeanObject result = existingBean;//遍历BeanPostProcessors列表for (BeanPostProcessor processor : getBeanPostProcessors()) {//postProcessAfterInitialization对bean实例进行包装Object current = processor.postProcessAfterInitialization(result, beanName);// 如果current为nullif (current == null) {//直接返回resultreturn result;}result = current;}//返回包装后的resultreturn result;}

12.finishRefresh

到这所有的对象已经创建完成,容器已经完成启动,该方法会发布容器的生命周期事件。

13.销毁阶段

创建完对象就可以正常使用,使用完成后就进入销毁阶段,Spring会调用close方法销毁

java">public void close() {synchronized (this.startupShutdownMonitor) {//销毁beandoClose();}
}protected void doClose() {// 清空BeanFactory的缓存destroyBeans();// 再将beanFactory置为nullcloseBeanFactory();
}protected void destroyBeans() {// 清除beanName与Bean包含的Bean名称集的映射集合this.containedBeanMap.clear();// 清除beanName与一组相关的Bean名称的映射集合this.dependentBeanMap.clear();// 清除beanName与bean依赖项的映射集合this.dependenciesForBeanMap.clear();// 清除注册表中所有的单例实例clearSingletonCache();
}protected void clearSingletonCache() {// 使用singletonObjects对象进行同步,确保只有一个线程可以执行清除方法synchronized (this.singletonObjects) {       // 清空singletonObjects集合,该集合存储了所有的单例Bean实例this.singletonObjects.clear();     // 清空singletonFactories集合,该集合存储了所有的单例Bean工厂this.singletonFactories.clear();    // 清空earlySingletonObjects集合,该集合存储了早期暴露的单例Bean实例this.earlySingletonObjects.clear();    // 清空registeredSingletons集合,该集合存储了所有已注册的单例Bean名称this.registeredSingletons.clear(); // 将标志设置为false,表示当前没有单例Bean正在销毁this.singletonsCurrentlyInDestruction = false;}
}private void clearByTypeCache() {// 清空按类型缓存的Bean名称集合this.allBeanNamesByType.clear();// 清空按类型缓存的单例Bean名称的集合this.singletonBeanNamesByType.clear();
}protected final void closeBeanFactory() {DefaultListableBeanFactory beanFactory = this.beanFactory;if (beanFactory != null) {beanFactory.setSerializationId(null);// 将beanFactory设置为空this.beanFactory = null;}
}

另外可以在配置文件中自定义初始化 init 和销毁 destory 的方法

java">public class CourseServiceImpl implements CourseService  {@Overridepublic String getCourseName() {return "Spring IOC源码";}public void init(){System.out.println("类的初始化阶段");}public void destroy(){System.out.println("类的销毁阶段");}}

然后在配置文件添加对应的标签即可。

java"><bean id="courseService" class="com.czl.spring.CourseServiceImpl" init-method="init" destroy-method="destroy"/>

http://www.ppmy.cn/server/129188.html

相关文章

机器人的性能指标

1. 负荷能力 负荷能力负荷能力是指机器人在满足其他性能要求的情况下,能够承载的负荷重量。例如,一台机器人的最大负荷能力可能远大于它的额定负荷能力,但是达到最大负荷时,机器人的工作精度可能会降低,可能无法准确地沿着预定的轨迹运动,或者产生额外的偏差。机器人的负荷量与…

【微服务】服务注册与发现、分布式配置管理 - Nacos

概述 Nacos是阿里巴巴旗下的一个开源产品&#xff0c;目前市场使用率还是比较高的。在最初开源时&#xff0c;Nacos选择内部三个产品合并并统一开源&#xff0c;这三个产品分别是&#xff1a;非持久化注册中心&#xff08;Configserver&#xff09;、持久化注册中心&#xff0…

设计模式——构建者模式

提问&#xff1a;通过对比使用构建者模式和不使用构建者模式&#xff0c;以更好的说明构建者模式的作用 GPT&#xff1a;当然&#xff0c;我很乐意通过对比来帮助您更好地理解构建者模式的作用。让我们以一个复杂对象的创建为例&#xff0c;比如一个计算机&#xff08;Computer…

奇异值分解SVD

文章目录 奇异值是什么&#xff1f;1 奇异值的定义2 奇异值的性质3 特征值与奇异值的关系4 奇异值的重要性 奇异值分解 奇异值是什么&#xff1f; 1 奇异值的定义 对于任意一个 m n m \times n mn 的矩阵 A A A&#xff0c;存在三个矩阵 U U U&#xff0c; V V V和 Σ \Si…

OpenCV高级图形用户界面(3)关闭由 OpenCV 创建的指定窗口函数destroyWindow()的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 销毁指定的窗口。 该函数 destroyWindow 销毁具有给定名称的窗口。 函数原型 void cv::destroyWindow (const String & winname ) 参数 …

基于Springboot+Vue的公寓出租系统 (含源码数据库)

1.开发环境 开发系统:Windows10/11 架构模式:MVC/前后端分离 JDK版本: Java JDK1.8 开发工具:IDEA 数据库版本: mysql5.7或8.0 数据库可视化工具: navicat 服务器: SpringBoot自带 apache tomcat 主要技术: Java,Springboot,mybatis,mysql,vue 2.视频演示地址 3.功能 这个系…

【智能算法应用】人工水母搜索算法求解二维路径规划问题

摘要 本文应用人工水母搜索算法&#xff08;Jellyfish Search, JFS&#xff09;求解二维空间中的路径规划问题。水母搜索算法是一种新型的智能优化算法&#xff0c;灵感来源于水母的群体运动行为&#xff0c;通过模仿水母的觅食、漂浮等行为&#xff0c;实现全局最优路径的搜索…

成功解决STM32-No ST-LINK detected问题!

在使用STM32开发板进行编程时&#xff0c;我们可能会遇到“No ST-LINK Detected”的问题&#xff0c;这通常意味着开发环境无法识别或连接到ST-LINK调试器。以下是一些可能的原因和相应的解决方法。 一、原因分析 接线问题&#xff1a;可能是ST-LINK与STM32开发板之间的连接不…