当前位置: 首页 > news >正文

SpringBoot设计了哪些可拓展的机制?

SpringBoot核心源码

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {  ...this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));// Servletthis.webApplicationType = WebApplicationType.deduceFromClasspath();  this.bootstrapRegistryInitializers = new ArrayList(this.getSpringFactoriesInstances(BootstrapRegistryInitializer.class));  // 注意这里,Initializersthis.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));  // 注意这里 Listenersthis.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));  this.mainApplicationClass = this.deduceMainApplicationClass();  
}
复制代码

我们可以看到空的SpringBoot项目有一些initializers以及一些listeners

注意这两行,换言之我们只要实现这两个类就可以自定义拓展SpringBoot了!

这里和手写Starter都是对SpringBoot的拓展,有兴趣的小伙伴可以看这篇文章

拓展Initializer

再看这张图

我们需要研究一下ApplicationContextInitializer这个类:

@FunctionalInterface  
public interface ApplicationContextInitializer<C extends ConfigurableApplicationContext> {  /**  * Initialize the given application context.  * @param applicationContext the application to configure  */  void initialize(C applicationContext);  
}
复制代码

这样就很清晰了,我们尝试手写一个继承类:

public class DemoInitializer implements ApplicationContextInitializer {  @Override  public void initialize(ConfigurableApplicationContext applicationContext) {  System.out.println("自定义初始化器执行...");  ConfigurableEnvironment environment =  applicationContext.getEnvironment();  Map<String, Object> map = new HashMap<>(1);  map.put("name", "sccccc");  environment.getPropertySources().addLast(new  MapPropertySource("DemoInitializer", map));  System.out.println("DemoInitializer execute, and add some property");  }  
}
复制代码

通过SPI机制将自定义初始化器交给list集合initializers

然后再debug,就会发现:

最后经过一次回调:

private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context,  ...  applyInitializers(context);  ...// Add boot specific singleton beans 下面是beanFactory的操作
复制代码

遍历所有的初始化器,然后

/**  
* Apply any {@link ApplicationContextInitializer}s to the context before it is  
* refreshed.  
* @param context the configured ApplicationContext (not refreshed yet)  
* @see ConfigurableApplicationContext#refresh()  
*/  
@SuppressWarnings({ "rawtypes", "unchecked" })  
protected void applyInitializers(ConfigurableApplicationContext context) {  for (ApplicationContextInitializer initializer : getInitializers()) {  Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(),  ApplicationContextInitializer.class);  Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");  initializer.initialize(context);  }  
}
复制代码

流程:

拓展监听器ApplicationListener

@FunctionalInterface  
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {  /**  * Handle an application event.  */  void onApplicationEvent(E event);  /**  * Create a new {@code ApplicationListener} for the given payload consumer.  */  static <T> ApplicationListener<PayloadApplicationEvent<T>> forPayload(Consumer<T> consumer) {  return event -> consumer.accept(event.getPayload());  }  }
复制代码

这里和上面initializer一样,就不演示了

BeanFactory的后置处理器 & Bean的后置处理器

Spring Boot解析配置成BeanDefinition的操作在invokeBeanFactoryPostProcessors方法中 自定义BeanFactory的后置处理器:

@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactorybeanFactory) throws BeansException {Arrays.asList(beanFactory.getBeanDefinitionNames()).forEach(beanDefinitionName ->System.out.println(beanDefinitionName));System.out.println("BeanFactoryPostProcessor...");}
}
复制代码

自定义Bean的后置处理器:

@Component
public class MyBeanPostProcessor implements BeanPostProcessor {@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName)throws BeansException {if(beanName.equals("userController")){System.out.println("找到了userController: "+bean);}return null;}
}
复制代码

AOP

这个相信大家用的比较多,可以自定义切面:

@Aspect
@Component
public class LogAspect {// 切入点 Pointcut   可以对Service服务做切面
@Pointcut("execution(* com.example.service.*.*(..))")
public void mypointcut(){}// 前置通知
@Before(value = "mypointcut()")
public void before(JoinPoint joinPoint){System.out.println("[前置通知] 准备开始记录日志...");System.out.println("[前置通知] 目标类是: "+joinPoint.getTarget());System.out.println("[前置通知] 目标方法是:"+joinPoint.getSignature().getName());
}// 后置通知
@AfterReturning(value = "mypointcut()")
public void afterReturning(JoinPoint joinPoint){System.out.println("[后置通知] 记录日志完成...");System.out.println("[后置通知] 目标类是: "+joinPoint.getTarget());System.out.println("[后置通知] 目标方法是:"+joinPoint.getSignature().getName());
}/*@Around(value = "mypointcut()")
public void around(ProceedingJoinPoint joinPoint){System.out.println("[环绕通知] 日志记录前的操作...");try {joinPoint.proceed();System.out.println("[环绕通知] 日志记录后的操作...");System.out.println("[环绕通知] "+joinPoint.getTarget());System.out.println("[环绕通知] "+joinPoint.getSignature().getName());} catch (Throwable throwable) {System.out.println("[环绕通知] 发生异常的操作...");throwable.printStackTrace();}finally {...}
}
复制代码

其他的拓展点

  1. Banner

方法地址: printBanner(env)->bannerPrinter.print->SpringBootBanner#printBanner

可以在resource目录下建立banner.txt文件夹实现自定义Banner

  1. Runners

流程:

自定义:

@Component
public class JackApplicationRunner implements ApplicationRunner {@Overridepublic void run(ApplicationArguments args) throws Exception {System.out.println("JackApplicationRunner...");}
}

http://www.lryc.cn/news/60486.html

相关文章:

  • Layer组件多个iframe弹出层打开与关闭及参数传递
  • BearPi环境搭建及基本使用
  • 算法笔记-换根DP
  • LeetCode 785. Is Graph Bipartite【DFS,二分图】中等
  • 【微信小程序】-- 分包 - 独立分包 分包预下载(四十五)
  • 2.3 连续性随机变量
  • 【DES详解】(一)处理input block(64 bits)
  • redis笔记——三种特殊的数据结构
  • 网络安全之编码加密算法
  • mp4视频无法播放的解决方法
  • 搭建Mysql
  • 气传导和骨传导耳机哪个好?简单科普这两种蓝牙耳机
  • 浅尝GoWeb开发之Gin框架
  • 工程行业管理系统-专业的工程管理软件-提供一站式服务
  • 目标检测YOLO系列-YOLOV7运行步骤(推理、训练全过程)
  • Spring Boot + Spring Security基础入门教程
  • MySQL数据库,表的增删改查详细讲解
  • SpringCloud-Gateway实现网关
  • Redis 如何配置读写分离架构(主从复制)?
  • 代码随想录二刷day05 | 哈希表之242.有效的字母异位词 349. 两个数组的交集 202. 快乐数 1. 两数之和
  • 2023年4月广东省计算机软考中/高级备考班招生简章
  • 在Github中77k星的王炸AutoGPT,会独立思考,直接释放双手
  • FVM链的Themis Pro,5日ido超百万美元
  • OpenCV实战——尺度不变特征检测器
  • 如何快速建立一个podman环境
  • 计算机视觉:人工智能领域当下火热的计算机视觉技术综述
  • EMC 专用名词大全~骚扰波形
  • 14:24面试,14:32就出来了 ,问的实在是太...
  • 高频算法题
  • AI工程师眼中的未来 | 年轻人如何求职选方向