上接Spring事务处理时自我调用的解决方案及一些实现方式的风险继续分析,在分析上篇的问题之前,我们需要了解下BeanPostProcessor概念和Spring容器创建Bean的流程。

一、BeanPostProcessor是什么

接口定义

Java代码  
  1. package org.springframework.beans.factory.config;
  2. public interface BeanPostProcessor {
  3. Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
  4. Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
  5. }

BeanPostProcessor是Spring容器的一个扩展点,可以进行自定义的实例化、初始化、依赖装配、依赖检查等流程,即可以覆盖默认的实例化,也可以增强初始化、依赖注入、依赖检查等流程,其javadoc有如下描述:

e.g. checking for marker interfaces or wrapping them with proxies.

大体意思是可以检查相应的标识接口完成一些自定义功能实现,如包装目标对象到代理对象。

我们可以看到BeanPostProcessor一共有两个回调方法postProcessBeforeInitialization和postProcessAfterInitialization,那这两个方法会在什么Spring执行流程中的哪个步骤执行呢?还有目前Spring提供哪些相应的实现呢?

Spring还提供了BeanPostProcessor一些其他接口实现,来完成除实例化外的其他功能,后续详细介绍。

二、通过源代码看看创建一个Bean实例的具体执行流程:

AbstractApplicationContext内部使用DefaultListableBeanFactory,且DefaultListableBeanFactory继承AbstractAutowireCapableBeanFactory,因此我们此处分析AbstractAutowireCapableBeanFactory即可。

一、AbstractAutowireCapableBeanFactory的createBean方法代码如下:

Java代码  
  1. protected Object createBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) throws BeanCreationException {
  2. resolveBeanClass(mbd, beanName); /1解析Bean的class
  3. mbd.prepareMethodOverrides(); //2 方法注入准备
  4. Object bean = resolveBeforeInstantiation(beanName, mbd); //3 第一个BeanPostProcessor扩展点
  5. if (bean != null) { //4 如果3处的扩展点返回的bean不为空,直接返回该bean,后续流程不需要执行
  6. return bean;
  7. }
  8. Object beanInstance = doCreateBean(beanName, mbd, args); //5 执行spring的创建bean实例的流程啦
  9. return beanInstance;
  10. }

0.3 第一个BeanPostProcessor扩展点(只有InstantiationAwareBeanPostProcessor接口的实现才会被调用)

二、AbstractAutowireCapableBeanFactory的resolveBeforeInstantiation方法代码如下:

Java代码  
  1. protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
  2. Object bean = null;
  3. if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
  4. // Make sure bean class is actually resolved at this point.
  5. if (mbd.hasBeanClass() && !mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
  6. //3.1、执行InstantiationAwareBeanPostProcessor的postProcessBeforeInstantiation回调方法
  7. bean = applyBeanPostProcessorsBeforeInstantiation(mbd.getBeanClass(), beanName);
  8. if (bean != null) {
  9. //3.2、执行InstantiationAwareBeanPostProcessor的postProcessAfterInitialization回调方法
  10. bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
  11. }
  12. }
  13. mbd.beforeInstantiationResolved = (bean != null);
  14. }
  15. return bean;
  16. }

通过如上代码可以进行实例化的预处理(自定义实例化bean,如创建相应的代理对象)和后处理(如进行自定义实例化的bean的依赖装配)。

三、AbstractAutowireCapableBeanFactory的doCreateBean方法代码如下:

Java代码  
  1. // 6、通过BeanWrapper实例化Bean
  2. BeanWrapper instanceWrapper = null;
  3. if (mbd.isSingleton()) {
  4. instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
  5. }
  6. if (instanceWrapper == null) {
  7. instanceWrapper = createBeanInstance(beanName, mbd, args);
  8. }
  9. final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
  10. Class beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);
  11. //7、执行MergedBeanDefinitionPostProcessor的postProcessMergedBeanDefinition流程
  12. synchronized (mbd.postProcessingLock) {
  13. if (!mbd.postProcessed) {
  14. applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
  15. mbd.postProcessed = true;
  16. }
  17. }
  18. // 8、及早暴露单例Bean引用,从而允许setter注入方式的循环引用
  19. boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
  20. isSingletonCurrentlyInCreation(beanName));
  21. if (earlySingletonExposure) {
  22. //省略log
  23. addSingletonFactory(beanName, new ObjectFactory() {
  24. public Object getObject() throws BeansException {
  25. //8.1、调用SmartInstantiationAwareBeanPostProcessor的getEarlyBeanReference返回一个需要暴露的Bean(例如包装目标对象到代理对象)
  26. return getEarlyBeanReference(beanName, mbd, bean);
  27. }
  28. });
  29. }
  30. Object exposedObject = bean;
  31. try {
  32. populateBean(beanName, mbd, instanceWrapper); //9、组装-Bean依赖
  33. if (exposedObject != null) {
  34. exposedObject = initializeBean(beanName, exposedObject, mbd); //10、初始化Bean
  35. }
  36. }
  37. catch (Throwable ex) {
  38. //省略异常
  39. }
  40. //11如果是及早暴露单例bean,通过getSingleton触发3.1处的getEarlyBeanReference调用获取要及早暴露的单例Bean
  41. if (earlySingletonExposure) {
  42. Object earlySingletonReference = getSingleton(beanName, false);
  43. if (earlySingletonReference != null) {
  44. if (exposedObject == bean) {
  45. exposedObject = earlySingletonReference;
  46. }
  47. else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
  48. String[] dependentBeans = getDependentBeans(beanName);
  49. Set<String> actualDependentBeans = new LinkedHashSet<String>(dependentBeans.length);
  50. for (String dependentBean : dependentBeans) {
  51. if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
  52. actualDependentBeans.add(dependentBean);
  53. }
  54. }
  55. if (!actualDependentBeans.isEmpty()) {
  56. throw new BeanCurrentlyInCreationException(beanName,
  57. "Bean with name '" + beanName + "' has been injected into other beans [" +
  58. StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
  59. "] in its raw version as part of a circular reference, but has eventually been " +
  60. "wrapped. This means that said other beans do not use the final version of the " +
  61. "bean. This is often the result of over-eager type matching - consider using " +
  62. "'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
  63. }
  64. }
  65. }
  66. }
  67. //12、注册Bean的销毁回调
  68. try {
  69. registerDisposableBeanIfNecessary(beanName, bean, mbd);
  70. }
  71. catch (BeanDefinitionValidationException ex) {
  72. throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
  73. }

四、AbstractAutowireCapableBeanFactory的populateBean方法代码如下:

Java代码  
  1. //9、组装-Bean
  2. protected void populateBean(String beanName, AbstractBeanDefinition mbd, BeanWrapper bw) {
  3. PropertyValues pvs = mbd.getPropertyValues();
  4. //省略部分代码
  5. //9.1、通过InstantiationAwareBeanPostProcessor扩展点允许自定义装配流程(如@Autowired支持等)
  6. //执行InstantiationAwareBeanPostProcessor的postProcessAfterInstantiation
  7. boolean continueWithPropertyPopulation = true;
  8. if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
  9. for (BeanPostProcessor bp : getBeanPostProcessors()) {
  10. if (bp instanceof InstantiationAwareBeanPostProcessor) {
  11. InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
  12. if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
  13. continueWithPropertyPopulation = false;
  14. break;
  15. }
  16. }
  17. }
  18. }
  19. if (!continueWithPropertyPopulation) {
  20. return;
  21. }
  22. if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||
  23. mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
  24. MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
  25. // 9. 2、自动装配(根据name/type)
  26. if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
  27. autowireByName(beanName, mbd, bw, newPvs);
  28. }
  29. if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
  30. autowireByType(beanName, mbd, bw, newPvs);
  31. }
  32. pvs = newPvs;
  33. }
  34. boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
  35. boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE);
  36. //9. 3、执行InstantiationAwareBeanPostProcessor的postProcessPropertyValues
  37. if (hasInstAwareBpps || needsDepCheck) {
  38. PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw);
  39. if (hasInstAwareBpps) {
  40. for (BeanPostProcessor bp : getBeanPostProcessors()) {
  41. if (bp instanceof InstantiationAwareBeanPostProcessor) {
  42. InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
  43. pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
  44. if (pvs == null) {
  45. return;
  46. }
  47. }
  48. }
  49. }
  50. //9. 4、执行依赖检查
  51. if (needsDepCheck) {
  52. checkDependencies(beanName, mbd, filteredPds, pvs);
  53. }
  54. }
  55. //9. 5、应用依赖注入
  56. applyPropertyValues(beanName, mbd, bw, pvs);
  57. }

五、AbstractAutowireCapableBeanFactory的initializeBean方法代码如下:

Java代码  
  1. //10、实例化Bean
  2. protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
  3. //10.1、调用Aware接口注入(BeanNameAware、BeanClassLoaderAware、BeanFactoryAware)
  4. invokeAwareMethods(beanName, bean);//此处省略部分代码
  5. //10.2、执行BeanPostProcessor扩展点的postProcessBeforeInitialization进行修改实例化Bean
  6. Object wrappedBean = bean;
  7. if (mbd == null || !mbd.isSynthetic()) {
  8. wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
  9. }
  10. //10.3、执行初始化回调(1、调用InitializingBean的afterPropertiesSet  2、调用自定义的init-method)
  11. try {
  12. invokeInitMethods(beanName, wrappedBean, mbd);
  13. }
  14. catch (Throwable ex) {
  15. //异常省略
  16. }
  17. //10.4、执行BeanPostProcessor扩展点的postProcessAfterInitialization进行修改实例化Bean
  18. if (mbd == null || !mbd.isSynthetic()) {
  19. wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
  20. }
  21. return wrappedBean;

三、创建一个Bean实例的执行流程简化:

protected Object createBean(final String beanName, final RootBeanDefinition mbd, final Object[] args); 创建Bean

(1、resolveBeanClass(mbd, beanName); 解析Bean class,若class配置错误将抛出CannotLoadBeanClassException;

(2、mbd.prepareMethodOverrides(); 准备和验证配置的方法注入,若验证失败抛出BeanDefinitionValidationException

有关方法注入知识请参考【第三章】 DI 之 3.3 更多DI的知识 ——跟我学spring3 3.3.5 方法注入;

(3、Object bean = resolveBeforeInstantiation(beanName, mbd); 第一个BeanPostProcessor扩展点,此处只执行InstantiationAwareBeanPostProcessor类型的BeanPostProcessor Bean;

(3.1、bean = applyBeanPostProcessorsBeforeInstantiation(mbd.getBeanClass(), beanName);执行InstantiationAwareBeanPostProcessor的实例化的预处理回调方法postProcessBeforeInstantiation(自定义的实例化,如创建代理);

(3.2、bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);执行InstantiationAwareBeanPostProcessor的实例化的后处理回调方法postProcessAfterInitialization(如依赖注入),如果3.1处返回的Bean不为null才执行;

(4、如果3处的扩展点返回的bean不为空,直接返回该bean,后续流程不需要执行;

(5、Object beanInstance = doCreateBean(beanName, mbd, args); 执行spring的创建bean实例的流程;

(6、createBeanInstance(beanName, mbd, args); 实例化Bean

(6.1、instantiateUsingFactoryMethod 工厂方法实例化;请参考【http://jinnianshilongnian.iteye.com/blog/1413857

(6.2、构造器实例化,请参考【http://jinnianshilongnian.iteye.com/blog/1413857】;

(6.2.1、如果之前已经解析过构造器

(6.2.1.1 autowireConstructor:有参调用autowireConstructor实例化

(6.2.1.2、instantiateBean:无参调用instantiateBean实例化;

(6.2.2、如果之前没有解析过构造器:

(6.2.2.1、通过SmartInstantiationAwareBeanPostProcessor的determineCandidateConstructors回调方法解析构造器,第二个BeanPostProcessor扩展点,返回第一个解析成功(返回值不为null)的构造器组,如AutowiredAnnotationBeanPostProcessor实现将自动扫描通过@Autowired/@Value注解的构造器从而可以完成构造器注入,请参考【第十二章】零配置 之 12.2 注解实现Bean依赖注入 ——跟我学spring3 ;

(6.2.2.2、autowireConstructor:如果(6.2.2.1返回的不为null,且是有参构造器,调用autowireConstructor实例化;

(6.2.2.3、instantiateBean: 否则调用无参构造器实例化;

(7、applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);第三个BeanPostProcessor扩展点,执行Bean定义的合并;

(7.1、执行MergedBeanDefinitionPostProcessor的postProcessMergedBeanDefinition回调方法,进行bean定义的合并;

(8、addSingletonFactory(beanName, new ObjectFactory() {

                            public Object getObject() throws BeansException {

                                   return getEarlyBeanReference(beanName, mbd, bean);

                            }

                     });  及早暴露单例Bean引用,从而允许setter注入方式的循环引用

(8.1、SmartInstantiationAwareBeanPostProcessor的getEarlyBeanReference;第四个BeanPostProcessor扩展点,当存在循环依赖时,通过该回调方法获取及早暴露的Bean实例;

(9、populateBean(beanName, mbd, instanceWrapper);装配Bean依赖

(9.1、InstantiationAwareBeanPostProcessor的postProcessAfterInstantiation;第五个BeanPostProcessor扩展点,在实例化Bean之后,所有其他装配逻辑之前执行,如果false将阻止其他的InstantiationAwareBeanPostProcessor的postProcessAfterInstantiation的执行和从(9.2到(9.5的执行,通常返回true;

(9.2、autowireByName、autowireByType:根据名字和类型进行自动装配,自动装配的知识请参考【第三章】 DI 之 3.3 更多DI的知识 ——跟我学spring3 3.3.3  自动装配;

(9.3、InstantiationAwareBeanPostProcessor的postProcessPropertyValues:第六个BeanPostProcessor扩展点,完成其他定制的一些依赖注入,如AutowiredAnnotationBeanPostProcessor执行@Autowired注解注入,CommonAnnotationBeanPostProcessor执行@Resource等注解的注入,PersistenceAnnotationBeanPostProcessor执行@
PersistenceContext等JPA注解的注入,RequiredAnnotationBeanPostProcessor执行@ Required注解的检查等等,请参考【第十二章】零配置 之 12.2 注解实现Bean依赖注入 ——跟我学spring3

(9.4、checkDependencies:依赖检查,请参考【第三章】 DI 之 3.3 更多DI的知识 ——跟我学spring3 
3.3.4  依赖检查;

(9.5、applyPropertyValues:应用明确的setter属性注入,请参考【第三章】 DI 之 3.1
DI的配置使用 ——跟我学spring3

(10、exposedObject = initializeBean(beanName, exposedObject, mbd); 执行初始化Bean流程;

(10.1、invokeAwareMethods(BeanNameAware、BeanClassLoaderAware、BeanFactoryAware):调用一些Aware标识接口注入如BeanName、BeanFactory;

(10.2、BeanPostProcessor的postProcessBeforeInitialization:第七个扩展点,在调用初始化之前完成一些定制的初始化任务,如BeanValidationPostProcessor完成JSR-303 @Valid注解Bean验证,InitDestroyAnnotationBeanPostProcessor完成@PostConstruct注解的初始化方法调用,ApplicationContextAwareProcessor完成一些Aware接口的注入(如EnvironmentAware、ResourceLoaderAware、ApplicationContextAware),其返回值将替代原始的Bean对象;

(10.3、invokeInitMethods : 调用初始化方法;

(10.3.1、InitializingBean的afterPropertiesSet :调用InitializingBean的afterPropertiesSet回调方法;

(10.3.2、通过xml指定的自定义init-method :调用通过xml配置的自定义init-method

(10.3.3、BeanPostProcessor的postProcessAfterInitialization :第八个扩展点,AspectJAwareAdvisorAutoProxyCreator(完成xml风格的AOP配置(<aop:config>)的目标对象包装到AOP代理对象)、AnnotationAwareAspectJAutoProxyCreator(完成@Aspectj注解风格(<aop:aspectj-autoproxy>
@Aspect)的AOP配置的目标对象包装到AOP代理对象),其返回值将替代原始的Bean对象;

(11、if (earlySingletonExposure) {

Object earlySingletonReference = getSingleton(beanName, false);

……

} :如果是earlySingleExposure,调用getSingle方法获取Bean实例;

earlySingleExposure =(mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName))

只要单例Bean且允许循环引用(默认true)且当前单例Bean正在创建中

(11.1、如果是earlySingletonExposure调用getSingleton将触发【8】处ObjectFactory.getObject()的调用,通过【8.1】处的getEarlyBeanReference获取相关Bean(如包装目标对象的代理Bean);(在循环引用Bean时可能引起Spring事务处理时自我调用的解决方案及一些实现方式的风险);

(12、registerDisposableBeanIfNecessary(beanName, bean, mbd) : 注册Bean的销毁方法(只有非原型Bean可注册);

(12.1、单例Bean的销毁流程

(12.1.1、DestructionAwareBeanPostProcessor的postProcessBeforeDestruction : 第九个扩展点,如InitDestroyAnnotationBeanPostProcessor完成@PreDestroy注解的销毁方法注册和调用;

(12.1.2、DisposableBean的destroy:注册/调用DisposableBean的destroy销毁方法;

(12.1.3、通过xml指定的自定义destroy-method : 注册/调用通过XML指定的destroy-method销毁方法;

(12.1.2、Scope的registerDestructionCallback:注册自定义的Scope的销毁回调方法,如RequestScope、SessionScope等;其流程和【12.1 单例Bean的销毁流程一样】,关于自定义Scope请参考【第三章】 DI 之 3.4
Bean的作用域 ——跟我学spring3

(13、到此Bean实例化、依赖注入、初始化完毕可以返回创建好的bean了。

 

 从上面的流程我们可以看到BeanPostProcessor一个使用了九个扩展点,其实还一个扩展点(SmartInstantiationAwareBeanPostProcessor的predictBeanType在下一篇介绍),接下来我们看看BeanPostProcessor这些扩展点都主要完成什么功能及常见的BeanPostProcessor。

我将在下一帖子中使用例子来解析这八个扩展点的主要功能,及一些Spring默认提供的BeanPostProcessor主要作用。

上接Spring事务处理时自我调用的解决方案及一些实现方式的风险继续分析,在分析上篇的问题之前,我们需要了解下BeanPostProcessor概念和Spring容器创建Bean的流程。

Spring开闭原则的表现-BeanPostProcessor的扩展点-1的更多相关文章

  1. 第2章 面向对象的设计原则(SOLID):6_开闭原则

    6. 开闭原则(Open Closed Principle,OCP) 6.1 定义 (1)一个类应该对扩展开放,对修改关闭.要求通过扩展来实现变化,而且是在不修改己有的代码情况下进行扩展,也不必改动己 ...

  2. Java的开发—面向对象的7大原则之开闭原则(一)

    开闭原则(Open Close Principle) 一.定义: 软件中的(类.模块.函数等等)应该对于扩展是开放的,对于修改时关闭的.意味着一个实体允许在不改变它的源代码的前提变更它的行为 这里的软 ...

  3. Java设计模式(1:软件架构设计七大原则及开闭原则详解)

    前言 在日常工作中,我们使用Java语言进行业务开发的时候,或多或少的都会涉及到设计模式,而运用好设计模式对于我而言,又是一个比较大的难题.为了解决.克服这个难题,笔主特别开了这个博客来记录自己学习的 ...

  4. 设计模式之六大原则——开闭原则(OCP)

    转载于: http://www.cnblogs.com/muzongyan/archive/2010/08/05/1793454.html 开闭原则(Open Closed Principle)是Ja ...

  5. [转]设计模式之六大原则——开闭原则(OCP)

    原文地址:http://www.cnblogs.com/muzongyan/archive/2010/08/05/1793454.html 开闭原则(Open Closed Principle)是Ja ...

  6. [设计模式]<<设计模式之禅>>关于开闭原则

    开闭原则是Java世界里最基础的设计原则,它指导我们如何建立一个稳定的.灵活的系统,先来看开闭原则的定义: Software entities like classes,modules and fun ...

  7. 设计模式值六大原则——开闭原则(OCP)

    开闭原则(Open Closed Principle)是Java世界里最基础的设计原则,它指导我们如何建立一个稳定的.灵活的系统. 定义: 一个软件实体如类.模块和函数应该对扩展开放,对修改关闭. S ...

  8. Java设计原则—开闭原则(转)

    原文出自:http://www.cnblogs.com/muzongyan/archive/2010/08/05/1793454.html 开闭原则(Open Closed Principle)是Ja ...

  9. 最简单直接地理解Java软件设计原则之开闭原则

    写在前面 本文属于Java软件设计原则系列文章的其中一篇,后续会继续分享其他的原则.想以最简单的方式,最直观的demo去彻底理解设计原则.文章属于个人整理.也欢迎大家提出不同的想法. 首先是一些理论性 ...

  10. 最容易懂的策略模式消除if-else分支,实现开闭原则,提高可扩展性

    1 介绍 策略模式最常用的场景就是用于消除代码中的if-else,这里所说的if-else并不是说任何简单的判断都引入策略模式来优化,这样反而会增加代码的复杂度. 反例:使用策略模式对一个boolea ...

随机推荐

  1. springboot 静态文件夹

    正常这个很久了,不需要写,但是好几年没有写这个相关的,都忘了,好记性不如烂笔头 spring: resources: static-locations: file:D:\\test #对应服务器内映射 ...

  2. VC 单文档FormView视图增加打印预览

    1修改my.rc文件二处 3 TEXTINCLUDE BEGIN "#define _AFX_NO_OLE_RESOURCES\r\n" "#define _AFX_NO ...

  3. Zeppelin 学习

    Zeppelin 遇到的问题: 1. 在interpreter 界面配置 dependency management 了以后,报 Error setting properties for interp ...

  4. C++: 智能指针的自定义删除器 `Custom Deleter` 有什么用?

    C++11智能指针std::shared_ptr和std::unique_ptr都支持自定义删除器,本文将介绍自定义删除器的使用场景和使用方法.智能指针模板参数的第二个类型是删除器,一般是一个函数指针 ...

  5. SQL全表扫描优化基础知识

    1.模糊查询效率很低: 原因:like本身效率就比较低,应该尽量避免查询条件使用like:对于like '%...%'(全模糊)这样的条件,是无法使用索引的,全表扫描自然效率很低:另外,由于匹配算法的 ...

  6. 通用能力及AI核心能力表现优异!合合信息智能文档处理系统(IDP)高评级通过中国信通院评估

    数字经济快速发展的背后,全球数据总量呈现出爆发式增长趋势.智能文档处理(IDP)技术能够高效地从多格式文档中捕捉.提取和处理数据,帮助机构和企业大幅提升文档处理效率,节约时间和人力成本.近期,合合信息 ...

  7. ASP.NET Core – View Component

    前言 以前写过 Asp.net core 学习笔记 ( ViewComponent 组件 ), 这篇作为翻新版. 参考 Docs – View components in ASP.NET Core D ...

  8. 微信js-sdk接入原理

    1.有一个微信公众号,并获取到该公众号的AppID和AppSecret. 其中AppID是可以对外公开的,AppSecret是该公众号的密钥,是需要绝对保密的 2.向微信服务器发送一个GET请求,获取 ...

  9. urb中几个函数的使用

    usb_buffer_alloc(free) 说是为了更好的从名字看出这个函数真实做的事情:DMA coherency linux提供两种方式,来保证使用dma时,内存和硬件cache的一致性: us ...

  10. Android dex、odex、oat、vdex、art区别

    1.dex java程序编译成class后,dx工具将所有class文件合成一个dex文件,dex文件是jar文件大小的50%左右. 2.odex(Android5.0之前)全称:Optimized ...