nfvo通过调用哪个接口实现对vnf生命周期的管理_Spring-Bean生命周期
只有四个!只有四个!只有四个!
是的,Spring Bean的生命周期只有这四个阶段。
要彻底搞清楚Spring的生命周期,首先要把这四个阶段牢牢记住。实例化和属性赋值对应构造方法和setter方法的注入,初始化和销毁是用户能自定义扩展的两个阶段。
- 实例化->Instantiation
- 属性赋值->Populate
- 初始化->Initialization
- 销毁->Destruction
实例化 -> 属性赋值 -> 初始化 -> 销毁
第一大类:影响多个Bean的接口
实现了这些接口的Bean会切入到多个Bean的生命周期中。正因为如此,这些接口的功能非常强大,Spring内部扩展也经常使用这些接口,例如自动注入以及AOP的实现都和他们有关。
- BeanPostProcessor
- InstantiationAwareBeanPostProcessor
这两兄弟可能是Spring扩展中最重要的两个接口!InstantiationAwareBeanPostProcessor作用于实例化阶段的前后,BeanPostProcessor作用于初始化阶段的前后。如图:
其中 InstantiationAwareBeanPostProcessor继承自BeanPostProcessor 是spring非常重要的拓展接口
1、postProcessBeforeInstantiation调用时机为bean实例化(Instantiation)之前 如果返回了bean实例, 则会替代原来正常通过target bean生成的bean的流程. 典型的例如aop返回proxy对象. 此时bean的执行流程将会缩短, 只会执行
BeanPostProcessor#postProcessAfterInitialization接口完成初始化。
2、postProcessAfterInstantiation调用时机为bean实例化(Instantiation)之后和任何初始化(Initialization)之前。
3、postProcessProperties调用时机为postProcessAfterInstantiation执行之后并返回true, 返回的PropertyValues将作用于给定bean属性赋值. spring 5.1之后出现以替换@Deprecated标注的postProcessPropertyValues
4、postProcessPropertyValues已经被标注@Deprecated,后续将会被postProcessProperties取代。
进入执行流程
步骤1 :InstantiationAwareBeanPostProcessor的触发入口从AbstractAutowireCapableBeanFactory#createBean开始。
/*** Central method of this class: creates a bean instance,* populates the bean instance, applies post-processors, etc.** @see #doCreateBean*/
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)throws BeanCreationException {// 省略......try {/*** 注释1. InstantiationAwareBeanPostProcessor#postProcessorsBeforeInstantiation触发入口*/Object bean = resolveBeforeInstantiation(beanName, mbdToUse);if (bean != null) {return bean;}} catch (Throwable ex) {throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,"BeanPostProcessor before instantiation of bean failed", ex);}// 省略......try {/*** 注释2. postProcessAfterInstantiation、postProcessProperties 触发入口* 主要逻辑都在doCreateBean()方法中,* 方法中包含了实例化、属性赋值、初始化过程。逻辑很清晰* 这三个方法与三个生命周期阶段一一对应,非常重要*/Object beanInstance = doCreateBean(beanName, mbdToUse, args);if (logger.isTraceEnabled()) {logger.trace("Finished creating instance of bean '" + beanName + "'");}return beanInstance;} catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {// A previously detected exception with proper bean creation context already,// or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry.throw ex;} catch (Throwable ex) {throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);}
}
步骤2:注释1中,跟进AbstractAutowireCapableBeanFactory#resolveBeforeInstantiation, 分析postProcessorsBeforeInstantiation执行时机 :
/** 注释1 代码进入后执行InstantiationAwareBeanPostProcessor#ostProcessBeforeInstantiation方法*/
@Nullable
protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {Object bean = null;if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {// Make sure bean class is actually resolved at this point.if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {Class<?> targetType = determineTargetType(beanName, mbd);if (targetType != null) {/*** 注释3:回调beanPostProcessorsBeforeInstantiation实例化,如果返回bean非null则直接执行* 不为空null就直接返回了而不执行doCreateBean()方法了,而该方法是创建Bean对象的方法* beanPostProcessorsAfterInitialization进行实例初始化*/bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);if (bean != null) {/** 注释4 */bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);}}}mbd.beforeInstantiationResolved = (bean != null);}return bean;
}/**注释3 代码跟进*/
@Nullable
protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {for (BeanPostProcessor bp : getBeanPostProcessors()) {if (bp instanceof InstantiationAwareBeanPostProcessor) {/*** 注释5:只要其中一个postProcessBeforeInstantiation返回实例bean即结束回调,* 这个bean将会直接返回给bean容器管理*/InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);if (result != null) {return result;}}}return null;
}/** 注释4 代码跟进*/
@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)throws BeansException {Object result = existingBean;for (BeanPostProcessor processor : getBeanPostProcessors()) {/**注释6 */Object current = processor.postProcessAfterInitialization(result, beanName);if (current == null) {return result;}result = current;}return result;
}
可以看到,postProcessBeforeInstantiation在doCreateBean之前调用,也就是在bean实例化之前调用的,英文源码注释解释道该方法的返回值会替换原本的Bean作为代理,这也是Aop等功能实现的关键点。
代码说明:
1. 注释5中,如果postProcessBeforeInstantiation方法返回了Object是null;那么就直接返回,调用doCreateBean方法();
2. 注释5中,如果postProcessBeforeInstantiation返回不为null;说明修改了bean对象;然后这个时候就立马执行postProcessAfterInitialization方法(注意这个是初始化之后的方法,也就是通过这个方法实例化了之后,直接执行初始化之后的方法;中间的实例化之后 和 初始化之前都不执行);
3. 注释6中,在调用postProcessAfterInitialization方法时候如果返回null;那么就直接返回,调用doCreateBean方法();(初始化之后的方法返回了null,那就需要调用doCreateBean生成对象了)
4. 在调用postProcessAfterInitialization时返回不为null;那这个bean就直接返回给ioc容器了初始化之后的操作是这里面最后一个方法了;
步骤2:跟进AbstractAutowireCapableBeanFactory#doCreateBean, 分析postProcessAfterInstantiation、postProcessProperties执行时机 :
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)throws BeanCreationException {BeanWrapper instanceWrapper = null;if (mbd.isSingleton()) {instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);}if (instanceWrapper == null) {/** 注释7 实例化阶段! */instanceWrapper = createBeanInstance(beanName, mbd, args);}// 省略......// Initialize the bean instance.Object exposedObject = bean;try {/** 注释8 依据bean definition 完成bean属性赋值 */populateBean(beanName, mbd, instanceWrapper);/** 注释9 执行bean初始化 */exposedObject = initializeBean(beanName, exposedObject, mbd);} catch (Throwable ex) {if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {throw (BeanCreationException) ex;} else {throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);}}// 省略......return exposedObject;
}
这三个方法与三个生命周期阶段一一对应,非常重要
- createBeanInstance() -> 实例化(注释7)
- populateBean() -> 属性赋值(注释8)
- initializeBean() -> 初始化(注释9)
注释8中,继续跟进AbstractAutowireCapableBeanFactory#populateBean
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {// Give any InstantiationAwareBeanPostProcessors the opportunity to modify the// state of the bean before properties are set. This can be used, for example,// to support styles of field injection.boolean continueWithPropertyPopulation = true;// InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation()/*** 注释10:满足两个要求:* 1、BeanDefinition为应用程序bean,而非基础框架bean信息。* 2、注册过InstantiationAwareBeanPostProcessor类型接口,上文有提到这个标志位。* 3、注册了多个接口时,只要其中一个postProcessAfterInstantiation返回false,即停止后续执行。*/ if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {for (BeanPostProcessor bp : getBeanPostProcessors()) {if (bp instanceof InstantiationAwareBeanPostProcessor) {InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {continueWithPropertyPopulation = false;break;}}}}// 忽略后续的属性赋值操作代码
}
可以看到该方法在属性赋值方法内,但是在真正执行赋值操作之前。其返回值为boolean,返回false时可以阻断属性赋值阶段(continueWithPropertyPopulation = false;
)
关于BeanPostProcessor执行阶段的源码穿插在下文Aware接口的调用时机分析中,因为部分Aware功能的就是通过他实现的!只需要先记住BeanPostProcessor在初始化前后调用就可以了。
第二大类:只调用一次的接口
这一大类接口的特点是功能丰富,常用于用户自定义扩展。
第二大类中又可以分为两类:
- Aware类型的接口
- 生命周期接口
Aware类型的接口的作用就是让我们能够拿到Spring容器中的一些资源。基本都能够见名知意,Aware之前的名字就是可以拿到什么资源,例如BeanNameAware
可以拿到BeanName,以此类推。调用时机需要注意:所有的Aware方法都是在初始化阶段之前调用的!
Aware接口众多,这里同样通过分类的方式帮助大家记忆。
Aware接口具体可以分为两组,至于为什么这么分,详见下面的源码分析。如下排列顺序同样也是Aware接口的执行顺序,能够见名知意的接口不再解释。
Aware Group1
- BeanNameAware
- BeanClassLoaderAware
- BeanFactoryAware
Aware Group2
- EnvironmentAware
- EmbeddedValueResolverAware (这个知道的人可能不多,实现该接口能够获取Spring EL解析器,用户的自定义注解需要支持spel表达式的时候可以使用,非常方便。)
- ApplicationContextAware(ResourceLoaderAwareApplicationEventPublisherAwareMessageSourceAware) 这几个接口可能让人有点懵,实际上这几个接口可以一起记,其返回值实质上都是当前的ApplicationContext对象,因为ApplicationContext是一个复合接口,如下:
public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,MessageSource, ApplicationEventPublisher, ResourcePatternResolver {}
这里涉及到另一道面试题,ApplicationContext和BeanFactory的区别,可以从ApplicationContext继承的这几个接口入手,除去BeanFactory相关的两个接口就是ApplicationContext独有的功能,这里不详细说明。
Aware调用时机源码分析
详情如下,忽略了部分无关代码。代码位置就是我们上文提到的initializeBean方法详情,这也说明了Aware都是在初始化阶段之前调用的!
// 注释9 代码进入 调用初始化阶段
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {// 注释11 这里调用的是Group1中的三个Bean开头的AwareinvokeAwareMethods(beanName, bean);Object wrappedBean = bean;/** * 这里调用的是Group2中的几个Aware,* 而实质上这里就是前面所说的BeanPostProcessor的调用点!* 也就是说与Group1中的Aware不同,这里是通过BeanPostProcessor(ApplicationContextAwareProcessor)实现的。*//** 注释12 */wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);/** 注释13 下文即将介绍的InitializingBean调用点 */invokeInitMethods(beanName, wrappedBean, mbd);/** 注释14 BeanPostProcessor的另一个调用点*/wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);return wrappedBean;
}/**注释11 代码进入 */
private void invokeAwareMethods(final String beanName, final Object bean) {if (bean instanceof Aware) {if (bean instanceof BeanNameAware) {((BeanNameAware) bean).setBeanName(beanName);}if (bean instanceof BeanClassLoaderAware) {((BeanClassLoaderAware) bean).setBeanClassLoader(getBeanClassLoader());}if (bean instanceof BeanFactoryAware) {((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);}}
}
注释11 代码进入后,可以看到并不是所有的Aware接口都使用同样的方式调用。Bean××Aware都是在代码中直接调用的。
而ApplicationContext相关的Aware都是通过applyBeanPostProcessorsBeforeInitialization来调用BeanPostProcessor#postProcessBeforeInitialization()实现的。感兴趣的可以自己看一下ApplicationContextAwareProcessor这个类的源码,就是判断当前创建的Bean是否实现了相关的Aware方法,如果实现了会调用回调方法将资源传递给Bean。
至于Spring为什么这么实现,应该没什么特殊的考量。也许和Spring的版本升级有关。基于对修改关闭,对扩展开放的原则,Spring对一些新的Aware采用了扩展的方式添加。
BeanPostProcessor的调用时机也能在这里体现,包围住invokeInitMethods方法,也就说明了在初始化阶段的前后执行。
关于Aware接口的执行顺序,其实只需要记住第一组在第二组执行之前就行了。每组中各个Aware方法的调用顺序其实没有必要记,有需要的时候点进源码一看便知。简单的两个生命周期接口
至于剩下的两个生命周期接口就很简单了,实例化和属性赋值都是Spring帮助我们做的,能够自己实现的有初始化和销毁两个生命周期阶段。
- InitializingBean 对应生命周期的初始化阶段,在上面源码的
invokeInitMethods(beanName, wrappedBean, mbd);
方法中调用。
有一点需要注意,因为Aware方法都是执行在初始化方法之前,所以可以在初始化方法中放心大胆的使用Aware接口获取的资源,这也是我们自定义扩展Spring的常用方式。
除了实现InitializingBean接口之外还能通过注解或者xml配置的方式指定初始化方法,至于这几种定义方式的调用顺序其实没有必要记。因为这几个方法对应的都是同一个生命周期,只是实现方式不同,我们一般只采用其中一种方式。 - DisposableBean 类似于InitializingBean,对应生命周期的销毁阶段,以ConfigurableApplicationContext#close()方法作为入口,实现是通过循环取所有实现了DisposableBean接口的Bean然后调用其destroy()方法 。感兴趣的可以自行跟一下源码。
扩展阅读: BeanPostProcessor 注册时机与执行顺序
注册时机
我们知道BeanPostProcessor也会注册为Bean,那么Spring是如何保证BeanPostProcessor在我们的业务Bean之前初始化完成呢?
请看我们熟悉的refresh()方法的源码,省略部分无关代码:
@Overridepublic void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {try {// Allows post-processing of the bean factory in context subclasses.postProcessBeanFactory(beanFactory);// Invoke factory processors registered as beans in the context.invokeBeanFactoryPostProcessors(beanFactory);// Register bean processors that intercept bean creation.// 所有BeanPostProcesser初始化的调用点registerBeanPostProcessors(beanFactory);// Initialize message source for this context.initMessageSource();// Initialize event multicaster for this context.initApplicationEventMulticaster();// Initialize other special beans in specific context subclasses.onRefresh();// Check for listener beans and register them.registerListeners();// Instantiate all remaining (non-lazy-init) singletons.// 所有单例非懒加载Bean的调用点finishBeanFactoryInitialization(beanFactory);// Last step: publish corresponding event.finishRefresh();}}
可以看出,Spring是先执行registerBeanPostProcessors()进行BeanPostProcessors的注册,然后再执行finishBeanFactoryInitialization初始化我们的单例非懒加载的Bean。
执行顺序
BeanPostProcessor有很多个,而且每个BeanPostProcessor都影响多个Bean,其执行顺序至关重要,必须能够控制其执行顺序才行。关于执行顺序这里需要引入两个排序相关的接口:PriorityOrdered、Ordered
- PriorityOrdered是一等公民,首先被执行,PriorityOrdered公民之间通过接口返回值排序
- Ordered是二等公民,然后执行,Ordered公民之间通过接口返回值排序
- 都没有实现是三等公民,最后执行
在以下源码中,可以很清晰的看到Spring注册各种类型BeanPostProcessor的逻辑,根据实现不同排序接口进行分组。优先级高的先加入,优先级低的后加入。
// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
// 首先,加入实现了PriorityOrdered接口的BeanPostProcessors,顺便根据PriorityOrdered排了序String[] postProcessorNames =beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);for (String ppName : postProcessorNames) {if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));processedBeans.add(ppName);}}sortPostProcessors(currentRegistryProcessors, beanFactory);registryProcessors.addAll(currentRegistryProcessors);invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);currentRegistryProcessors.clear();// Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.
// 然后,加入实现了Ordered接口的BeanPostProcessors,顺便根据Ordered排了序postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);for (String ppName : postProcessorNames) {if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));processedBeans.add(ppName);}}sortPostProcessors(currentRegistryProcessors, beanFactory);registryProcessors.addAll(currentRegistryProcessors);invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);currentRegistryProcessors.clear();// Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.
// 最后加入其他常规的BeanPostProcessorsboolean reiterate = true;while (reiterate) {reiterate = false;postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);for (String ppName : postProcessorNames) {if (!processedBeans.contains(ppName)) {currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));processedBeans.add(ppName);reiterate = true;}}sortPostProcessors(currentRegistryProcessors, beanFactory);registryProcessors.addAll(currentRegistryProcessors);invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);currentRegistryProcessors.clear();}// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
// 首先,加入实现了PriorityOrdered接口的BeanPostProcessors,顺便根据PriorityOrdered排了序String[] postProcessorNames =beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);for (String ppName : postProcessorNames) {if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));processedBeans.add(ppName);}}sortPostProcessors(currentRegistryProcessors, beanFactory);registryProcessors.addAll(currentRegistryProcessors);invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);currentRegistryProcessors.clear();// Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.
// 然后,加入实现了Ordered接口的BeanPostProcessors,顺便根据Ordered排了序postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);for (String ppName : postProcessorNames) {if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));processedBeans.add(ppName);}}sortPostProcessors(currentRegistryProcessors, beanFactory);registryProcessors.addAll(currentRegistryProcessors);invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);currentRegistryProcessors.clear();// Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.
// 最后加入其他常规的BeanPostProcessorsboolean reiterate = true;while (reiterate) {reiterate = false;postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);for (String ppName : postProcessorNames) {if (!processedBeans.contains(ppName)) {currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));processedBeans.add(ppName);reiterate = true;}}sortPostProcessors(currentRegistryProcessors, beanFactory);registryProcessors.addAll(currentRegistryProcessors);invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);currentRegistryProcessors.clear();}
根据排序接口返回值排序,默认升序排序,返回值越低优先级越高。
/*** Useful constant for the highest precedence value.* @see java.lang.Integer#MIN_VALUE*/int HIGHEST_PRECEDENCE = Integer.MIN_VALUE;/*** Useful constant for the lowest precedence value.* @see java.lang.Integer#MAX_VALUE*/int LOWEST_PRECEDENCE = Integer.MAX_VALUE;
PriorityOrdered、Ordered接口作为Spring整个框架通用的排序接口,在Spring中应用广泛,也是非常重要的接口。
总结
Spring Bean的生命周期分为四个阶段
和多个扩展点
。扩展点又可以分为影响多个Bean
和影响单个Bean
。整理如下:
四个阶段
- 实例化 Instantiation
- 属性赋值 Populate
- 初始化 Initialization
- 销毁 Destruction
多个扩展点
- 影响多个Bean
- BeanPostProcessor
- InstantiationAwareBeanPostProcessor
- 影响单个Bean
- Aware
- Aware Group1
- BeanNameAware
- BeanClassLoaderAware
- BeanFactoryAware
- Aware Group2
- EnvironmentAware
- EmbeddedValueResolverAware
- ApplicationContextAware(ResourceLoaderAwareApplicationEventPublisherAwareMessageSourceAware)
- Aware Group1
- 生命周期
- InitializingBean
- DisposableBean
- Aware
至此,Spring Bean的生命周期介绍完毕,由于作者水平有限难免有疏漏,欢迎留言纠错。
nfvo通过调用哪个接口实现对vnf生命周期的管理_Spring-Bean生命周期相关推荐
- 在VS2015中用C++创建DLL并用C#调用且同时实现对DLL的调试
from:http://m.blog.csdn.net/article/details?id=51075023 在VS2015中先创建C#项目,然后再创建要编写的动态库DLL项目,这样做的好处是整个解 ...
- @Autowire注入了bean(A)在当前类,但其他类需要调用这个A,报null异常,使用get获取bean为解决方案
@Autowire注入了bean(A)在当前类,但其他类需要调用这个A,报null异常,使用get获取bean为解决方案 问题背景 解决方案 心得 Lyric: 远远抛开一切 问题背景 在做项目时,我 ...
- QTP提供的编程接口实现对QTP操作
我们可以通过调用 Automation Object Model 里的对象接口 ,来实现对QTP 的操作,如打开 /运行脚本等动作 Automation object model 的对象结构图如下 ( ...
- uni-app调用Native.jsAPI实现对Android原生日历的增删查操作
文章目录 前言 一.引入插件(uni-app插件市场) 二.使用步骤 1.手机系统日历操作需要添加权限才能操作 2.在对应的页面中进行使用 总结 前言 最近的uni-app项目中有一个直播日历的功能, ...
- vue函数如何调用其他函数?_从源码中学Vue(一)生命周期中的钩子函数的那点事儿...
欢迎来到我的<从源码中学Vue>专题系列文章,更多精彩内容持续更新中,欢迎关注 :) Vue作为当下前端最流行的框架之一,在国内占绝对的优势.所以接下来我们一起来学习它吧! 我不会像其它人 ...
- 170630、springboot编程之普通类中调用spring管理的bean对象
我们知道如果我们要在一个类使用spring提供的bean对象,我们需要把这个类注入到spring容器中,交给spring容器进行管理,但是在实际当中,我们往往会碰到在一个普通的Java类中,想直接使用 ...
- SpringBoot 项目中在Controller 直接调用Mapper,提示:Field mapper in ‘*Controller ‘ required a bean of type ‘*Map
今天使用IDEA 搭建SpringBoot 项目,我心血来潮想省略Service 层的编写就直接在Controller 层调用Mapper 层接口,提示如下错误信息: **************** ...
- springCloud Feign调用报错 Parameter 6 of constructor in xxxxxxxx required a bean of type ‘xxxxxx‘ that
Description: Parameter 6 of constructor in xxxxxxx required a bean of type 'xxxxxxx' that could not ...
- 基于python的类的调用(快递查询,天气查询,学员管理,旅游查询,电影查询,景点查询,手机销售系统,内涵段子,手机号id查询))
一.汇总模型 #模块<==>python文件 #引入express中的KD类 from express import KD from weather import WT from stud ...
最新文章
- JAVA C++ 左花括号{该另起一行写还是写在行尾的思考
- Java深入了解String对象
- Spring框架在属性注入时@Autowired和@Resource的区别
- SQLServer获取最后插入生成的ID 不同方法
- 【NLP】Google BERT详解
- 8位16进制频率计设计实验--VHDL
- arm linux 时间获取,菜鸟自学ARM:linux下编程获取系统时间和设置时间
- RAN adjusts schedule for 2nd wave of 5G specifications
- 全球首个零损耗容器等多款新品重磅发布,华为云用全栈创新普惠千行百业
- 2019版PHP自动发卡平台源码
- 华为S5700交换机端口聚合
- 机械电子工程和计算机联系应用,论机械电子技术与计算机的融合发展
- Day6——yaml简介
- (公式)用欧拉公式推导三角函数恒等式
- Windows远程桌面无法最大化问题
- 阿姆斯特朗数python
- 斐波那契的N种实现方式
- VS Code 自定义语法高亮 —— 入门
- sprin boot计算公式
- Android Surface system analyze
热门文章
- Qt元对象QMetaObject的indexOfSlot等函数获取类方法注意问题
- java 优化 寄存器_JVM性能优化系列-(6) 晚期编译优化
- 浅析Hibernate映射(一)——基本映射
- iOS7 企业应用无法安装应用程序 因为证书无效的解决方案
- java 兼容excel_Java解析Excel工具类(兼容xls和xlsx)
- mysql change命令_Mysql 操作基本命令大全
- 计算结构体、数组、指针的sizeof
- redis3.0.7_sds.c_sdsnewlen()
- 傅里叶变换库FFTW的安装配置(VS2010)
- 建立SQL Server警告和给操作员发送email通知