面试官:Spring refresh过程是怎样的?

2023-11-12

小熊学Java网站:https://javaxiaobear.gitee.io/,每周持续更新干货,建议收藏!

 

1. Spring refresh 流程

refresh 是 AbstractApplicationContext 中的核心方法,负责初始化 ApplicationContext 容器,容器必须调用 refresh 才能正常工作。

 public void refresh() throws BeansException, IllegalStateException {
     //使用互斥锁,防止启动、关闭及注册函调函数的重复调用,保证上下文对象状态
         synchronized(this.startupShutdownMonitor) {
             StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
             //1.提前准备启动参数,预处理
             this.prepareRefresh();
             //2.获取BeanFactory;默认实现是DefaultListableBeanFactory,在创建容器的时候创建的
             ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
             //3.初始化和设置BeanFactory的参数
             this.prepareBeanFactory(beanFactory);
 
             try {
                 //4.调用BeanFactory的后置处理器,
                 this.postProcessBeanFactory(beanFactory);
                 StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
                //5.执行BeanFactoryPostProcessor的方法;
                 this.invokeBeanFactoryPostProcessors(beanFactory);
                  //6.在bean工厂中注册bean的后置处理器,bean的代理的生成也是由它实现的
                 this.registerBeanPostProcessors(beanFactory);
                 beanPostProcess.end();
                 //7.初始化消息源
                 this.initMessageSource();
                 //8.初始化消息推送器
                 this.initApplicationEventMulticaster();
                 //9.调用子类重写当前方法,是子类实现的扩展
                 this.onRefresh();
                 //10.注册应用的监听器。就是注册实现了ApplicationListener接口的监听器bean,这些监听器是注册到ApplicationEventMulticaster中的
                 this.registerListeners();
                 //11.把所有非延迟加载的bean初始化并设置冻结标志位
                 this.finishBeanFactoryInitialization(beanFactory);
                 //12.
                 this.finishRefresh();
             } catch (BeansException var10) {
                 if (this.logger.isWarnEnabled()) {
                     this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var10);
                 }
                 //销毁已经存在的bean
                 this.destroyBeans();
                 //释放标志位
                 this.cancelRefresh(var10);
                 throw var10;
             } finally {
                 //清除与反射相关的缓存,例如反射的方法、字段、类型解析已经类加载等
                 this.resetCommonCaches();
                 contextRefresh.end();
             }
 
         }
     }

它的内部主要会调用 12 个方法,我们把它们称为 refresh 的 12 个步骤:

  1. prepareRefresh

  2. obtainFreshBeanFactory

  3. prepareBeanFactory

  4. postProcessBeanFactory

  5. invokeBeanFactoryPostProcessors

  6. registerBeanPostProcessors

  7. initMessageSource

  8. initApplicationEventMulticaster

  9. onRefresh

  10. registerListeners

  11. finishBeanFactoryInitialization

  12. finishRefresh

功能分类

  • 1 为准备环境

  • 2 3 4 5 6 为准备 BeanFactory

  • 7 8 9 10 12 为准备 ApplicationContext

  • 11 为初始化 BeanFactory 中非延迟单例 bean

1. prepareRefresh

 protected void prepareRefresh() {
     //设置启动时间
     this.startupDate = System.currentTimeMillis();
     //撤销关闭状态
     this.closed.set(false);
     //开启活跃状态
     this.active.set(true);
     if (this.logger.isDebugEnabled()) {
         if (this.logger.isTraceEnabled()) {
             this.logger.trace("Refreshing " + this);
         } else {
             this.logger.debug("Refreshing " + this.getDisplayName());
         }
     }
     //初始化上下文信息
     this.initPropertySources();
     //验证属性
     this.getEnvironment().validateRequiredProperties();
     if (this.earlyApplicationListeners == null) {
         this.earlyApplicationListeners = new LinkedHashSet(this.applicationListeners);
     } else {
         this.applicationListeners.clear();
         this.applicationListeners.addAll(this.earlyApplicationListeners);
     }
 
     this.earlyApplicationEvents = new LinkedHashSet();
 }
  • 这一步创建和准备了 Environment 对象,它作为 ApplicationContext 的一个成员变量

  • Environment 对象的作用之一是为后续 @Value,值注入时提供键值

  • Environment 分成三个主要部分

    • systemProperties - 保存 java 环境键值

    • systemEnvironment - 保存系统环境键值

    • 自定义 PropertySource - 保存自定义键值,例如来自于 *.properties 文件的键值

2. obtainFreshBeanFactory

 protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
     //刷新beanFactory
     this.refreshBeanFactory();
     return this.getBeanFactory();
 }
  • 这一步获取(或创建) BeanFactory,它也是作为 ApplicationContext 的一个成员变量

  • BeanFactory 的作用是负责 bean 的创建、依赖注入和初始化,bean 的各项特征由 BeanDefinition 定义

    • BeanDefinition 作为 bean 的设计蓝图,规定了 bean 的特征,如单例多例、依赖关系、初始销毁方法等

    • BeanDefinition 的来源有多种多样,可以是通过 xml 获得、配置类获得、组件扫描获得,也可以是编程添加

  • 所有的 BeanDefinition 会存入 BeanFactory 中的 beanDefinitionMap 集合

3. prepareBeanFactory

 protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
     //设置类加载器
     beanFactory.setBeanClassLoader(this.getClassLoader());
     if (!shouldIgnoreSpel) {
         //设置 支持解析 SpEL的解析器
         beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
     }
 
     beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, this.getEnvironment()));
     //设置添加一个 tApplicationContextAwareProcessor 后置处理器
     beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
     //设置忽略的自动装配的接口,就是设置这些接口的实现类不能通过这些接口实现自动注入
     beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
     beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
     beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
     beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
     beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
     beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
     beanFactory.ignoreDependencyInterface(ApplicationStartupAware.class);
     //注册可以解析的自动装配,假设想要使用@Autowired 注解将Spring提供的 BeanFactory
     beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
     beanFactory.registerResolvableDependency(ResourceLoader.class, this);
     beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
     beanFactory.registerResolvableDependency(ApplicationContext.class, this);
     //设置添加一个ApplicationListenerDetector后置处理器
     beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
     //添加编译时支持AspectJ
     if (!NativeDetector.inNativeImage() && beanFactory.containsBean("loadTimeWeaver")) {
         beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
         beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
     }
 
     if (!beanFactory.containsLocalBean("environment")) {
         //注册单例bean environment,存储默认的属性
         beanFactory.registerSingleton("environment", this.getEnvironment());
     }
 
     if (!beanFactory.containsLocalBean("systemProperties")) {
         //注册单例bean systemProperties,存储系统属性
         beanFactory.registerSingleton("systemProperties", this.getEnvironment().getSystemProperties());
     }
 
     if (!beanFactory.containsLocalBean("systemEnvironment")) {
         //注册单例bean systemEnvironment,存储系统环境信息
         beanFactory.registerSingleton("systemEnvironment", this.getEnvironment().getSystemEnvironment());
     }
 
     if (!beanFactory.containsLocalBean("applicationStartup")) {
         //注册单例bean applicationStartup,系统启动
         beanFactory.registerSingleton("applicationStartup", this.getApplicationStartup());
     }
 
 }
  • 这一步会进一步完善 BeanFactory,为它的各项成员变量赋值

  • beanExpressionResolver 用来解析 SpEL,常见实现为 StandardBeanExpressionResolver

  • propertyEditorRegistrars 会注册类型转换器

    • 它在这里使用了 ResourceEditorRegistrar 实现类

    • 并应用 ApplicationContext 提供的 Environment 完成 ${ } 解析

  • registerResolvableDependency 来注册 beanFactory 以及 ApplicationContext,让它们也能用于依赖注入

  • beanPostProcessors 是 bean 后处理器集合,会工作在 bean 的生命周期各个阶段,此处会添加两个:

    • ApplicationContextAwareProcessor 用来解析 Aware 接口

    • ApplicationListenerDetector 用来识别容器中 ApplicationListener 类型的 bean

4. postProcessBeanFactory

 protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
 }
  • 这一步是空实现,留给子类扩展。

    • 一般 Web 环境的 ApplicationContext 都要利用它注册新的 Scope,完善 Web 下的 BeanFactory

  • 这里体现的是模板方法设计模式

5. invokeBeanFactoryPostProcessors

 protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
     //执行beanFactory后置处理器中的方法,该方法中获取所有BeanFactoryPostProcessor,遍历判断
     //对不同的BeanFactoryPostProcessor进行排序,因为先后执行的顺序不同,
     //PriorityOrdered>BeanDefinitionRegistryPostProcessor>BeanFactoryPostProcessor
     //然后执行后置处理器中定义的初始化 beanFactory 后要执行的方法
     PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, this.getBeanFactoryPostProcessors());
     if (!NativeDetector.inNativeImage() && beanFactory.getTempClassLoader() == null && beanFactory.containsBean("loadTimeWeaver")) {
         beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
         beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
     }
  • 这一步会调用 beanFactory 后处理器

  • beanFactory 后处理器,充当 beanFactory 的扩展点,可以用来补充或修改 BeanDefinition

  • 常见的 beanFactory 后处理器有

    • ConfigurationClassPostProcessor – 解析 @Configuration、@Bean、@Import、@PropertySource 等

    • PropertySourcesPlaceHolderConfigurer – 替换 BeanDefinition 中的 ${ }

    • MapperScannerConfigurer – 补充 Mapper 接口对应的 BeanDefinition

6. registerBeanPostProcessors

 protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
     PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);
 }
  • 这一步是继续从 beanFactory 中找出 bean 后处理器,添加至 beanPostProcessors 集合中

  • bean 后处理器,充当 bean 的扩展点,可以工作在 bean 的实例化、依赖注入、初始化阶段,常见的有:

    • AutowiredAnnotationBeanPostProcessor 功能有:解析 @Autowired,@Value 注解

    • CommonAnnotationBeanPostProcessor 功能有:解析 @Resource,@PostConstruct,@PreDestroy

    • AnnotationAwareAspectJAutoProxyCreator 功能有:为符合切点的目标 bean 自动创建代理

7. initMessageSource

 protected void initMessageSource() {
     //获取beanFactory
     ConfigurableListableBeanFactory beanFactory = this.getBeanFactory();
     //是否包含‘messageSource’的bean
     if (beanFactory.containsLocalBean("messageSource")) {
         //获取这个bean并进行赋值
         this.messageSource = (MessageSource)beanFactory.getBean("messageSource", MessageSource.class);
         if (this.parent != null && this.messageSource instanceof HierarchicalMessageSource) {
             HierarchicalMessageSource hms = (HierarchicalMessageSource)this.messageSource;
             if (hms.getParentMessageSource() == null) {
                 hms.setParentMessageSource(this.getInternalParentMessageSource());
             }
         }
 
         if (this.logger.isTraceEnabled()) {
             this.logger.trace("Using MessageSource [" + this.messageSource + "]");
         }
     } else {
         //没有就创建一个
         DelegatingMessageSource dms = new DelegatingMessageSource();
         // 注册到容器中(以后获取国际化配置文件的相关信息,可以通过@Autowired在Spring
         dms.setParentMessageSource(this.getInternalParentMessageSource());
         this.messageSource = dms;
         beanFactory.registerSingleton("messageSource", this.messageSource);
         if (this.logger.isTraceEnabled()) {
             this.logger.trace("No 'messageSource' bean, using [" + this.messageSource + "]");
         }
     }
 
 }
  • 这一步是为 ApplicationContext 添加 messageSource 成员,实现国际化功能

  • 去 beanFactory 内找名为 messageSource 的 bean,如果没有,则提供空的 MessageSource 实现

8. initApplicationContextEventMulticaster

 protected void initApplicationEventMulticaster() {
     //获取beanFactory
     ConfigurableListableBeanFactory beanFactory = this.getBeanFactory();
     if (beanFactory.containsLocalBean("applicationEventMulticaster")) {
         this.applicationEventMulticaster = (ApplicationEventMulticaster)beanFactory.getBean("applicationEventMulticaster", ApplicationEventMulticaster.class);
         if (this.logger.isTraceEnabled()) {
             this.logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
         }
     } else {
         //没有就创建一个
         this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
         //注册到bean容器中
         beanFactory.registerSingleton("applicationEventMulticaster", this.applicationEventMulticaster);
         if (this.logger.isTraceEnabled()) {
             this.logger.trace("No 'applicationEventMulticaster' bean, using [" + this.applicationEventMulticaster.getClass().getSimpleName() + "]");
         }
     }
 }
  • 这一步为 ApplicationContext 添加事件广播器成员,即 applicationContextEventMulticaster

  • 它的作用是发布事件给监听器

  • 去 beanFactory 找名为 applicationEventMulticaster 的 bean 作为事件广播器,若没有,会创建默认的事件广播器

  • 之后就可以调用 ApplicationContext.publishEvent(事件对象) 来发布事件

9. onRefresh

 protected void onRefresh() throws BeansException {
 }

这一步是空实现,留给子类扩展

  • SpringBoot 中的子类在这里准备了 WebServer,即内嵌 web 容器

  • 体现的是模板方法设计模式

10. registerListeners

 protected void registerListeners() {
     //获取容器中的监听器
     Iterator var1 = this.getApplicationListeners().iterator();
 
     while(var1.hasNext()) {
         ApplicationListener<?> listener = (ApplicationListener)var1.next();
         //添加至事件applicationEventMulticaster
         this.getApplicationEventMulticaster().addApplicationListener(listener);
     }
     //获取没有创建的监听器
     String[] listenerBeanNames = this.getBeanNamesForType(ApplicationListener.class, true, false);
     String[] var7 = listenerBeanNames;
     int var3 = listenerBeanNames.length;
      //添加至事件applicationEventMulticaster
     for(int var4 = 0; var4 < var3; ++var4) {
         String listenerBeanName = var7[var4];
         this.getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
     }
     //获取早期设置的事件(派发之前的事件)
     Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
     this.earlyApplicationEvents = null;
     if (!CollectionUtils.isEmpty(earlyEventsToProcess)) {
         Iterator var9 = earlyEventsToProcess.iterator();
 
         while(var9.hasNext()) {
             ApplicationEvent earlyEvent = (ApplicationEvent)var9.next();
              //将早期的事件派发出去
             this.getApplicationEventMulticaster().multicastEvent(earlyEvent);
         }
     }
 
 }
  • 这一步会从多种途径找到事件监听器,并添加至 applicationEventMulticaster

  • 事件监听器顾名思义,用来接收事件广播器发布的事件,有如下来源

    • 事先编程添加的

    • 来自容器中的 bean

    • 来自于 @EventListener 的解析

  • 要实现事件监听器,只需要实现 ApplicationListener 接口,重写其中 onApplicationEvent(E e) 方法即可

11. finishBeanFactoryInitialization

 protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
     //如果beanFactory包含“conversionService”
     if (beanFactory.containsBean("conversionService") && beanFactory.isTypeMatch("conversionService", ConversionService.class)) {
         beanFactory.setConversionService((ConversionService)beanFactory.getBean("conversionService", ConversionService.class));
     }
     //如果beanFactory之前没有注册嵌入值解析器,则注册默认的嵌入值解析器:主要用于注解属性值的解析
     if (!beanFactory.hasEmbeddedValueResolver()) {
         beanFactory.addEmbeddedValueResolver((strVal) -> {
             return this.getEnvironment().resolvePlaceholders(strVal);
         });
     }
     //初始化LoadTimeWeaverAware Bean实例对象
     String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
     String[] var3 = weaverAwareNames;
     int var4 = weaverAwareNames.length;
 
     for(int var5 = 0; var5 < var4; ++var5) {
         String weaverAwareName = var3[var5];
         this.getBean(weaverAwareName);
     }
 
     beanFactory.setTempClassLoader((ClassLoader)null);
     //冻结所有bean定义,注册的bean定义不会被修改或进一步后处理,因为马上要创建 Bean 实例对象了
     beanFactory.freezeConfiguration();
     //实例化所有剩余(非懒加载)单例对象
     beanFactory.preInstantiateSingletons();
 }
  • 这一步会将 beanFactory 的成员补充完毕,并初始化所有非延迟单例 bean

  • conversionService 也是一套转换机制,作为对 PropertyEditor 的补充

  • embeddedValueResolvers 即内嵌值解析器,用来解析 @Value 中的 ${ },借用的是 Environment 的功能

  • singletonObjects 即单例池,缓存所有单例对象

    • 对象的创建都分三个阶段,每一阶段都有不同的 bean 后处理器参与进来,扩展功能

12. finishRefresh

 protected void finishRefresh() {
     //清除资源缓存
     this.clearResourceCaches();
     //初始化跟生命周期有关的后置处理器,在容器中获取LifecycleProcessor
     this.initLifecycleProcessor();
     //获取到生命周期后,调用onRefresh容器刷新完成方法
     this.getLifecycleProcessor().onRefresh();
     //刷新事件
     this.publishEvent((ApplicationEvent)(new ContextRefreshedEvent(this)));
     if (!NativeDetector.inNativeImage()) {
         LiveBeansView.registerApplicationContext(this);
     }
 }
  • 这一步会为 ApplicationContext 添加 lifecycleProcessor 成员,用来控制容器内需要生命周期管理的 bean

  • 如果容器中有名称为 lifecycleProcessor 的 bean 就用它,否则创建默认的生命周期管理器

  • 准备好生命周期管理器,就可以实现

    • 调用 context 的 start,即可触发所有实现 LifeCycle 接口 bean 的 start

    • 调用 context 的 stop,即可触发所有实现 LifeCycle 接口 bean 的 stop

  • 发布 ContextRefreshed 事件,整个 refresh 执行完成

问题回答

  1. 你知道 @Value("${key}") 注入的值是从哪儿来的吗,谁去解析 ${ } ?

  2. 是 ApplicationContext 完成了 bean 的创建和依赖组装吗?

  3. ApplicationContext 与 BeanFactory 之间的关系是什么?

  4. 国际化属于谁的功能

  5. SpEL 谁来解析

  6. 类型谁来转换

  7. 为什么实现了 XxxAware 接口,就能自动装配 Xxx 类型

  8. @Bean 和 是等价的吗?

  9. @Autowired,@Resource 它们由谁来解析,原始的 BeanFactory 提供了这些解析功能吗

  10. Spring 中的事件驱动开发是怎么回事,谁来发事件,谁来收事件

  11. LifeCycle 生命周期和 Spring 的生命周期是一回事吗?

好啦,这次的学习到这里就结束,上面的问题作为回顾,拜拜!

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

面试官:Spring refresh过程是怎样的? 的相关文章

  • 如何循环遍历所有组合,例如48 选择 5 [重复]

    这个问题在这里已经有答案了 可能的重复 如何在java中从大小为n的集合中迭代生成k个元素子集 https stackoverflow com questions 4504974 how to iteratively generate k
  • 为 java 游戏创建交互式 GUI

    大家好 我正在创建一个类似于 java 中的 farmville 的游戏 我只是想知道如何实现用户通常单击以与游戏客户端交互的交互式对象 按钮 我不想使用 swing 库 通用 Windows 看起来像对象 我想为我的按钮导入自定义图像 并
  • Hibernate 挂起或引发延迟初始化,没有会话或会话已关闭

    我正在增强旧的 Spring Hibernate 应用程序 但我陷入困境 我有一种方法可以读取 3000 多行长的文件 每行都有一条记录 必须与数据库中的某些内容进行比较 然后必须将寄存器添加到数据库 多对多表 表和关系是 Branch h
  • 动态选择端口号?

    在 Java 中 我需要获取端口号以在同一程序的多个实例之间进行通信 现在 我可以简单地选择一些固定的数字并使用它 但我想知道是否有一种方法可以动态选择端口号 这样我就不必打扰我的用户设置端口号 这是我的一个想法 其工作原理如下 有一个固定
  • 如何获取之前的URL?

    我需要调用我的网络应用程序的 URL 例如 如果有一个从 stackoverflow com 到我的网站 foo com 的链接 我需要 Web 应用程序 托管 bean 中的 stackoverflow 链接 感谢所有帮助 谢谢 并不总是
  • jQuery AJAX 调用 Java 方法

    使用 jQuery AJAX 我们可以调用特定的 JAVA 方法 例如从 Action 类 该 Java 方法返回的数据将用于填充一些 HTML 代码 请告诉我是否可以使用 jQuery 轻松完成此操作 就像在 DWR 中一样 此外 对于
  • 来自 dll 的 Java 调用函数

    我有这个 python 脚本导入zkemkeeperdll 并连接到考勤设备 ZKTeco 这是我正在使用的脚本 from win32com client import Dispatch zk Dispatch zkemkeeper ZKE
  • java.lang.IllegalStateException:应用程序 PagerAdapter 更改了适配器的内容,而没有调用 PagerAdapter#notifyDataSetChanged android

    我正在尝试使用静态类将值传递给视图 而不是使用意图 因为我必须传递大量数据 有时我会收到此错误 但无法找出主要原因是什么 Error java lang IllegalStateException The application s Pag
  • 没有 Spring 的自定义 Prometheus 指标

    我需要为 Web 应用程序提供自定义指标 问题是我不能使用 Spring 但我必须使用 jax rs 端点 要求非常简单 想象一下 您有一个包含键值对的映射 其中键是指标名称 值是一个简单的整数 它是一个计数器 代码会是这样的 public
  • 检测并缩短字符串中的所有网址

    假设我有一条字符串消息 您应该将 file zip 上传到http google com extremelylonglink zip http google com extremelylonglink zip not https stack
  • 在 junit 测试中获取 javax.lang.model.element.Element 类

    我想测试我的实用程序类 ElementUtils 但我不知道如何将类作为元素获取 在 AnnotationProcessors 中 我使用以下代码获取元素 Set
  • Java ResultSet 如何检查是否有结果

    结果集 http java sun com j2se 1 4 2 docs api java sql ResultSet html没有 hasNext 方法 我想检查 resultSet 是否有任何值 这是正确的方法吗 if resultS
  • tomcat 中受密码保护的应用程序

    我正在使用 JSP Servlet 开发一个Web应用程序 并且我使用了Tomcat 7 0 33 as a web container 所以我的要求是tomcat中的每个应用程序都会password像受保护的manager applica
  • 如何对不同的参数类型使用相同的java方法?

    我的问题 我有 2 个已定义的记录 创建对象请求 更新对象请求 必须通过实用方法进行验证 由于这两个对象具有相同的字段 因此可以对这两种类型应用相同的验证方法 现在我只是使用两种方法进行重载 但它很冗长 public record Crea
  • 尝试将 Web 服务部署到 TomEE 时出现“找不到...的 appInfo”

    我有一个非常简单的项目 用于培训目的 它是一个 RESTful Web 服务 我使用 js css 和 html 创建了一个客户端 我正在尝试将该服务部署到 TomEE 这是我尝试部署时遇到的错误 我在这里做错了什么 刚刚遇到这个问题 我曾
  • 为什么 Java 8 不允许非公共默认方法?

    让我们举个例子 public interface Testerface default public String example return Hello public class Tester implements Testerface
  • Cucumber 0.4.3 (cuke4duke) 与 java + maven gem 问题

    我最近开始为 Cucumber 安装一个示例项目 并尝试使用 maven java 运行它 我遵循了这个指南 http www goodercode com wp using cucumber tests with maven and ja
  • 我如何在java中读取二进制数据文件

    因此 我正在为学校做一个项目 我需要读取二进制数据文件并使用它来生成角色的统计数据 例如力量和智慧 它的设置是让前 8 位组成一个统计数据 我想知道执行此操作的实际语法是什么 是不是就像读文本文件一样 这样 File file new Fi
  • 如何使用mockito模拟构建器

    我有一个建造者 class Builder private String name private String address public Builder setName String name this name name retur
  • Java中super关键字的范围和使用

    为什么无法使用 super 关键字访问父类变量 使用以下代码 输出为 feline cougar c c class Feline public String type f public Feline System out print fe

随机推荐

  • 栈抽象数据类型及Python实现

    目录 栈的实现 栈的应用 十进制转化为二进制 中缀转后缀 后缀表达式求值 栈的实现 栈Stack 一种有次序的数据项集合 在栈中 数据项的加入和移除都仅发生在同一端 一端叫栈 顶top 另一端叫栈 底base 栈的特性 反转次序 在栈中数据
  • 安卓页面布局中android:gravity与android:layout_gravity的区别

    android gravity 指的是在控件内的元素要排布的方向 android layout gravity 指的是该控件相对于父控件的显示位置 当这俩个属性取多个值时可以使用 来分隔 且在LinearLayout布局中 使用androi
  • 手把手教你用matlab做深度学习(二)- --CNN

    在上一篇博客中 讲解了怎么用matlab搭建CNN网络模型 并给出了训练过程与结果 但是结果不是很满意 大概训练精度在80 左右 现在给出改进方案 1 首先 我们可以把CNN滤波输出数改大点 从原来的32改为numFilters 128 完
  • 在线图片尺寸修改 生成图标

    https www sojson com image change html https www idc yun com index php icon make 工具机 https www idc yun com index php uti
  • python输出希腊字母

    24个希腊字母 一 希腊字母及读音 二 Python输出 三 发现问题 一 希腊字母及读音 大写 小写 英文读音 中文读音 Alpha 阿尔法 Beta 贝塔 Gamma 伽马 Delta 德尔塔 Epsilon 艾普西隆 Zeta 泽塔
  • R数据分析:方法与案例详解--自学笔记

    TOC 目录 第二章 数据结构与基本运算 2 1 数据类型 数值型 numeric 整数 小数 科学数 字符型 character 夹杂单引号或者双引号之间 MR 逻辑型 只能读取T TRUE 或 F FALSE 值 复数型 a bi 原始
  • Java框架简介

    一 框架介绍 1 SpringBoot SpringBoot是Spring家族中一个全新框架 用来简化Spring应用程序的创建和开发过程 特性 1 一个快速开发框架 能够快速创建基于Spring的应用程序 2 能够直接使用java mai
  • Jenkins管理Docker容器

    一 Docker镜像容器手动更新流程 1 Docker安装 curl o etc yum repos d epel repo http mirrors aliyun com repo epel 7 repo curl o etc yum r
  • ajax的添加,在ajax中添加更多参数

    我正在使用AJAX功能 我使用AJAX将3个变量传递到下一页 当我添加第4个变量时 函数不会被调用 Code Browser Support Code function ajaxFunction var ajaxRequest The va
  • 超大规模数据库集群保稳系列之一:高可用系统

    基于过去多年在大规模数据集群保稳方面的实践经验 我们希望能够跟业界进行一些技术交流 美团技术团队举办了第75期技术沙龙 我们邀请到了美团研究员赵应钢担任出品人 同时请邀请到张洪 王占全 蔺瑞超 沈裕锋等4位数据库方向的4位技术专家 围绕进攻
  • C++虚拟机制的压制

    C 中 如果一个类有虚拟函数的时候 当使用该类的指针调用其虚函数的时候 代码会被编译器转换为使用虚函数表中保存的函数地址找到函数后二次调用 即 class A public virtual void Out this gt Inner vi
  • ue4绘制线的三种方式

    第一种方式 是用样条线 简明扼要 但是打包后就消失了 AActor actor world gt SpawnActor lt AActor gt ActorClass actor gt AttachToActor this FAttachm
  • 步进及伺服调试中常见问题

    步进及伺服调试中常见问题 步进 伺服 步进 1 步进电机驱动器可以接收两种脉冲信号 一种单脉冲方式 一种是双脉冲方式 可通过驱动器拨码开关设置进行选择 试分别画出两种方式的信号图 单脉冲方式脉冲信号从脉冲端 PUL 输入 通过方向端 DIR
  • java实现域名解析

    java实现域名解析 域名解析过程 浏览器检查是否有该域名缓存 检查本机host文件之内是否有该域名对应ip 检查本机DNS缓存 递归或迭代向DNS根域名服务器获取该域名ip地址 1 windows控制台 win r 输入cmd进入控制台
  • C语言常见校验(加密)操作——异或

    在通讯传输数据过程中 往往要加校验码 今天写了个简单的异或以及解异或的操作代码 include
  • arcsde安装步骤_ArcGIS 9.3 安装之 SDE的安装及使用

    由于ArcSDE9 3只支持Oracle 11gR1 32位版本 所以要在安装ArcSDE的电脑上安装一个32位版本的Oracle 11gR1客户端 1 安装SDE程序 并进行注册 1 选择注册机KeyGen exe 点击server标签
  • Vue3中父子组件实现数据双向绑定效果

    父组件
  • MarkDown/README.md文件添加图片

    README md文件添加图片 用MarkDown格式的文档编辑时 需要上传图片 比如往gitHub上的README md中添加一张展示效果图 alt text path to img jpg Title 其中 path to img jp
  • 树莓派设置静态IP记录(整理)

    另外 树莓派直连电脑 设置静态ip 可参考 http blog csdn net liang890319 article details 8639128 树莓派默认使用的是dhcp自动分配ip 而且默认打开SSH服务 当没有显示器的时候 我
  • 面试官:Spring refresh过程是怎样的?

    小熊学Java网站 https javaxiaobear gitee io 每周持续更新干货 建议收藏 1 Spring refresh 流程 refresh 是 AbstractApplicationContext 中的核心方法 负责初始