其实在面试过程中问的最多的可能是自动装配的原理,而自动装配是在启动过程中完成,只不过在刚开始的时候我们选择性的跳过了,下面详细讲解自动装配的过程。 【5分钟背八股】12:Springboot自动装配原理是什么?.png 1、在springboot的启动过程中,有一个步骤是创建上下文,如果不记得可以看下面的代码: public ConfigurableApplicationContext run(String... args) { StopWatch stopWatch = new StopWatch(); stopWatch.start(); ConfigurableApplicationContext context = null; Collection exceptionReporters = new ArrayList<>(); configureHeadlessProperty(); SpringApplicationRunListeners listeners = getRunListeners(args); listeners.starting(); try { ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments); configureIgnoreBeanInfo(environment); Banner printedBanner = printBanner(environment); context = createApplicationContext(); exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[] { ConfigurableApplicationContext.class }, context); //此处完成自动装配的过程 prepareContext(context, environment, listeners, applicationArguments, printedBanner); refreshContext(context); afterRefresh(context, applicationArguments); stopWatch.stop(); if (this.logStartupInfo) { new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch); } listeners.started(context); callRunners(context, applicationArguments); } catch (Throwable ex) { handleRunFailure(context, ex, exceptionReporters, listeners); throw new IllegalStateException(ex); } try { listeners.running(context); } catch (Throwable ex) { handleRunFailure(context, ex, exceptionReporters, null); throw new IllegalStateException(ex); } return context; } 2、在prepareContext方法中查找load方法,一层一层向内点击,找到最终的load方法 //prepareContext方法 private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) { context.setEnvironment(environment); postProcessApplicationContext(context); applyInitializers(context); listeners.contextPrepared(context); if (this.logStartupInfo) { logStartupInfo(context.getParent() == null); logStartupProfileInfo(context); } // Add boot specific singleton beans ConfigurableListableBeanFactory beanFactory = context.getBeanFactory(); beanFactory.registerSingleton("springApplicationArguments", applicationArguments); if (printedBanner != null) { beanFactory.registerSingleton("springBootBanner", printedBanner); } if (beanFactory instanceof DefaultListableBeanFactory) { ((DefaultListableBeanFactory) beanFactory) .setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding); } if (this.lazyInitialization) { context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor()); } // Load the sources Set sources = getAllSources(); Assert.notEmpty(sources, "Sources must not be empty"); //load方法完成该功能 load(context, sources.toArray(new Object[0])); listeners.contextLoaded(context); } /** * Load beans into the application context. * @param context the context to load beans into * @param sources the sources to load * 加载bean对象到context中 */ protected void load(ApplicationContext context, Object[] sources) { if (logger.isDebugEnabled()) { logger.debug("Loading source " + StringUtils.arrayToCommaDelimitedString(sources)); } //获取bean对象定义的加载器 BeanDefinitionLoader loader = createBeanDefinitionLoader(getBeanDefinitionRegistry(context), sources); if (this.beanNameGenerator != null) { loader.setBeanNameGenerator(this.beanNameGenerator); } if (this.resourceLoader != null) { loader.setResourceLoader(this.resourceLoader); } if (this.environment != null) { loader.setEnvironment(this.environment); } loader.load(); } /** * Load the sources into the reader. * @return the number of loaded beans */ int load() { int count = 0; for (Object source : this.sources) { count += load(source); } return count; } 3、实际执行load的是BeanDefinitionLoader中的load方法,如下: //实际记载bean的方法 private int load(Object source) { Assert.notNull(source, "Source must not be null"); //如果是class类型,启用注解类型 if (source instanceof Class) { return load((Class) source); } //如果是resource类型,启动xml解析 if (source instanceof Resource) { return load((Resource) source); } //如果是package类型,启用扫描包,例如@ComponentScan if (source instanceof Package) { return load((Package) source); } //如果是字符串类型,直接加载 if (source instanceof CharSequence) { return load((CharSequence) source); } throw new IllegalArgumentException("Invalid source type " + source.getClass()); } 4、下面方法将用来判断是否资源的类型,是使用groovy加载还是使用注解的方式 private int load(Class source) { //判断使用groovy脚本 if (isGroovyPresent() && GroovyBeanDefinitionSource.class.isAssignableFrom(source)) { // Any GroovyLoaders added in beans{} DSL can contribute beans here GroovyBeanDefinitionSource loader = BeanUtils.instantiateClass(source, GroovyBeanDefinitionSource.class); load(loader); } //使用注解加载 if (isComponent(source)) { this.annotatedReader.register(source); return 1; } return 0; } 5、下面方法判断启动类中是否包含@Component注解,但是会神奇的发现我们的启动类中并没有该注解,继续更进发现MergedAnnotations类传入了一个参数SearchStrategy.TYPE_HIERARCHY,会查找继承关系中是否包含这个注解,@SpringBootApplication-->@SpringBootConfiguration-->@Configuration-->@Component,当找到@Component注解之后,会把该对象注册到AnnotatedBeanDefinitionReader对象中 private boolean isComponent(Class type) { // This has to be a bit of a guess. The only way to be sure that this type is // eligible is to make a bean definition out of it and try to instantiate it. if (MergedAnnotations.from(type, SearchStrategy.TYPE_HIERARCHY).isPresent(Component.class)) { return true; } // Nested anonymous classes are not eligible for registration, nor are groovy // closures return !type.getName().matches(".*\\$_.*closure.*") && !type.isAnonymousClass() && type.getConstructors() != null && type.getConstructors().length != 0; } /** * Register a bean from the given bean class, deriving its metadata from * class-declared annotations. * 从给定的bean class中注册一个bean对象,从注解中找到相关的元数据 */ private void doRegisterBean(Class beanClass, @Nullable String name, @Nullable Class[] qualifiers, @Nullable Supplier supplier, @Nullable BeanDefinitionCustomizer[] customizers) { AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass); if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) { return; } abd.setInstanceSupplier(supplier); ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd); abd.setScope(scopeMetadata.getScopeName()); String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry)); AnnotationConfigUtils.processCommonDefinitionAnnotations(abd); if (qualifiers != null) { for (Class qualifier : qualifiers) { if (Primary.class == qualifier) { abd.setPrimary(true); } else if (Lazy.class == qualifier) { abd.setLazyInit(true); } else { abd.addQualifier(new AutowireCandidateQualifier(qualifier)); } } } if (customizers != null) { for (BeanDefinitionCustomizer customizer : customizers) { customizer.customize(abd); } } BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName); definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry); BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry); } /** * Register the given bean definition with the given bean factory. * 注册主类,如果有别名可以设置别名 */ public static void registerBeanDefinition( BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException { // Register bean definition under primary name. String beanName = definitionHolder.getBeanName(); registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition()); // Register aliases for bean name, if any. String[] aliases = definitionHolder.getAliases(); if (aliases != null) { for (String alias : aliases) { registry.registerAlias(beanName, alias); } } } //@SpringBootApplication @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @SpringBootConfiguration @EnableAutoConfiguration @ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class), @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) }) public @interface SpringBootApplication {} //@SpringBootConfiguration @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Configuration public @interface SpringBootConfiguration {} //@Configuration @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Component public @interface Configuration {} 当看完上述代码之后,只是完成了启动对象的注入,自动装配还没有开始,下面开始进入到自动装配。 6、自动装配入口,从刷新容器开始 @Override public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // Prepare this context for refreshing. prepareRefresh(); // Tell the subclass to refresh the internal bean factory. ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context. prepareBeanFactory(beanFactory); try { // Allows post-processing of the bean factory in context subclasses. postProcessBeanFactory(beanFactory); // Invoke factory processors registered as beans in the context. // 此处是自动装配的入口 invokeBeanFactoryPostProcessors(beanFactory); } 7、在invokeBeanFactoryPostProcessors方法中完成bean的实例化和执行 /** * Instantiate and invoke all registered BeanFactoryPostProcessor beans, * respecting explicit order if given. * Must be called before singleton instantiation. */ protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) { //开始执行beanFactoryPostProcessor对应实现类,需要知道的是beanFactoryPostProcessor是spring的扩展接口,在刷新容器之前,该接口可以用来修改bean元数据信息 PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors()); // Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime // (e.g. through an @Bean method registered by ConfigurationClassPostProcessor) if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) { beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory)); beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader())); } } 8、查看invokeBeanFactoryPostProcessors的具体执行方法 public static void invokeBeanFactoryPostProcessors( ConfigurableListableBeanFactory beanFactory, List beanFactoryPostProcessors) { // Invoke BeanDefinitionRegistryPostProcessors first, if any. Set processedBeans = new HashSet<>(); if (beanFactory instanceof BeanDefinitionRegistry) { BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory; List regularPostProcessors = new ArrayList<>(); List registryProcessors = new ArrayList<>(); //开始遍历三个内部类,如果属于BeanDefinitionRegistryPostProcessor子类,加入到bean注册的集合,否则加入到regularPostProcessors for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) { if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) { BeanDefinitionRegistryPostProcessor registryProcessor = (BeanDefinitionRegistryPostProcessor) postProcessor; registryProcessor.postProcessBeanDefinitionRegistry(registry); registryProcessors.add(registryProcessor); } else { regularPostProcessors.add(postProcessor); } } // Do not initialize FactoryBeans here: We need to leave all regular beans // uninitialized to let the bean factory post-processors apply to them! // Separate between BeanDefinitionRegistryPostProcessors that implement // PriorityOrdered, Ordered, and the rest. List currentRegistryProcessors = new ArrayList<>(); // First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered. //通过BeanDefinitionRegistryPostProcessor获取到对应的处理类“org.springframework.context.annotation.internalConfigurationAnnotationProcessor”,但是需要注意的是这个类在springboot中搜索不到,这个类的完全限定名在AnnotationConfigEmbeddedWebApplicationContext中,在进行初始化的时候会装配几个类,在创建AnnotatedBeanDefinitionReader对象的时候会将该类注册到bean对象中,此处可以看到internalConfigurationAnnotationProcessor为bean名称,容器中真正的类是ConfigurationClassPostProcessor String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false); //首先执行类型为PriorityOrdered的BeanDefinitionRegistryPostProcessor //PriorityOrdered类型表明为优先执行 for (String ppName : postProcessorNames) { if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) { //获取对应的bean currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class)); //用来存储已经执行过的BeanDefinitionRegistryPostProcessor processedBeans.add(ppName); } } sortPostProcessors(currentRegistryProcessors, beanFactory); registryProcessors.addAll(currentRegistryProcessors); //开始执行装配逻辑 invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry); currentRegistryProcessors.clear(); // Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered. //其次执行类型为Ordered的BeanDefinitionRegistryPostProcessor //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. //循环中执行类型不为PriorityOrdered,Ordered类型的BeanDefinitionRegistryPostProcessor boolean 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(); } // Now, invoke the postProcessBeanFactory callback of all processors handled so far. //执行父类方法,优先执行注册处理类 invokeBeanFactoryPostProcessors(registryProcessors, beanFactory); //执行有规则处理类 invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory); } else { // Invoke factory processors registered with the context instance. invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory); } // Do not initialize FactoryBeans here: We need to leave all regular beans // uninitialized to let the bean factory post-processors apply to them! String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false); // Separate between BeanFactoryPostProcessors that implement PriorityOrdered, // Ordered, and the rest. List priorityOrderedPostProcessors = new ArrayList<>(); List orderedPostProcessorNames = new ArrayList<>(); List nonOrderedPostProcessorNames = new ArrayList<>(); for (String ppName : postProcessorNames) { if (processedBeans.contains(ppName)) { // skip - already processed in first phase above } else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) { priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class)); } else if (beanFactory.isTypeMatch(ppName, Ordered.class)) { orderedPostProcessorNames.add(ppName); } else { nonOrderedPostProcessorNames.add(ppName); } } // First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered. sortPostProcessors(priorityOrderedPostProcessors, beanFactory); invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory); // Next, invoke the BeanFactoryPostProcessors that implement Ordered. List orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size()); for (String postProcessorName : orderedPostProcessorNames) { orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class)); } sortPostProcessors(orderedPostProcessors, beanFactory); invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory); // Finally, invoke all other BeanFactoryPostProcessors. List nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size()); for (String postProcessorName : nonOrderedPostProcessorNames) { nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class)); } invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory); // Clear cached merged bean definitions since the post-processors might have // modified the original metadata, e.g. replacing placeholders in values... beanFactory.clearMetadataCache(); } 9、开始执行自动配置逻辑(启动类指定的配置,非默认配置),可以通过debug的方式一层层向里进行查找,会发现最终会在ConfigurationClassParser类中,此类是所有配置类的解析类,所有的解析逻辑在parser.parse(candidates)中 public void parse(Set configCandidates) { for (BeanDefinitionHolder holder : configCandidates) { BeanDefinition bd = holder.getBeanDefinition(); try { //是否是注解类 if (bd instanceof AnnotatedBeanDefinition) { parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName()); } else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) { parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName()); } else { parse(bd.getBeanClassName(), holder.getBeanName()); } } catch (BeanDefinitionStoreException ex) { throw ex; } catch (Throwable ex) { throw new BeanDefinitionStoreException( "Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex); } } //执行配置类 this.deferredImportSelectorHandler.process(); } ------------------- protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException { processConfigurationClass(new ConfigurationClass(metadata, beanName)); } ------------------- protected void processConfigurationClass(ConfigurationClass configClass) throws IOException { if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) { return; } ConfigurationClass existingClass = this.configurationClasses.get(configClass); if (existingClass != null) { if (configClass.isImported()) { if (existingClass.isImported()) { existingClass.mergeImportedBy(configClass); } // Otherwise ignore new imported config class; existing non-imported class overrides it. return; } else { // Explicit bean definition found, probably replacing an import. // Let's remove the old one and go with the new one. this.configurationClasses.remove(configClass); this.knownSuperclasses.values().removeIf(configClass::equals); } } // Recursively process the configuration class and its superclass hierarchy. SourceClass sourceClass = asSourceClass(configClass); do { //循环处理bean,如果有父类,则处理父类,直至结束 sourceClass = doProcessConfigurationClass(configClass, sourceClass); } while (sourceClass != null); this.configurationClasses.put(configClass, configClass); } 10、继续跟进doProcessConfigurationClass方法,此方式是支持注解配置的核心逻辑 /** * Apply processing and build a complete {@link ConfigurationClass} by reading the * annotations, members and methods from the source class. This method can be called * multiple times as relevant sources are discovered. * @param configClass the configuration class being build * @param sourceClass a source class * @return the superclass, or {@code null} if none found or previously processed */ @Nullable protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass) throws IOException { //处理内部类逻辑,由于传来的参数是启动类,并不包含内部类,所以跳过 if (configClass.getMetadata().isAnnotated(Component.class.getName())) { // Recursively process any member (nested) classes first processMemberClasses(configClass, sourceClass); } // Process any @PropertySource annotations //针对属性配置的解析 for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable( sourceClass.getMetadata(), PropertySources.class, org.springframework.context.annotation.PropertySource.class)) { if (this.environment instanceof ConfigurableEnvironment) { processPropertySource(propertySource); } else { logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() + "]. Reason: Environment must implement ConfigurableEnvironment"); } } // Process any @ComponentScan annotations // 这里是根据启动类@ComponentScan注解来扫描项目中的bean Set componentScans = AnnotationConfigUtils.attributesForRepeatable( sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class); if (!componentScans.isEmpty() && !this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) { for (AnnotationAttributes componentScan : componentScans) { // The config class is annotated with @ComponentScan -> perform the scan immediately //遍历项目中的bean,如果是注解定义的bean,则进一步解析 Set scannedBeanDefinitions = this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName()); // Check the set of scanned definitions for any further config classes and parse recursively if needed for (BeanDefinitionHolder holder : scannedBeanDefinitions) { BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition(); if (bdCand == null) { bdCand = holder.getBeanDefinition(); } if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) { //递归解析,所有的bean,如果有注解,会进一步解析注解中包含的bean parse(bdCand.getBeanClassName(), holder.getBeanName()); } } } } // Process any @Import annotations //递归解析,获取导入的配置类,很多情况下,导入的配置类中会同样包含导入类注解 processImports(configClass, sourceClass, getImports(sourceClass), true); // Process any @ImportResource annotations //解析@ImportResource配置类 AnnotationAttributes importResource = AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class); if (importResource != null) { String[] resources = importResource.getStringArray("locations"); Class readerClass = importResource.getClass("reader"); for (String resource : resources) { String resolvedResource = this.environment.resolveRequiredPlaceholders(resource); configClass.addImportedResource(resolvedResource, readerClass); } } // Process individual @Bean methods //处理@Bean注解修饰的类 Set beanMethods = retrieveBeanMethodMetadata(sourceClass); for (MethodMetadata methodMetadata : beanMethods) { configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass)); } // Process default methods on interfaces // 处理接口中的默认方法 processInterfaces(configClass, sourceClass); // Process superclass, if any //如果该类有父类,则继续返回,上层方法判断不为空,则继续递归执行 if (sourceClass.getMetadata().hasSuperClass()) { String superclass = sourceClass.getMetadata().getSuperClassName(); if (superclass != null && !superclass.startsWith("java") && !this.knownSuperclasses.containsKey(superclass)) { this.knownSuperclasses.put(superclass, configClass); // Superclass found, return its annotation metadata and recurse return sourceClass.getSuperClass(); } } // No superclass -> processing is complete return null; } 11、查看获取配置类的逻辑 processImports(configClass, sourceClass, getImports(sourceClass), true); /** * Returns {@code @Import} class, considering all meta-annotations. */ private Set getImports(SourceClass sourceClass) throws IOException { Set imports = new LinkedHashSet<>(); Set visited = new LinkedHashSet<>(); collectImports(sourceClass, imports, visited); return imports; } ------------------ /** * Recursively collect all declared {@code @Import} values. Unlike most * meta-annotations it is valid to have several {@code @Import}s declared with * different values; the usual process of returning values from the first * meta-annotation on a class is not sufficient. * For example, it is common for a {@code @Configuration} class to declare direct * {@code @Import}s in addition to meta-imports originating from an {@code @Enable} * annotation. * 看到所有的bean都以导入的方式被加载进去 */ private void collectImports(SourceClass sourceClass, Set imports, Set visited) throws IOException { if (visited.add(sourceClass)) { for (SourceClass annotation : sourceClass.getAnnotations()) { String annName = annotation.getMetadata().getClassName(); if (!annName.equals(Import.class.getName())) { collectImports(annotation, imports, visited); } } imports.addAll(sourceClass.getAnnotationAttributes(Import.class.getName(), "value")); } } 12、继续回到ConfigurationClassParser中的parse方法中的最后一行,继续跟进该方法: this.deferredImportSelectorHandler.process() ------------- public void process() { List deferredImports = this.deferredImportSelectors; this.deferredImportSelectors = null; try { if (deferredImports != null) { DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler(); deferredImports.sort(DEFERRED_IMPORT_COMPARATOR); deferredImports.forEach(handler::register); handler.processGroupImports(); } } finally { this.deferredImportSelectors = new ArrayList<>(); } } --------------- public void processGroupImports() { for (DeferredImportSelectorGrouping grouping : this.groupings.values()) { grouping.getImports().forEach(entry -> { ConfigurationClass configurationClass = this.configurationClasses.get( entry.getMetadata()); try { processImports(configurationClass, asSourceClass(configurationClass), asSourceClasses(entry.getImportClassName()), false); } catch (BeanDefinitionStoreException ex) { throw ex; } catch (Throwable ex) { throw new BeanDefinitionStoreException( "Failed to process import candidates for configuration class [" + configurationClass.getMetadata().getClassName() + "]", ex); } }); } } ------------ /** * Return the imports defined by the group. * @return each import with its associated configuration class */ public Iterable getImports() { for (DeferredImportSelectorHolder deferredImport : this.deferredImports) { this.group.process(deferredImport.getConfigurationClass().getMetadata(), deferredImport.getImportSelector()); } return this.group.selectImports(); } } ------------ public DeferredImportSelector getImportSelector() { return this.importSelector; } ------------ @Override public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) { Assert.state(deferredImportSelector instanceof AutoConfigurationImportSelector, () -> String.format("Only %s implementations are supported, got %s", AutoConfigurationImportSelector.class.getSimpleName(), deferredImportSelector.getClass().getName())); AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector) .getAutoConfigurationEntry(getAutoConfigurationMetadata(), annotationMetadata); this.autoConfigurationEntries.add(autoConfigurationEntry); for (String importClassName : autoConfigurationEntry.getConfigurations()) { this.entries.putIfAbsent(importClassName, annotationMetadata); } } 推荐学习:【5分钟背八股】Spring事务什么时候会失效? 你可能感兴趣的:(【5分钟背八股】SpringBoot自动装配原理是什么?) Java面试宝典(Spring篇) y_Haveme Spring面试题开发语言javaspring 目录1.什么是spring?2.Spring框架的优点。3.什么是IOC(控制反转)?4.依赖注入的方式。5.Autowired和Resource关键字的区别?6.什么是AOP(面向切面编程)?7.什么是通知呢?有哪些类型呢?8.springbean的生命周期。9.Spring支持的几种bean的作用域。10.Spring框架中都用到了哪些设计模式?11.事务三要素是什么?12.Spring事务实 无线瘦AP部署——Capwap隧道原理及故障:Capwap隧道常见问题-11.X版本 你可知这世上再难遇我 锐捷网络网络capwap隧道wlan 目录1、capwap隧道建立不成功2、AP和AC的隧道无法建立--AC查看拒绝原因3、AC无法下发配置给AP4、AP和AC跨公网上线,同一个网点的AP,部分可以上线成功,部分无法上线成功。【故障现象】5、AC、AP版本相同,但却无法在AC上正常上线,卡在join状态6、AP掉线后在ac上还是长时间显示在线7、大部分AP无法上线成功,且已经上线的AP经常出现掉线情况,隧道状态反复8、AP故障无法建立 新冠疫情数据分析项目实战 附完整项目代码 实验报告 计算机毕设论文 python之数据分析可视化数据分析数据挖掘python 题目要求1.标明你的数据来源:包括网址和首页截图2.数据分析和展示应包括:a)15天中,全球新冠疫情的总体变化趋势;b)累计确诊数排名前20的国家名称及其数量;c)15天中,每日新增确诊数累计排名前10个国家的每日新增确诊数据的曲线图;d)累计确诊人数占国家总人口比例最高的10个国家;e)死亡率(累计死亡人数/累计确诊人数)最低的10个国家;f)用饼图展示各个国家的累计确诊人数的比例(你爬取的所有 2025年AI免费大战:从DeepSeek到GPT-5的商业逻辑与行业变革 听吉米讲故事 人工智能gptdeepseek开源 引言:人工智能行业的2025年重大转折2025年伊始,人工智能行业的竞争格局发生了深刻变化,尤其是以DeepSeek为代表的新兴力量,通过低成本开源策略迅速崛起,迫使OpenAI、百度文心一言等人工智能巨头纷纷调整策略,甚至开放免费服务。这场"AI免费大战"不仅重新定义了人工智能行业的商业逻辑,也对企业的技术研发和商业化提出了全新的挑战。本文将从DeepSeek的低成本策略入手,剖析AI免费模式背 STM32:迎接汽车与AI时代MCU新挑战 EEPW电子产品世界 单片机stm32汽车 作为通用32位MCU市场最受关注的产品系列,意法半导体(ST)的STM32MCU从2007年问世之后就迎来爆发式增长,成功占据通用32位MCU市占率领头羊的位置,并且不断引领着通用MCU技术与应用的新思维开拓。本文引用地址:https://www.eepw.com.cn/article/202501/466521.htm新能源汽车带动汽车电子架构级革命和AI引领的边缘智能应用浪潮成为2024年最受 Centos7将/dev/mapper/centos-home磁盘空间转移到/dev/mapper/centos-root AnnyYoung 笔记FAQcentoslinux运维 1、查看存储df-h文件系统容量已用可用已用%挂载点devtmpfs126G0126G0%/devtmpfs126G0126G0%/dev/shmtmpfs126G19M126G1%/runtmpfs126G0126G0%/sys/fs/cgroup/dev/mapper/centos-root50G45G5.4G90%//dev/sda21014M187M828M19%/boot/dev/sda Go 语言的协程(goroutine) yymagicer gogolang算法 Go语言的协程(goroutine)是轻量级的并发机制,可以理解为Go中的线程,但它比线程更轻量,且由Go语言的运行时调度器管理。下面详细说明Go协程的原理、使用方法以及应用场景。1.协程原理Go协程(goroutine)在运行时由Go调度器管理,其运行时模型不同于传统的操作系统线程。Go的调度器采用M模型,即多个goroutine由少量的线程管理和调度。它依赖于两个关键组件:M(Machine) QT5实现简单的TCP通信 瑟寒凌风 QT开发 原文https://blog.csdn.net/u014695839/article/details/70041771/这段时间用到了QT的TCP通信,做了初步的学习与尝试,编写了一个客户端和服务器基于窗口通信的小例程。使用QT的网络套接字需要.pro文件中加入一句:QT+=network一、客户端的编写1、客户端的代码比服务器稍简单,总的来说,使用QT中的QTcpSocket类与服务器进行通信只 Topaz Video AI中文v6.0.4 免费版 sdddsada eclipse 链接:https://pan.quark.cn/s/d625eff6e20d软件特点更少的运动伪影其他视频放大技术通常会通过相邻帧中的不同处理产生“闪烁”或“闪烁”效果。TVAI显着减少了这些伪影。恢复视频细节从多个相邻帧中的附加信息中提取真实细节到您的视频中。获得更自然的结果传统的放大通常会导致伪影。我们通过从多个帧中获取新信息来缓解这些问题。受过视频训练专门针对视频剪辑而不是静止图像进行训练。 深究Spring中Bean的生命周期之面试宝典-百度面试题目(未弄懂) 是阿杜呀 面试javabean面试 转自:https://www.cnblogs.com/javazhiyin/p/10905294.html前言这其实是一道面试题,是我在面试百度的时候被问到的,当时没有答出来(因为自己真的很菜),后来在网上寻找答案,看到也是一头雾水,直到看到了《Springinaction》这本书,书上有对Bean声明周期的大致解释,但是没有代码分析,所以就自己上网寻找资料,一定要把这个Bean生命周期弄明白!网 git恢复被删除的远程分支 十八点四零 gitgitgithub 1、使用reflog,找到最后一次commitidgitreflog--date=iso2、找到目标分支最后一次的commitID298dax2HEAD@{2019-05-1315:35:18+0800}:test3、进行恢复gitcheckout-b分支名称298dax24、切出分支后,本地有分支了,再push到远程仓库就可以了gitpushorigin分支名称 Go语言学习路线(持续更新) 寅贝勒 Go核心知识学习golang Hey,我是寅贝勒,后端开发一枚,欢迎来我的个人网站www.ly-zone.cloud一起学习交流~说明博客分为两部分,第一部分为Go学习路线的思维导图,第二部分为思维导图对应的每个部分的讲解文章以及视频(持续更新)全文中Go语言的版本将会采用最新的1.19版本1、思维导图链接:https://www.processon.com/view/link/62e6331d1e0853070699f85f 探索外盘期货:主力连续合约与月份合约数据解析 level2Tick 外盘期货高频数据区块链人工智能大数据数据库金融python 探索外盘期货:主力连续合约与月份合约数据解析为了促进学习和研究,我们在此分享一部分匿名处理的外盘期货高频历史行情数据集。外盘期货分钟高频历史行情数据链接:https://pan.baidu.com/s/1vkCwoZhbk55MXF7o8724Xw?pwd=9tna提取码:9tna请注意,分享这些数据的目的是为了教育和研究,不构成任何投资建议。描述性统计分析通过对纽约期货高频合约历史行情数据的描述 deepseek与gpt,核心原理对比 test猿 gpt DeepSeek与GPT作为AI大模型,在自然语言处理等领域展现出强大的能力,它们的核心原理对比主要体现在模型架构、训练策略、资源效率以及应用场景优化等方面。一、模型架构DeepSeek混合专家(MoE)框架:DeepSeek采用了混合专家框架,其内部包含多个“专家”子模块,每个子模块专注于不同的任务或数据领域。例如,DeepSeek-R1拥有6710亿参数,但每次仅激活约370亿参数,通过动态选 Golang并发编程-协程goroutine初体验 锅锅来了 Golang实战案例golang开发语言goroutineWaitGroup案例 文章目录前言一、Goroutine适合的使用场景二、Goroutine的使用1.协程初体验三、WaitGroupWaitGroup案例一WaitGroup案例二总结前言学习Golang一段时间了,一直没有使用过goroutine来提高程序执行效率,在一些特殊场景下,还是有必须开启协程提升体验的,打算整理几篇关于协程的原理的文章和案例,结合工作场景将协程使用起来。一、Goroutine适合的使用场景 【Docker】Docker中卷的类型、区别及应用 阿猿收手吧! #Dockerdockereureka开发语言容器 文章目录引言1.Docker卷的基本概念2.Docker卷的类型2.1匿名卷(AnonymousVolume)2.2命名卷(NamedVolume)2.3绑定挂载(BindMount)2.4临时文件系统(tmpfsMount)3.Docker卷的区别3.1生命周期3.2数据存储位置3.3性能4.Docker卷的应用场景4.1数据持久化4.2数据共享4.3开发环境4.4临时数据存储5.总结引言在现代 java.lang.IllegalArgumentException: No view found for id 崩溃总结 GordonH1991 Android基础androidkotlinjava 出现崩溃项目在发布前测试测出一个偶现崩溃,起初因为无法复现,就直接带bug上线了,灰度后有少量的上报,评估后不影响放量,决定直接放开全量。第二天就收到了告警,线上出现了大量的相同的崩溃,崩溃堆栈如下:03-0620:34:50.2241379013790DAndroidRuntime:ShuttingdownVM03-0620:34:50.2251379013790EAndroidRuntime: 动手学深度学习V2.0(Pytorch)——25. 使用块的网络 VGG 吨吨不打野 动手学深度学习pytorch深度学习pytorch网络 文章目录P1讲解1.1基本介绍1.2总结P2代码实现2.1报错解决2.2windows下专用/共享GPU内存P3Q&AP4.其他4.1ImageNetClassificationLeaderboard4.2VGG其它讲解P1讲解1.1基本介绍视频地址:https://www.bilibili.com/video/BV1Ao4y117Pd教材文档:https://zh-v2.d2l.ai/chapt HTML语言的区块链 沈韡蕙 包罗万象golang开发语言后端 区块链技术的崛起与发展区块链是一种新兴的技术,它以其独特的去中心化、透明性和不可篡改性,正在全球范围内改变许多行业的游戏规则。在这篇文章中,我们将深入探讨区块链的基本概念、技术原理、应用场景以及未来的发展趋势。一、区块链的基本概念区块链,顾名思义,是一个由区块(Block)和链(Chain)组成的数据结构。每个区块中包含了一组交易记录,而这些区块通过加密算法和时间戳相互连接,形成一条连续的链条。这 C++-----------酒店客房管理系统 布鲁惠比寿 c++c++开发语言学习 酒店客房管理系统要求:1.客房信息管理:包括客房的编号、类型、价格、状态等信息的录入和修改;2.顾客信息管理:包括顾客的基本信息、预订信息等的管理;3.客房预订:客户可以根据需要进行客房的预订,系统会自动判断客房的可用情况;4.入住管理:客户入住时需要进行登记,同时系统会自动更改客房的状态信息;*5.结账管理:客户结账需要进行登记,同时系统会自动更改客房的状态信息;*6.统计报表:包括客房的使用情 【Python】解决PyTorch报错:PytorchStreamReader failed reading zip archive: failed finding central的解决方案 I'mAlex pythonpytorch开发语言 在使用PyTorch时,遇到“PytorchStreamReaderfailedreadingziparchive:failedfindingcentral”错误通常是由于损坏的模型文件或不兼容的文件版本导致的。这种问题在加载模型或数据时比较常见。以下是一些排查和解决该问题的步骤。博主简介:现任阿里巴巴嵌入式技术专家,15年工作经验,深耕嵌入式+人工智能领域,精通嵌入式领域开发、技术管理、简历招聘 Python实现简易DLNA投屏功能,局域网秒变家庭影院! 代码简单说 2025开发必备python开发语言DLNA投屏无线投屏python实现dlna投屏 欢迎关注『2025开发必备』专栏,专注于解决你在开发过程中遇到的各种问题,帮你快速找到解决方案,节省大量调试时间。内容持续更新中,保证每篇都值得收藏!Python实现简易DLNA投屏,局域网秒变家庭影院!一、前言前两天,我朋友问我,能不能用Python写一个DLNA投屏工具,能把视频从电脑推送到智能电视上播放。我一听,这不就是DLNA协议的基本应用吗?于是花了点时间,写了一个简易版的DLNA投屏脚 python 读取各类文件格式的文本信息:doc,html,mht,excel 北房有佳人 手写功能python读取doc文档python读取mhtpython读取excelpython读取html 引言众所周知,python最强大的地方在于,python社区汇总拥有丰富的第三方库,开源的特性,使得有越来越多的技术开发者来完善python的完美性。未来人工智能,大数据方向,区块链的识别和进阶都将以python为中心来展开。咳咳咳!好像有点打广告的嫌疑了。当前互联网信息共享时代,最重要的是什么?是数据。最有价值的是什么?是数据。最能直观体现技术水平的是什么?还是数据。所以,今天我们要分享的是:如 大模型参数高效微调(PEFT)技术解析及微调加速实践 AI产品经理 人工智能自然语言处理深度学习语言模型 2023年,大模型如雨后春笋般爆发,58同城TEG-AILab作为AI平台部门,紧跟大语言模型技术发展步伐,打造了大语言模型平台,支持大语言模型训练和推理部署,并基于大语言模型平台构建了58同城生活服务领域(房产、招聘、汽车、黄页)垂类大模型灵犀大语言模型(ChatLing),支撑了业务方大模型应用的探索落地。灵犀大语言模型在公开评测集和实际应用场景下,效果均优于开源通用大语言模型以及商用通用大语 机器学习入门-读书摘要 不像程序员的程序媛 机器学习人工智能 先看了《深度学习入门:基于python的理论和实践》这本电子书,早上因为入迷还坐过站了。。因为里面的反向传播和链式法则特别难懂,又网上搜了相关内容进行进一步理解,参考的以下文章(个人认为都讲的都非常好):https://zhuanlan.zhihu.com/p/65472471https://zhuanlan.zhihu.com/p/635438713https://zhuanlan.zhihu. 【教程4>第5章>第28节】基于帧同步+相位同步+位同步的QPSK调制解调通信系统整体性能分析 fpga和matlab #fpga开发帧同步+相位同步+位同步QPSK教程4 欢迎订阅FPGA/MATLAB/Simulink系列教程《★教程1:matlab入门100例》《★教程2:fpga入门100例》《★教程3:simulink入门60例》《★教程4:FPGA/MATLAB/Simulink联合开发入门与进阶X例》目录1.软件版本2.系统资源占用3.系统性能分析3.1信噪比设置3.2时偏设置3.3相位偏差设置4.总结 项目缺陷责任期是什么?如何保障项目质量? 项目管理 在软件开发和项目管理领域,项目缺陷责任期是一个至关重要的概念。它不仅关系到项目的质量保障,还直接影响到客户满意度和企业信誉。本文将深入探讨项目缺陷责任期的定义、重要性以及如何通过有效的质量管理来保障项目质量。项目缺陷责任期,通常指的是在项目交付后的一段时间内,开发团队需要对项目中出现的缺陷或问题负责并提供修复的期限。这个期限的长短往往取决于项目的复杂程度、合同约定以及行业惯例。在这个期间,如果发现 cocos creator从零开发2048(11)-游戏失败处理 cocos Canvas节点下新建空节点并重命名为panelFailed,挂载Widget组件并勾选Top、Right、Bottom、Left并把这些属性都设置为0,挂载BlockInputEvents组件。panelFailed节点下新建Sprite(单色)并重命名为bg,Size设置为500x500,Color设置为#43C1BE。panelFailed节点下新建Label(文字),PositionY设置 香港服务器里面说的CN2线路指的是什么? 网硕互联的小客服 服务器云计算运维linuxwindows CN2线路指的是中国电信的"中国电信下一代承载网"(ChinaTelecomNextCarrierNetwork,简称CN2)。这是中国电信专门为高质量网络传输设计的骨干网络,具有低延迟、高带宽的特点,主要用于国际通信、跨境数据传输等场景。在香港服务器的环境下,CN2线路通常指的是香港的服务器通过CN2专线与中国大陆进行网络连接。与传统中国电信的163骨干网相比,CN2线路在网络质量、稳定性和速度 C++栈内存管理:从原理到高性能编程实践 溟海. c++c++开发语言 以下是一篇关于C++栈机制的原创技术论文框架及内容,结合语言规范、编译器实现与工程实践,包含创新性分析和实验验证:---**C++栈内存管理:从原理到高性能编程实践****摘要**本文深入剖析C++栈内存的分配机制、生命周期管理及优化策略。通过反汇编分析GCC/Clang编译器实现,验证栈帧结构与函数调用约定,提出基于现代C++特性的栈使用优化方案。实验证明,合理控制栈空间可降低30%内存访问延迟 Spring中@Value注解,需要注意的地方 无量 springbean@Valuexml Spring 3以后,支持@Value注解的方式获取properties文件中的配置值,简化了读取配置文件的复杂操作 1、在applicationContext.xml文件(或引用文件中)中配置properties文件 <bean id="appProperty" class="org.springframework.beans.fac mongoDB 分片 开窍的石头 mongodb mongoDB的分片。要mongos查询数据时候 先查询configsvr看数据在那台shard上,configsvr上边放的是metar信息,指的是那条数据在那个片上。由此可以看出mongo在做分片的时候咱们至少要有一个configsvr,和两个以上的shard(片)信息。 第一步启动两台以上的mongo服务 &nb OVER(PARTITION BY)函数用法 0624chenhong oracle 这篇写得很好,引自 http://www.cnblogs.com/lanzi/archive/2010/10/26/1861338.html OVER(PARTITION BY)函数用法 2010年10月26日 OVER(PARTITION BY)函数介绍 开窗函数 &nb Android开发中,ADB server didn't ACK 解决方法 一炮送你回车库 Android开发 首先通知:凡是安装360、豌豆荚、腾讯管家的全部卸载,然后再尝试。 一直没搞明白这个问题咋出现的,但今天看到一个方法,搞定了!原来是豌豆荚占用了 5037 端口导致。 参见原文章:一个豌豆荚引发的血案——关于ADB server didn't ACK的问题 简单来讲,首先将Windows任务进程中的豌豆荚干掉,如果还是不行,再继续按下列步骤排查。 &nb canvas中的像素绘制问题 换个号韩国红果果 JavaScriptcanvas pixl的绘制,1.如果绘制点正处于相邻像素交叉线,绘制x像素的线宽,则从交叉线分别向前向后绘制x/2个像素,如果x/2是整数,则刚好填满x个像素,如果是小数,则先把整数格填满,再去绘制剩下的小数部分,绘制时,是将小数部分的颜色用来除以一个像素的宽度,颜色会变淡。所以要用整数坐标来画的话(即绘制点正处于相邻像素交叉线时),线宽必须是2的整数倍。否则会出现不饱满的像素。 2.如果绘制点为一个像素的 编码乱码问题 灵静志远 javajvmjsp编码 1、JVM中单个字符占用的字节长度跟编码方式有关,而默认编码方式又跟平台是一一对应的或说平台决定了默认字符编码方式;2、对于单个字符:ISO-8859-1单字节编码,GBK双字节编码,UTF-8三字节编码;因此中文平台(中文平台默认字符集编码GBK)下一个中文字符占2个字节,而英文平台(英文平台默认字符集编码Cp1252(类似于ISO-8859-1))。 3、getBytes()、getByte java 求几个月后的日期 darkranger calendargetinstance Date plandate = planDate.toDate(); SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd"); Calendar cal = Calendar.getInstance(); cal.setTime(plandate); // 取得三个月后时间 cal.add(Calendar.M 数据库设计的三大范式(通俗易懂) aijuans 数据库复习 关系数据库中的关系必须满足一定的要求。满足不同程度要求的为不同范式。数据库的设计范式是数据库设计所需要满足的规范。只有理解数据库的设计范式,才能设计出高效率、优雅的数据库,否则可能会设计出错误的数据库. 目前,主要有六种范式:第一范式、第二范式、第三范式、BC范式、第四范式和第五范式。满足最低要求的叫第一范式,简称1NF。在第一范式基础上进一步满足一些要求的为第二范式,简称2NF。其余依此类推。 想学工作流怎么入手 atongyeye jbpm 工作流在工作中变得越来越重要,很多朋友想学工作流却不知如何入手。 很多朋友习惯性的这看一点,那了解一点,既不系统,也容易半途而废。好比学武功,最好的办法是有一本武功秘籍。研究明白,则犹如打通任督二脉。 系统学习工作流,很重要的一本书《JBPM工作流开发指南》。 本人苦苦学习两个月,基本上可以解决大部分流程问题。整理一下学习思路,有兴趣的朋友可以参考下。 1 首先要 Context和SQLiteOpenHelper创建数据库 百合不是茶 androidContext创建数据库 一直以为安卓数据库的创建就是使用SQLiteOpenHelper创建,但是最近在android的一本书上看到了Context也可以创建数据库,下面我们一起分析这两种方式创建数据库的方式和区别,重点在SQLiteOpenHelper 一:SQLiteOpenHelper创建数据库: 1,SQLi 浅谈group by和distinct bijian1013 oracle数据库group bydistinct group by和distinct只了去重意义一样,但是group by应用范围更广泛些,如分组汇总或者从聚合函数里筛选数据等。 譬如:统计每id数并且只显示数大于3 select id ,count(id) from ta vi opertion 征客丶 macoprationvi 进入 command mode (命令行模式) 按 esc 键 再按 shift + 冒号 注:以下命令中 带 $ 【在命令行模式下进行】,不带 $ 【在非命令行模式下进行】 一、文件操作 1.1、强制退出不保存 $ q! 1.2、保存 $ w 1.3、保存并退出 $ wq 1.4、刷新或重新加载已打开的文件 $ e 二、光标移动 2.1、跳到指定行 数字 【Spark十四】深入Spark RDD第三部分RDD基本API bit1129 spark 对于K/V类型的RDD,如下操作是什么含义? val rdd = sc.parallelize(List(("A",3),("C",6),("A",1),("B",5)) rdd.reduceByKey(_+_).collect reduceByKey在这里的操作,是把 java类加载机制 BlueSkator java虚拟机 java类加载机制 1.java类加载器的树状结构 引导类加载器 ^ | 扩展类加载器 ^ | 系统类加载器 java使用代理模式来完成类加载,java的类加载器也有类似于继承的关系,引导类是最顶层的加载器,它是所有类的根加载器,它负责加载java核心库。当一个类加载器接到装载类到虚拟机的请求时,通常会代理给父类加载器,若已经是根加载器了,就自己完成加载。 虚拟机区分一个Cla 动态添加文本框 BreakingBad 文本框 <script> var num=1; function AddInput() { var str=""; str+="<input 读《研磨设计模式》-代码笔记-单例模式 bylijinnan java设计模式 声明: 本文只为方便我个人查阅和理解,详细的分析以及源代码请移步 原作者的博客http://chjavach.iteye.com/ public class Singleton { } /* * 懒汉模式。注意,getInstance如果在多线程环境中调用,需要加上synchronized,否则存在线程不安全问题 */ class LazySingleton iOS应用打包发布常见问题 chenhbc iosiOS发布iOS上传iOS打包 这个月公司安排我一个人做iOS客户端开发,由于急着用,我先发布一个版本,由于第一次发布iOS应用,期间出了不少问题,记录于此。 1、使用Application Loader 发布时报错:Communication error.please use diagnostic mode to check connectivity.you need to have outbound acc 工作流复杂拓扑结构处理新思路 comsci 设计模式工作算法企业应用OO 我们走的设计路线和国外的产品不太一样,不一样在哪里呢? 国外的流程的设计思路是通过事先定义一整套规则(类似XPDL)来约束和控制流程图的复杂度(我对国外的产品了解不够多,仅仅是在有限的了解程度上面提出这样的看法),从而避免在流程引擎中处理这些复杂的图的问题,而我们却没有通过事先定义这样的复杂的规则来约束和降低用户自定义流程图的灵活性,这样一来,在引擎和流程流转控制这一个层面就会遇到很 oracle 11g新特性Flashback data archive daizj oracle 1. 什么是flashback data archive Flashback data archive是oracle 11g中引入的一个新特性。Flashback archive是一个新的数据库对象,用于存储一个或多表的历史数据。Flashback archive是一个逻辑对象,概念上类似于表空间。实际上flashback archive可以看作是存储一个或多个表的所有事务变化的逻辑空间。 多叉树:2-3-4树 dieslrae 树 平衡树多叉树,每个节点最多有4个子节点和3个数据项,2,3,4的含义是指一个节点可能含有的子节点的个数,效率比红黑树稍差.一般不允许出现重复关键字值.2-3-4树有以下特征: 1、有一个数据项的节点总是有2个子节点(称为2-节点) 2、有两个数据项的节点总是有3个子节点(称为3-节 C语言学习七动态分配 malloc的使用 dcj3sjt126com clanguagemalloc /* 2013年3月15日15:16:24 malloc 就memory(内存) allocate(分配)的缩写 本程序没有实际含义,只是理解使用 */ # include <stdio.h> # include <malloc.h> int main(void) { int i = 5; //分配了4个字节 静态分配 int * p Objective-C编码规范[译] dcj3sjt126com 代码规范 原文链接 : The official raywenderlich.com Objective-C style guide 原文作者 : raywenderlich.com Team 译文出自 : raywenderlich.com Objective-C编码规范 译者 : Sam Lau 0.性能优化-目录 frank1234 性能优化 从今天开始笔者陆续发表一些性能测试相关的文章,主要是对自己前段时间学习的总结,由于水平有限,性能测试领域很深,本人理解的也比较浅,欢迎各位大咖批评指正。 主要内容包括: 一、性能测试指标 吞吐量、TPS、响应时间、负载、可扩展性、PV、思考时间 http://frank1234.iteye.com/blog/2180305 二、性能测试策略 生产环境相同 基准测试 预热等 htt Java父类取得子类传递的泛型参数Class类型 happyqing java泛型父类子类Class import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import org.junit.Test; abstract class BaseDao<T> { public void getType() { //Class<E> clazz = 跟我学SpringMVC目录汇总贴、PDF下载、源码下载 jinnianshilongnian springMVC ----广告-------------------------------------------------------------- 网站核心商详页开发 掌握Java技术,掌握并发/异步工具使用,熟悉spring、ibatis框架; 掌握数据库技术,表设计和索引优化,分库分表/读写分离; 了解缓存技术,熟练使用如Redis/Memcached等主流技术; 了解Ngin the HTTP rewrite module requires the PCRE library 流浪鱼 rewrite ./configure: error: the HTTP rewrite module requires the PCRE library. 模块依赖性Nginx需要依赖下面3个包 1. gzip 模块需要 zlib 库 ( 下载: http://www.zlib.net/ ) 2. rewrite 模块需要 pcre 库 ( 下载: http://www.pcre.org/ ) 3. s 第12章 Ajax(中) onestopweb Ajax index.html <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/ Optimize query with Query Stripping in Web Intelligence blueoxygen BO http://wiki.sdn.sap.com/wiki/display/BOBJ/Optimize+query+with+Query+Stripping+in+Web+Intelligence and a very straightfoward video http://www.sdn.sap.com/irj/scn/events?rid=/library/uuid/40ec3a0c-936 Java开发者写SQL时常犯的10个错误 tomcat_oracle javasql 1、不用PreparedStatements 有意思的是,在JDBC出现了许多年后的今天,这个错误依然出现在博客、论坛和邮件列表中,即便要记住和理解它是一件很简单的事。开发者不使用PreparedStatements的原因可能有如下几个: 他们对PreparedStatements不了解 他们认为使用PreparedStatements太慢了 他们认为写Prepar 世纪互联与结盟有感 阿尔萨斯 10月10日,世纪互联与(Foxcon)签约成立合资公司,有感。 全球电子制造业巨头(全球500强企业)与世纪互联共同看好IDC、云计算等业务在中国的增长空间,双方迅速果断出手,在资本层面上达成合作,此举体现了全球电子制造业巨头对世纪互联IDC业务的欣赏与信任,另一方面反映出世纪互联目前良好的运营状况与广阔的发展前景。 众所周知,精于电子产品制造(世界第一),对于世纪互联而言,能够与结盟 按字母分类: ABCDEFGHIJKLMNOPQRSTUVWXYZ其他