Spring源码--IOC容器实现(5)--Bean对象的创建

2023-05-16

前言

Github:https://github.com/yihonglei/thinking-in-spring

在前面文章中分析了容器初始化过程,已经建立了一个可以使用的容器。

1)BeanDefinition的Resource定位

2)BeanDefinition的载入和解析

3)BeanDefinition的注册

    容器初始化的工作主要是在IOC容器中建立了BeanDefinition数据映射,并通过HashMap持有数据,

BeanDefinition都在beanDefinitionMap里被检索和使用。在IOC容器BeanFactory中,有一个getBean的接口定义,

通过这个接口实现可以获取到Bean对象。但是,这个Bean对象并不是一个普通的Bean对象,它是一个处理完依赖关系

后的Bean对象。所以一个getBean()实现里面,分为两个大步骤来处理返回用户需要的Bean对象:

1)根据BeanDefinition创建Bean对象,也即Bean对象的创建。

2)创建出来的Bean是一个还没有建立依赖关系的Bean,所有需要完成依赖关系建立,叫做Bean依赖注入。

本文先分析如何根据BeanDefinition数据结构创建用户需要的Bean,下面从就从BeanFactory入手去看getBean的实现。

BeanFactory源码:


 
 
  1. package org.springframework.beans.factory;
  2. import org.springframework.beans.BeansException;
  3. import org.springframework.core.ResolvableType;
  4. public interface BeanFactory {
  5. String FACTORY_BEAN_PREFIX = "&";
  6. Object getBean(String name) throws BeansException;
  7. <T> T getBean(String name, Class<T> requiredType) throws BeansException;
  8. <T> T getBean(Class<T> requiredType) throws BeansException;
  9. Object getBean(String name, Object... args) throws BeansException;
  10. <T> T getBean(Class<T> requiredType, Object... args) throws BeansException;
  11. boolean containsBean(String name);
  12. boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
  13. boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
  14. boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;
  15. boolean isTypeMatch(String name, Class<?> typeToMatch) throws NoSuchBeanDefinitionException;
  16. Class<?> getType(String name) throws NoSuchBeanDefinitionException;
  17. String[] getAliases(String name);
  18. }

从getBean(String name)最简单明了的方法入手看实现,该方法在很多类中有实现,重点研究AbstractBeanFactory

中的实现方法。

AbstractBeanFactory.getBean()方法源码:


 
 
  1. @Override
  2. public Object getBean(String name) throws BeansException {
  3. return doGetBean(name, null, null, false);
  4. }

AbstractBeanFactory.doGetBean()方法源码:


 
 
  1. protected <T> T doGetBean(
  2. final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
  3. throws BeansException {
  4. final String beanName = transformedBeanName(name);
  5. Object bean;
  6. // Eagerly check singleton cache for manually registered singletons.
  7. // 先从缓存中获得Bean,处理那些已经被创建过的单间模式的Bean,对这种Bean的请求不需要重复地创建
  8. Object sharedInstance = getSingleton(beanName);
  9. if (sharedInstance != null && args == null) {
  10. if (logger.isDebugEnabled()) {
  11. if (isSingletonCurrentlyInCreation(beanName)) {
  12. logger.debug( "Returning eagerly cached instance of singleton bean '" + beanName +
  13. "' that is not fully initialized yet - a consequence of a circular reference");
  14. }
  15. else {
  16. logger.debug( "Returning cached instance of singleton bean '" + beanName + "'");
  17. }
  18. }
  19. // 这里的getObjectForBeanInstance完成的是FactoryBean的相关处理,以取得FactoryBean的生产结果
  20. bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
  21. }
  22. else {
  23. // Fail if we're already creating this bean instance:
  24. // We're assumably within a circular reference.
  25. if (isPrototypeCurrentlyInCreation(beanName)) {
  26. throw new BeanCurrentlyInCreationException(beanName);
  27. }
  28. // Check if bean definition exists in this factory.
  29. /**
  30. * 对IOC容器中的BeanDefinition是否存在进行检查,检查是否能在当前的BeanFactory中取得需要的Bean。
  31. * 如果在当前的工厂中取不到,则到双亲BeanFactory中去取;
  32. * 如果当前的双亲工厂取不到,就顺着双亲BeanFactory链一直向上查找
  33. */
  34. BeanFactory parentBeanFactory = getParentBeanFactory();
  35. if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
  36. // Not found -> check parent.
  37. String nameToLookup = originalBeanName(name);
  38. if (args != null) {
  39. // Delegation to parent with explicit args.
  40. return (T) parentBeanFactory.getBean(nameToLookup, args);
  41. }
  42. else {
  43. // No args -> delegate to standard getBean method.
  44. return parentBeanFactory.getBean(nameToLookup, requiredType);
  45. }
  46. }
  47. if (!typeCheckOnly) {
  48. markBeanAsCreated(beanName);
  49. }
  50. try {
  51. // 根据Bean的名字获取BeanDefinition
  52. final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
  53. checkMergedBeanDefinition(mbd, beanName, args);
  54. // Guarantee initialization of beans that the current bean depends on.
  55. // 获取当前Bean的所有依赖Bean,这样会触发getBean的递归调用,直到渠道一个没有任何依赖的Bean为止
  56. String[] dependsOn = mbd.getDependsOn();
  57. if (dependsOn != null) {
  58. for (String dep : dependsOn) {
  59. if (isDependent(beanName, dep)) {
  60. throw new BeanCreationException(mbd.getResourceDescription(), beanName,
  61. "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
  62. }
  63. registerDependentBean(dep, beanName);
  64. getBean(dep);
  65. }
  66. }
  67. // Create bean instance.
  68. // 以下是创建Bean实例
  69. // 创建sigleton bean
  70. if (mbd.isSingleton()) {
  71. sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
  72. @Override
  73. public Object getObject() throws BeansException {
  74. try {
  75. return createBean(beanName, mbd, args);
  76. }
  77. catch (BeansException ex) {
  78. // Explicitly remove instance from singleton cache: It might have been put there
  79. // eagerly by the creation process, to allow for circular reference resolution.
  80. // Also remove any beans that received a temporary reference to the bean.
  81. destroySingleton(beanName);
  82. throw ex;
  83. }
  84. }
  85. });
  86. bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
  87. }
  88. // 创建prototype bean
  89. else if (mbd.isPrototype()) {
  90. // It's a prototype -> create a new instance.
  91. Object prototypeInstance = null;
  92. try {
  93. beforePrototypeCreation(beanName);
  94. prototypeInstance = createBean(beanName, mbd, args);
  95. }
  96. finally {
  97. afterPrototypeCreation(beanName);
  98. }
  99. bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
  100. }
  101. else {
  102. String scopeName = mbd.getScope();
  103. final Scope scope = this.scopes.get(scopeName);
  104. if (scope == null) {
  105. throw new IllegalStateException( "No Scope registered for scope name '" + scopeName + "'");
  106. }
  107. try {
  108. Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() {
  109. @Override
  110. public Object getObject() throws BeansException {
  111. beforePrototypeCreation(beanName);
  112. try {
  113. return createBean(beanName, mbd, args);
  114. }
  115. finally {
  116. afterPrototypeCreation(beanName);
  117. }
  118. }
  119. });
  120. bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
  121. }
  122. catch (IllegalStateException ex) {
  123. throw new BeanCreationException(beanName,
  124. "Scope '" + scopeName + "' is not active for the current thread; consider " +
  125. "defining a scoped proxy for this bean if you intend to refer to it from a singleton",
  126. ex);
  127. }
  128. }
  129. }
  130. catch (BeansException ex) {
  131. cleanupAfterBeanCreationFailure(beanName);
  132. throw ex;
  133. }
  134. }
  135. // Check if required type matches the type of the actual bean instance.
  136. // 对创建的Bean进行类型检查,如果没有问题,就返回这个新创建的Bean,这个Bean已经是包含依赖关系的Bean
  137. if (requiredType != null && bean != null && !requiredType.isAssignableFrom(bean.getClass())) {
  138. try {
  139. return getTypeConverter().convertIfNecessary(bean, requiredType);
  140. }
  141. catch (TypeMismatchException ex) {
  142. if (logger.isDebugEnabled()) {
  143. logger.debug( "Failed to convert bean '" + name + "' to required type '" +
  144. ClassUtils.getQualifiedName(requiredType) + "'", ex);
  145. }
  146. throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
  147. }
  148. }
  149. return (T) bean;
  150. }

   getBean()方法只是创建对象的起点,doGetBean()只是getBean()的具体执行,在doGetBean()中会调用createBean()

方法,在这个过程中,Bean对象会依据BeanDefinition定义的要求生成。AbstractBeanFactory中的createBean是一个

抽象方法,具体的实现在AbstractAutowireCapableBeanFactory中。

AbstractAutowireCapableBeanFactory.createBean()方法源码:


 
 
  1. @Override
  2. protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException {
  3. if (logger.isDebugEnabled()) {
  4. logger.debug( "Creating instance of bean '" + beanName + "'");
  5. }
  6. RootBeanDefinition mbdToUse = mbd;
  7. // Make sure bean class is actually resolved at this point, and
  8. // clone the bean definition in case of a dynamically resolved Class
  9. // which cannot be stored in the shared merged bean definition.
  10. // 判断需要创建的Bean是否可以实例化,
  11. Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
  12. if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
  13. mbdToUse = new RootBeanDefinition(mbd);
  14. mbdToUse.setBeanClass(resolvedClass);
  15. }
  16. // Prepare method overrides.
  17. try {
  18. mbdToUse.prepareMethodOverrides();
  19. }
  20. catch (BeanDefinitionValidationException ex) {
  21. throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
  22. beanName, "Validation of method overrides failed", ex);
  23. }
  24. try {
  25. // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
  26. // 如果Bean配置了PostProcessor,则返回一个proxy代理对象
  27. Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
  28. if (bean != null) {
  29. return bean;
  30. }
  31. }
  32. catch (Throwable ex) {
  33. throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
  34. "BeanPostProcessor before instantiation of bean failed", ex);
  35. }
  36. // 创建Bean的调用
  37. Object beanInstance = doCreateBean(beanName, mbdToUse, args);
  38. if (logger.isDebugEnabled()) {
  39. logger.debug( "Finished creating instance of bean '" + beanName + "'");
  40. }
  41. return beanInstance;
  42. }

AbstractAutowireCapableBeanFactory.doCreateBean()方法源码:


 
 
  1. protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
  2. throws BeanCreationException {
  3. // Instantiate the bean.
  4. // 这个BeanWrapper是用来持有创建出来的Bean对象
  5. BeanWrapper instanceWrapper = null;
  6. // 如果是Singleton,先把缓存中的同名Bean清除
  7. if (mbd.isSingleton()) {
  8. instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
  9. }
  10. // 通过createBeanInstance()创建Bean
  11. if (instanceWrapper == null) {
  12. instanceWrapper = createBeanInstance(beanName, mbd, args);
  13. }
  14. final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
  15. Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);
  16. mbd.resolvedTargetType = beanType;
  17. // Allow post-processors to modify the merged bean definition.
  18. synchronized (mbd.postProcessingLock) {
  19. if (!mbd.postProcessed) {
  20. try {
  21. applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
  22. }
  23. catch (Throwable ex) {
  24. throw new BeanCreationException(mbd.getResourceDescription(), beanName,
  25. "Post-processing of merged bean definition failed", ex);
  26. }
  27. mbd.postProcessed = true;
  28. }
  29. }
  30. // Eagerly cache singletons to be able to resolve circular references
  31. // even when triggered by lifecycle interfaces like BeanFactoryAware.
  32. boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
  33. isSingletonCurrentlyInCreation(beanName));
  34. if (earlySingletonExposure) {
  35. if (logger.isDebugEnabled()) {
  36. logger.debug( "Eagerly caching bean '" + beanName +
  37. "' to allow for resolving potential circular references");
  38. }
  39. addSingletonFactory(beanName, new ObjectFactory<Object>() {
  40. @Override
  41. public Object getObject() throws BeansException {
  42. return getEarlyBeanReference(beanName, mbd, bean);
  43. }
  44. });
  45. }
  46. // Initialize the bean instance.
  47. // 对Bean进行初始化,这个exposedObject在初始化以后会返回座位依赖注入完成后的Bean
  48. Object exposedObject = bean;
  49. try {
  50. populateBean(beanName, mbd, instanceWrapper);
  51. if (exposedObject != null) {
  52. exposedObject = initializeBean(beanName, exposedObject, mbd);
  53. }
  54. }
  55. catch (Throwable ex) {
  56. if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
  57. throw (BeanCreationException) ex;
  58. }
  59. else {
  60. throw new BeanCreationException(
  61. mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
  62. }
  63. }
  64. if (earlySingletonExposure) {
  65. Object earlySingletonReference = getSingleton(beanName, false);
  66. if (earlySingletonReference != null) {
  67. if (exposedObject == bean) {
  68. exposedObject = earlySingletonReference;
  69. }
  70. else if (! this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
  71. String[] dependentBeans = getDependentBeans(beanName);
  72. Set<String> actualDependentBeans = new LinkedHashSet<String>(dependentBeans.length);
  73. for (String dependentBean : dependentBeans) {
  74. if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
  75. actualDependentBeans.add(dependentBean);
  76. }
  77. }
  78. if (!actualDependentBeans.isEmpty()) {
  79. throw new BeanCurrentlyInCreationException(beanName,
  80. "Bean with name '" + beanName + "' has been injected into other beans [" +
  81. StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
  82. "] in its raw version as part of a circular reference, but has eventually been " +
  83. "wrapped. This means that said other beans do not use the final version of the " +
  84. "bean. This is often the result of over-eager type matching - consider using " +
  85. "'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
  86. }
  87. }
  88. }
  89. }
  90. // Register bean as disposable.
  91. try {
  92. registerDisposableBeanIfNecessary(beanName, bean, mbd);
  93. }
  94. catch (BeanDefinitionValidationException ex) {
  95. throw new BeanCreationException(
  96. mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
  97. }
  98. return exposedObject;
  99. }

看下真正创建Bean对象的方法createBeanInstance(),该方法会生成包含Java对象的Bean,这个Bean生成有很多

中方式,可以通过工厂方法生成,也可以通过容器的Autowire特性生成,这些生成方式都是由相关的BeanDefinition

来指定的。看下以下正在创建对象的源码。

AbstractAutowireCapableBeanFactory.createBeanInstance()方法源码:


 
 
  1. protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {
  2. // Make sure bean class is actually resolved at this point.
  3. // 确认需要创建的Bean实例的类可以实例化
  4. Class<?> beanClass = resolveBeanClass(mbd, beanName);
  5. // 以下通过工厂方法对Bean进行实例化
  6. if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
  7. throw new BeanCreationException(mbd.getResourceDescription(), beanName,
  8. "Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
  9. }
  10. if (mbd.getFactoryMethodName() != null) {
  11. return instantiateUsingFactoryMethod(beanName, mbd, args);
  12. }
  13. // Shortcut when re-creating the same bean...
  14. // 重新创建Bean的快捷方式
  15. boolean resolved = false;
  16. boolean autowireNecessary = false;
  17. if (args == null) {
  18. synchronized (mbd.constructorArgumentLock) {
  19. if (mbd.resolvedConstructorOrFactoryMethod != null) {
  20. resolved = true;
  21. autowireNecessary = mbd.constructorArgumentsResolved;
  22. }
  23. }
  24. }
  25. if (resolved) {
  26. if (autowireNecessary) {
  27. return autowireConstructor(beanName, mbd, null, null);
  28. }
  29. else {
  30. return instantiateBean(beanName, mbd);
  31. }
  32. }
  33. // Need to determine the constructor...
  34. // 以下使用构造函数对Bean进行实例化
  35. Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
  36. if (ctors != null ||
  37. mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||
  38. mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
  39. return autowireConstructor(beanName, mbd, ctors, args);
  40. }
  41. // No special handling: simply use no-arg constructor.
  42. // 使用默认的构造器函数对Bean进行实例化
  43. return instantiateBean(beanName, mbd);
  44. }

instantiateBean()方法采用默认构造器实例化bean的过程。

AbstractAutowireCapableBeanFactory.instantiateBean()方法源码:


 
 
  1. protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {
  2. try {
  3. Object beanInstance;
  4. final BeanFactory parent = this;
  5. if (System.getSecurityManager() != null) {
  6. beanInstance = AccessController.doPrivileged( new PrivilegedAction<Object>() {
  7. @Override
  8. public Object run() {
  9. return getInstantiationStrategy().instantiate(mbd, beanName, parent);
  10. }
  11. }, getAccessControlContext());
  12. }
  13. else {
  14. beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);
  15. }
  16. BeanWrapper bw = new BeanWrapperImpl(beanInstance);
  17. initBeanWrapper(bw);
  18. return bw;
  19. }
  20. catch (Throwable ex) {
  21. throw new BeanCreationException(
  22. mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);
  23. }
  24. }

类中使用默认的实例化策略进行实例化,默认采用CGLIB对Bean进行实例化。CGLIB是一个常用的字节码

生成器的类库,它提供了一些列的API来提供生成和转换Java的字节码的功能。

SimpleInstantiationStrategy.instantiate()方法源码:


 
 
  1. @Override
  2. public Object instantiate(RootBeanDefinition bd, String beanName, BeanFactory owner) {
  3. // Don't override the class with CGLIB if no overrides.
  4. if (bd.getMethodOverrides().isEmpty()) {
  5. // 获取指定的构造器或者生产对象工厂方法来对Bean进行实例化
  6. Constructor<?> constructorToUse;
  7. synchronized (bd.constructorArgumentLock) {
  8. constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod;
  9. if (constructorToUse == null) {
  10. final Class<?> clazz = bd.getBeanClass();
  11. if (clazz.isInterface()) {
  12. throw new BeanInstantiationException(clazz, "Specified class is an interface");
  13. }
  14. try {
  15. if (System.getSecurityManager() != null) {
  16. constructorToUse = AccessController.doPrivileged( new PrivilegedExceptionAction<Constructor<?>>() {
  17. @Override
  18. public Constructor<?> run() throws Exception {
  19. return clazz.getDeclaredConstructor((Class[]) null);
  20. }
  21. });
  22. }
  23. else {
  24. constructorToUse = clazz.getDeclaredConstructor((Class[]) null);
  25. }
  26. bd.resolvedConstructorOrFactoryMethod = constructorToUse;
  27. }
  28. catch (Throwable ex) {
  29. throw new BeanInstantiationException(clazz, "No default constructor found", ex);
  30. }
  31. }
  32. }
  33. // 通过BeanUtils进行实例化,这个BeanUtils实例化通过Constructor来实例化Bean,
  34. // 在BeanUtils中可以看到具体的调用ctor.newInstance(args)
  35. return BeanUtils.instantiateClass(constructorToUse);
  36. }
  37. else {
  38. // Must generate CGLIB subclass.
  39. // 使用CGLIB进行实例化
  40. return instantiateWithMethodInjection(bd, beanName, owner);
  41. }
  42. }

BeanUtils.instantiateClass()源码:


 
 
  1. public static <T> T instantiateClass(Constructor<T> ctor, Object... args) throws BeanInstantiationException {
  2. Assert.notNull(ctor, "Constructor must not be null");
  3. try {
  4. ReflectionUtils.makeAccessible(ctor);
  5. return ctor.newInstance(args);
  6. }
  7. catch (InstantiationException ex) {
  8. throw new BeanInstantiationException(ctor, "Is it an abstract class?", ex);
  9. }
  10. catch (IllegalAccessException ex) {
  11. throw new BeanInstantiationException(ctor, "Is the constructor accessible?", ex);
  12. }
  13. catch (IllegalArgumentException ex) {
  14. throw new BeanInstantiationException(ctor, "Illegal arguments for constructor", ex);
  15. }
  16. catch (InvocationTargetException ex) {
  17. throw new BeanInstantiationException(ctor, "Constructor threw exception", ex.getTargetException());
  18. }
  19. }

如果感兴趣,可以一直追溯newInstance()方法,最后调用一个Native方法创建对象。

到此,Bean对象创建完成。

 

参考文献:

1、《Spring技术内幕》

2、《Spring实战》

3、Spring官网API

4、Spring源码

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

Spring源码--IOC容器实现(5)--Bean对象的创建 的相关文章

  • 面试可能遇到的问题野指针等解决方法

    空指针 xff1a 一般声明一个指针变量赋值为NULL xff0c 这就是空指针 xff0c 各个类型的空指针都存在确确实实的内存地址 xff0c 但是不会指向任何有效的值的内存地址 xff0c 对空指针操作 xff0c 例如访问属性和方法
  • 大规模分布式储存系统笔记(一)

    分布式储存系统的特性 xff1a 1 可扩展性 可按集群规模增长 xff0c 系统性能线性增长 xff1b 2 低成本 系统自动容错 xff0c 自动负载均衡 xff0c 运维方便 3 高性能 4 易用性 对外提供接口 数据类型 xff1a
  • 用MATLAB实现对运动物体识别与跟踪

    不得不说MATLAB的图像处理函数有点多 xff0c 但速度有时也是出奇的慢 还是想c的指针 xff0c 虽然有点危险 xff0c 但速度那是杠杠的 第二个MATLAB程序 xff0c 对运动物体的识别与追踪 这里我们主要运用帧差法实现运动
  • PS 开启GPU加速图片处理

    还认为你的电脑的速度效果比不上苹果吗 xff1f 还在嫌电脑渲染速度慢吗 xff1f 试一下 xff0c 电脑开启GPU硬件加速吧 xff01 只要有独显轻松加速 xff08 毕竟苹果笔记本要配独显电脑的价格基本上在15000以上 xff0
  • 【附源码】计算机毕业设计SSM社区团购系统

    项目运行 环境配置 xff1a Jdk1 8 43 Tomcat7 0 43 Mysql 43 HBuilderX xff08 Webstorm也行 xff09 43 Eclispe xff08 IntelliJ IDEA Eclispe
  • Maven 使用slf4j 没有输出控制台

    Maven 使用slf4j 没有输出控制台并报如下错 xff1a log4j WARN No appenders could be found span class hljs keyword for span logger Redissen
  • 管道鸟cortex-M4(TM4C1294)

    看到满屏的贪吃蛇 xff0c 我也来开源一个Ti开发板 xff08 TM4C1294 xff09 的游戏 将简化版的管道鸟 xff0c 根据自己玩的经历 xff0c 在cortexm4开发板上重新撸了一边 xff0c 设计思路 xff1a
  • C#连接MYSQL数据库并进行查询

    之前用MFC开发结果界面太难看被pass了 要求用C 重新来开发 gt lt 不过终于摆脱VC6 0的蛋疼操作了Y 先来连接数据库 xff08 1 xff09 用c 连接MYSQL数据库需要用到mysql connector net xff
  • Jetson tx2刷机过程中的坑

    暑假各种事忙得差不多后 xff0c 终于有时间拿出早就申请到的tx2 xff0c 开始刷机教程 xff0c 这两天几乎踩边了所有的坑 第一个坑 xff0c 虚拟机 一般在安装VMware虚拟机时 xff0c 建议的安装空间20GB xff0
  • python词云实现

    python的一个蛮酷炫的功能是可以轻松地实现词云 github上有关于这个项目的开源代码 xff1a https github com amueller word cloud 注意跑例程时要删除里面的wordcloud文件夹 词云的功能有
  • ubuntu18切换为gnome桌面托盘图标消失

    在软件菜单中选择 优化 拓展 gt Ubuntu appindicators xff0c 打开此项即可 效果
  • Expression #1 of ORDER BY clause is not in SELECT list, references column 'ekbX1.t0.name' which is n

    报错信息 xff1a Expression 1 of ORDER BY clause is not in SELECT list references column 39 ekbX1 t0 name 39 which is not in S
  • Archlinux + kde桌面环境 安装

    1 首先余留磁盘空间 2 xff1a 官网下载ArchLinux镜像 3 xff1a rufus刻录 4 xff1a 打开电脑从u盘启动 5 xff1a 首先联网 如果用wifi终端输入下面命令 xff1a wifi menu 如果是用网线
  • 判断图的连通子图个数

    题目要求 给定一个具有n个顶点 m条边的无向图G 假设项点的编号为1 n 基于深度优先搜索算法 xff0c 编写程序 求无向图G连通子图的个数 输入格式 第一行两个整数n m 分别表示图G的顶点数和边的数量 下面m行的每 行有两个整数a和b
  • Java常用包有哪些

    Java lang 语言包 Java语言的基础类 xff0c 包括Object类 Thread类 String Math System Runtime Class Exception Process等 xff0c 是Java的核心类库 最重
  • QT 建立透明背景图像QPixmap

    列将下面背景透明图片1转变成图片2 图1 图2 span class hljs preprocessor include 34 mainwindow h 34 span span class hljs preprocessor includ
  • Spring Boot——日志文件

    文章目录 1 日志的作用2 日志的用法3 自定义日志打印日志格式的说明 4 日志级别5 在配置文件中设置日志级别5 1设置全局的日志级别和局部文件夹的日志级别 6 日志持久化7 更简单的日志输出 lombok 1 日志的作用 日志的作用 x
  • VxWorks入门06:虚拟机中运行

    在下载的VxWorks安装包中 xff0c 包含了一份在虚拟机下安装测试的文档 xff0c 我们按照这个文档测试一下 VxWorks 6 8 3 43 VxWorks Workbench 3 2 3 43 VMware 16 1 2 43
  • 后浪小萌新Python --- 类中的属性

    一 什么是属性 我们通过类中的属性来保存类相关的属性 二 属性的分类 类中的属性分为两种 xff1a 类属性和对象属性 类属性 类的字段 a 定义 xff1a 直接定义在类中的变量就是类属性 b 使用 xff1a 类 属性 c 什么时候用
  • 业务架构的定义、特性和方法

    引言 业务架构一般不被开发重视 xff0c 开发人员喜欢追求新技术 xff0c 而技术是服务于业务的 xff0c 现在没有一项技术是自娱自乐的 xff0c 一定要支撑业务 xff0c 否则没有场景 设计好业务架构要考虑的方面比较多 xff0

随机推荐

  • VMware虚拟机扩展磁盘空间Ubuntu(超简单)

    一 简介 在平时使用时 xff0c 会遇到安装的虚拟机磁盘空间不足 的情况 此时需要给系统扩展磁盘空间 网上的很多教程都是输入一堆命令 xff0c 申请 分配 初始化 挂载等等特别麻烦 今天介绍一个最简单 最实用 的方法 二 实操 先进入r
  • Ubuntu 安装git及git命令

    1 检查git是否已经安装 xff0c 输入git version命令即可 xff0c 如果没有显示版本号表示没有安装git 2 安装git sudo apt get install git 3 配置git全局环境 git config g
  • Bad method handle type 7异常解决

    在利用androidx版本写demo时 xff0c 在添加了一些依赖后 xff0c 遇到了java lang ClassNotFoundExceptionbug xff0c 这就很奇怪了 xff0c 我就添加rxjava3的依赖 xff0c
  • linux防火墙添加端口

    iptables版 iptables nL line number vi etc sysconfig iptables 添加以下语句 A RH Firewall 1 INPUT p tcp m state state NEW m tcp d
  • 如何在webstorm使用eslint检查代码规范

    一 安装esLint xff08 一 xff09 打开项目代码 xff0c 进入terminal xff08 二 xff09 安装esLint 1 安装esLint npm install eslint span class token o
  • VUE基本格式

    96 VUE基本格式 lt template gt lt div gt lt div gt lt template gt lt script gt export default beforeCreate function data retu
  • Decode Ways 解码方法

    一条包含字母 A Z 的消息通过以下方式进行了编码 xff1a 39 A 39 gt 1 39 B 39 gt 2 39 Z 39 gt 26 给定一个只包含数字的非空 字符串 xff0c 请计算解码方法的总数 示例 1 输入 34 12
  • CAS单点登录6 - 服务端自定义返回的用户信息

    原理 返回的用户信息是在deployerConfigContext xml中的配置的 既然想自定义返回的用户信息 xff0c 那么继承org jasig services persondir support StubPersonAttrib
  • kotlin-android-extensions处理方案

    不幸的是 xff0c kotlin android extensions官方提示过时了 xff0c 而且列出来了几个过时的原因 但是这些我都不在乎 xff0c 也不觉得会对我产生什么影响 那可以尝试这样吧 xff0c 再被as彻底删除之后
  • Fragment跳转到Activity无动画

    这段代码无效果 xff1a startActivity span class hljs keyword new span Intent mContext GalleryActivity span class hljs keyword cla
  • Matlab科研绘图颜色补充(特别篇)—51种中国传统颜色

    前几天在找资料的时候 xff0c 发现了这个 xff1a 这是由 中国国家地理 杂志社制作的色卡 xff0c 据说总共包含98种中国传统颜色 xff0c 但目前能找到的就是这51种 xff08 而且比较模糊 xff09 百草霜 竹月 胭脂
  • Tensorflow Lite GPU在安卓上实现

    在近期工作中 xff0c 采用TensorFlow Lite将ssd mobilenet目标检测模型移植安卓机上 从安卓机测试的效果来看 xff0c 非量化的模型每帧图像推理的速率较慢 为压缩模型提升推理速度 xff0c 采用了减少模型深度
  • 面试官让我手写一个生产者消费者模式

    不知道你是否遇到过面试官让你手写生产者消费者代码 别说 xff0c 前段时间有小伙伴还真的遇到了这种情况 当时是一脸懵逼 但是 xff0c 俗话说 xff0c 从哪里跌倒就要从哪里爬起来 既然这次被问到了 xff0c 那就回去好好研究一下
  • 2-11 附:文档的基本操作 - 查询

  • ActiveMQ的简单Topic实现案例

    首先我们在这里要说一下消息中间件中有两个角色 xff0c 生产者Producer与消费者Consumer xff0c 简单理解即使发发送消息者与接收消息者 xff0c 在编写代码之前我们需要将下载到的ActiveMQ压缩包中的activem
  • Java学习之旅--集合的使用(Map集合)

    好几天没有更新了 xff0c 主要是最近正在学习集合 xff0c 让博主有点头大 所以就耽误了 xff1a 现在就来说说集合里的Map集合 xff1a import java span class hljs preprocessor uti
  • CartPole 强化学习详解1 - DQN

    工作中常会接触到强化学习的内容 xff0c 自己以gym环境中的Cartpole为例动手实现一下 xff0c 记录点实现细节 环境 xff1a python 61 3 6 13 xff1b pytorch 61 1 10 2 目录 1 gy
  • Java学习之旅--线程的创建方法

    线程创建的方法一 span class hljs keyword package span com geminno day14 createthread1 span class hljs keyword public span span c
  • select搜索功能实现

    select搜索功能实现 最近在找工作 没时间写博客 现在找到了 就发发工作上的代码吧 xff01 今天我们说说select标签的搜索功能 xff1b 拿到任务时 xff0c 我先想到就是上网找资料 xff0c 最后看到的都是各种jquer
  • Spring源码--IOC容器实现(5)--Bean对象的创建

    前言 Github xff1a https github com yihonglei thinking in spring 在前面文章中分析了容器初始化过程 xff0c 已经建立了一个可以使用的容器 1 xff09 BeanDefiniti