手写SpringBoot(四)之bean动态加载

news/2024/4/30 10:02:24

系列文章目录

手写SpringBoot(一)之简易版SpringBoot
手写SpringBoot(二)之动态切换Servlet容器
手写SpringBoot(三)之自动配置
手写SpringBoot(四)之bean动态加载

手写SpringBoot(四)之bean动态加载

本节巩固一下@ConditionalOnClass的相关逻辑,主要新增@ConditionalOnMissingBean注解

SpringBoot配置了很多类,如果用户不希望使用springboot自动配置的那个类怎么办?

如果用户强行配置了一个相同的类,SpringBoot会选择使用哪一个呢?

这就需要按需加载了,如果用户配置了相同的类,则SpringBoot就不加载自己配置的那个。这就是ConditionalOnMissingBean的由来,如果这个bean缺失了,则SpringBoot将这个Bean配置上,如果这个Bean由用户配置了,则自己配置的bean作弃。


前置工作,将MyConditionalOnClass,MyClassCondition 迁移到my-spring-boot-configuration模块下面


ConditionalOnMissingBean 逻辑实现

  1. 定义@MyConditionalOnMissingBean注解
package cn.axj.springboot.my.annotation;import cn.axj.springboot.my.condition.MyMissingBeanCondition;
import org.springframework.context.annotation.Conditional;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE,ElementType.METHOD})
@Conditional(MyMissingBeanCondition.class)
public @interface MyConditionalOnMissingBean {String value();
}
  1. 实现MissBean的判断逻辑,新增MyMissingBeanCondition
package cn.axj.springboot.my.condition;import cn.axj.springboot.my.annotation.MyConditionalOnMissingBean;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;import java.util.Map;
import java.util.Objects;public class MyMissingBeanCondition implements Condition {@Overridepublic boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {Map<String, Object> annotationAttributes = metadata.getAnnotationAttributes(MyConditionalOnMissingBean.class.getName());/*** 获取{@link MyConditionalOnMissingBean}注解中的属性值* 例如:@MyConditionalOnMissingBean(value = "com.example.MyBean")* 则可以通过annotationAttributes.get("value")获取到"com.example.MyBean"*/String beanName = (String) annotationAttributes.get("value");ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();Object bean = null;try {//这里简单点,根据beanName获取bean,实际中需要更复杂的逻辑来判断是否缺失bean = beanFactory.getBean(beanName);return false;} catch (BeansException e) {BeanFactory parentBeanFactory = beanFactory.getParentBeanFactory();try {if(Objects.isNull(parentBeanFactory)){return true;}bean = parentBeanFactory.getBean(beanName);return false;} catch (BeansException ex) {return true;}}}
}

至此@ConditionalOnMissingBean逻辑开发完成


测试

在UserApplication中配置tomcatWebServer

	@Beanpublic TomcatWebServer tomcatWebServer(){System.out.println("userApplication tomcatWebServer init");return new TomcatWebServer();}

在my-spring-boot模块WebServerAutoConfiguration中,配置tomcatWebServer中加上注解@ConditionalOnMissingBean

@Bean@MyConditionalOnClass("org.apache.catalina.startup.Tomcat")@MyConditionalOnMissingBean("tomcatWebServer")public TomcatWebServer tomcatWebServer() {System.out.println("mySpringboot tomcatWebServer init");return new TomcatWebServer();}

启动user-application,

userApplication tomcatWebServer init
三月 29, 2024 5:20:31 下午 org.springframework.context.annotation.ConfigurationClassPostProcessor enhanceConfigurationClasses
信息: Cannot enhance @Configuration bean definition 'userApplication' 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'.
启动TomcatWeb容器
三月 29, 2024 5:20:31 下午 org.apache.coyote.AbstractProtocol init
信息: Initializing ProtocolHandler ["http-nio-8080"]
三月 29, 2024 5:20:31 下午 org.apache.catalina.core.StandardService startInternal
信息: Starting service [Tomcat]
三月 29, 2024 5:20:31 下午 org.apache.catalina.core.StandardEngine startInternal
信息: Starting Servlet engine: [Apache Tomcat/9.0.75]
三月 29, 2024 5:20:32 下午 org.apache.catalina.util.SessionIdGeneratorBase createSecureRandom
警告: Creation of SecureRandom instance for session ID generation using [SHA1PRNG] took [320] milliseconds.
三月 29, 2024 5:20:32 下午 org.apache.coyote.AbstractProtocol start
信息: Starting ProtocolHandler ["http-nio-8080"]

可以看到只有userApplication tomcatWebServer init打印,没有mySpringboot tomcatWebServer init打印,证明spring-boot只加载了用户定义的那个tomcatWebServer

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.cpky.cn/p/11278.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈,一经查实,立即删除!

相关文章

4、Cocos Creator 动画系统

目录 1、Clip 参数 2、动画编辑器 3、基本操作 更改时间轴缩放比例 移动显示区域 更改当前选中的时间轴节点 播放 / 暂停动画 修改 clip 属性 快捷键 4、模拟实验 5、动画事件 6、注意事项 参考 Animation 组件是节点上的一个组件。Clip 动画剪辑就是一份动画的声…

迭代实现二叉树的遍历-算法通关村

迭代实现二叉树的遍历-算法通关村 理论上&#xff0c;递归能做的迭代一定能做&#xff0c;但可能会比较复杂。有时候面试官要求不使用递归实现三种遍历&#xff0c;递归就是每次执行方法调用都会先把当前的局部变量、参数值和返回地址等压入栈中&#xff0c;后面在递归返回的时…

C# NumericUpDown 控件正整数输入控制

用到了控件的 KeyPress 和 KeyUp事件。 KeyPress 中控制输入“点、空格&#xff0c;负号”&#xff1b; KeyUp 中防止删空&#xff0c;以及防止输入超过最大值或最小值 。 private void nudStart_KeyPress(object sender, KeyPressEventArgs e){numericUpDownKeyPress(sender…

SpringBoot整合腾讯云邮件发送服务非STMP

SpringBoot整合腾讯云邮箱服务 1、pom配置 <!-- 腾讯云邮箱服务--><dependency><groupId>com.tencentcloudapi</groupId><artifactId>tencentcloud-sdk-java</artifactId><!-- go to https://search.maven.org/search?qtencen…

硬件15、PCB如何将元器件切换顶层和底层以及元器件布局对齐

器件切换顶层和底层 在移动元器件的时候&#xff0c;按一下 L 键&#xff0c;原器件就会变为蓝色&#xff0c;这就是放到了底层&#xff0c;然后再按 L 键就可以切换到顶层了 元器件放置后布局如何变得对齐那种 首先选中需要对齐的元器件&#xff0c;然后进行设置布局的属性…

vue3+threejs新手从零开发卡牌游戏(二十):添加卡牌被破坏进入墓地逻辑

在game目录下新建graveyard文件夹存放墓地相关代码&#xff1a; game/graveyard/p1.vue&#xff0c;这里主要设置了墓地group的位置&#xff1a; <template><div></div> </template><script setup lang"ts"> import { reactive, ref,…