在IoC容器初始化过程中,一般不包含Bean依赖注入的实现。

依赖注入一般发生在应用第一次向容器获取Bean时(getBean),但是有一个例外。

在使用IoC容器时有一个预实例化的配置,即通过lazy-init属性控制Bean的实例化(依赖注入)时机。

一般情况

// <<AbstractBeanFactory>>
public Object getBean(String name) throws BeansException {
return this.doGetBean(name, (Class)null, (Object[])null, false);
} protected <T> T doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly) throws BeansException {
String beanName = this.transformedBeanName(name);
// 首先检查是否存在缓存的singleton bean,对于已经存在的不需要重复创建
Object sharedInstance = this.getSingleton(beanName);
Object bean;
if (sharedInstance != null && args == null) {
...
bean = this.getObjectForBeanInstance(sharedInstance, name, beanName, (RootBeanDefinition)null);
} else {
// 如果bean正在创建中则获取失败
if (this.isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
// 检查当前BeanFactory中是否存在以beanName为名的BeanDefinition
// 如果当前BeanFactory中没有,则会顺着其父BeanFactory查找
BeanFactory parentBeanFactory = this.getParentBeanFactory();
// 这里的containsBeanDefinition是一个模板方法,由DefaultListableBeanFactory实现
// 即在存储BeanDefinition的Map中查找是否存在
if (parentBeanFactory != null && !this.containsBeanDefinition(beanName)) {
String nameToLookup = this.originalBeanName(name);
if (parentBeanFactory instanceof AbstractBeanFactory) {
return ((AbstractBeanFactory)parentBeanFactory).doGetBean(nameToLookup, requiredType, args, typeCheckOnly);
}
if (args != null) {
return parentBeanFactory.getBean(nameToLookup, args);
}
if (requiredType != null) {
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
return parentBeanFactory.getBean(nameToLookup);
}
// 父BeanFactory为null,或者当前存在以beanName为名的BeanDefinition时
...
try {
// 根据beanName获取BeanFactory中的BeanDefinition
// 这里的RootBeanDefinition代表着在继承关系下创建的BeanDefinition
RootBeanDefinition mbd = this.getMergedLocalBeanDefinition(beanName);
this.checkMergedBeanDefinition(mbd, beanName, args);
// 获得当前Bean依赖的所有Bean,通过 depends-on="xxx" 属性指定
// 表示初始化当前Bean需要先初始化其依赖的xxx
String[] dependsOn = mbd.getDependsOn();
String[] var11;
if (dependsOn != null) {
var11 = dependsOn;
int var12 = dependsOn.length; for(int var13 = 0; var13 < var12; ++var13) {
String dep = var11[var13];
if (this.isDependent(beanName, dep)) {
... // throws "Circular depends-on relationship "
}
this.registerDependentBean(dep, beanName);
try {
// 递归,直到取到没有depends-on的Bean
this.getBean(dep);
} catch (NoSuchBeanDefinitionException var24) {
...
}
}
} // 创建bean实例
if (mbd.isSingleton()) { // 创建singleton作用域Bean实例
sharedInstance = this.getSingleton(beanName, () -> {
try {
// 进行 doCreateBean 方法,★
return this.createBean(beanName, mbd, args);
} catch (BeansException var5) {
this.destroySingleton(beanName);
throw var5;
}
});
bean = this.getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
} else if (mbd.isPrototype()) { // 创建prototype作用域Bean实例
var11 = null;
Object prototypeInstance;
try {
this.beforePrototypeCreation(beanName);
prototypeInstance = this.createBean(beanName, mbd, args);
} finally {
this.afterPrototypeCreation(beanName);
}
bean = this.getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
} else { // 创建其他作用域Bean:request、session、global session
String scopeName = mbd.getScope();
Scope scope = (Scope)this.scopes.get(scopeName);
if (scope == null) {
...
}
try {
Object scopedInstance = scope.get(beanName, () -> {
this.beforePrototypeCreation(beanName);
Object var4;
try {
var4 = this.createBean(beanName, mbd, args);
} finally {
this.afterPrototypeCreation(beanName);
}
return var4;
});
bean = this.getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}...
}
}...
} // 类型检查
if (requiredType != null && !requiredType.isInstance(bean)) {
try {
// 类型转换
T convertedBean = this.getTypeConverter().convertIfNecessary(bean, requiredType);
if (convertedBean == null) {
...
} else {
// 返回类型转换后的bean实例
return convertedBean;
}
}...
} else {
return bean;
}
}
// <AbstractAutowireCapableBeanFactory>
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
...logger
// 根据class属性或className解析beanClass
RootBeanDefinition mbdToUse = mbd;
Class<?> resolvedClass = this.resolveBeanClass(mbd, beanName, new Class[0]);
if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
mbdToUse = new RootBeanDefinition(mbd);
mbdToUse.setBeanClass(resolvedClass);
} // 对override属性(lookup-method、replace-method)进行处理
// 会检测当前beanDefinition的class中是否是否包含相应方法,
// 并将override方法标记为覆盖,防止进行重载参数检查
try {
mbdToUse.prepareMethodOverrides();
}... Object beanInstance;
try {
// 调用InstantiationAwareBeanPostProcessor
// 允许在实例化前后进行处理
// 如果返回值不为空,表示配置了InstantiationAwareBeanPostProcessor,并且修改了bean
// 则返回一个代理,而不是bean实例
beanInstance = this.resolveBeforeInstantiation(beanName, mbdToUse);
if (beanInstance != null) {
return beanInstance;
}
}... try {
// ★
beanInstance = this.doCreateBean(beanName, mbdToUse, args);
...
return beanInstance;
}...
} // 真正开始创建bean
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
BeanWrapper instanceWrapper = null;
// 如果是单例bean,则先清除缓存同名缓存
if (mbd.isSingleton()) {
instanceWrapper = (BeanWrapper)this.factoryBeanInstanceCache.remove(beanName);
}
// 创建bean实例★
if (instanceWrapper == null) {
instanceWrapper = this.createBeanInstance(beanName, mbd, args);
} Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
// 通过post-processors合并继承关系下的beanDefinition
synchronized(mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
this.applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}...
mbd.postProcessed = true;
}
}
// 提前曝光bean(利用缓存),用于支持循环bean的循环依赖
boolean earlySingletonExposure = mbd.isSingleton() && this.allowCircularReferences && this.isSingletonCurrentlyInCreation(beanName);
if (earlySingletonExposure) {
...
// 通过匿名内部类添加单例工厂到缓存
this.addSingletonFactory(beanName, () -> {
return this.getEarlyBeanReference(beanName, mbd, bean);
});
}
// 初始化bean
Object exposedObject = bean; try {
// 这里开始进行依赖注入★
this.populateBean(beanName, mbd, instanceWrapper);
// 【初始化bean】:
// applyBeanPostProcessorsBeforeInitialization【后置处理器】
// invokeInitMethods:执行init-method
// applyBeanPostProcessorsAfterInitialization【后置处理器】
exposedObject = this.initializeBean(beanName, exposedObject, mbd);
} catch (Throwable var18) {
if (var18 instanceof BeanCreationException && beanName.equals(((BeanCreationException)var18).getBeanName())) {
throw (BeanCreationException)var18;
}...
// 检查在提前曝光时,注入的bean是否为最终版本
if (earlySingletonExposure) {
Object earlySingletonReference = this.getSingleton(beanName, false);
if (earlySingletonReference != null) {
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
} else if (!this.allowRawInjectionDespiteWrapping && this.hasDependentBean(beanName)) {
String[] dependentBeans = this.getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet(dependentBeans.length);
String[] var12 = dependentBeans;
int var13 = dependentBeans.length; for(int var14 = 0; var14 < var13; ++var14) {
String dependentBean = var12[var14];
if (!this.removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
} if (!actualDependentBeans.isEmpty()) {
...
}
}
}
}
// 给Bean注册一些必要的销毁操作,当容器shutdown时执行
try {
this.registerDisposableBeanIfNecessary(beanName, bean, mbd);
// 返回Bean实例,这里已经完成了依赖注入
return exposedObject;
}...
} ---开始bean的实例化--- protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
// 确保Bean类可以实例化
Class<?> beanClass = this.resolveBeanClass(mbd, beanName, new Class[0]);
if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
...
} else {
// 5.0的新特性
// doc注释:用作创建Bean的回调,设置该回调后会覆盖掉创建Bean的工厂方法和构造函数,
// 但不影响依赖注入过程
Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
if (instanceSupplier != null) {
return this.obtainFromSupplier(instanceSupplier, beanName);
} else if (mbd.getFactoryMethodName() != null) { // 使用工厂方法实例化Bean
return this.instantiateUsingFactoryMethod(beanName, mbd, args);
} else {
// 创建Bean时需要根据beanClass解析构造方法,并缓存在RootBeanDefinition中
// 这里通过缓存直接进行处理,在创建相同Bean时不需要重复解析构造方法
boolean resolved = false;
boolean autowireNecessary = false;
if (args == null) {
synchronized(mbd.constructorArgumentLock) {
if (mbd.resolvedConstructorOrFactoryMethod != null) {
resolved = true;
autowireNecessary = mbd.constructorArgumentsResolved;
}
}
}
// 已解析构造方法
if (resolved) {
return autowireNecessary ? this.autowireConstructor(beanName, mbd, (Constructor[])null, (Object[])null) : this.instantiateBean(beanName, mbd);
} else {
// 使用构造函数实例化Bean
Constructor<?>[] ctors = this.determineConstructorsFromBeanPostProcessors(beanClass, beanName);
if (ctors == null && mbd.getResolvedAutowireMode() != 3 && !mbd.hasConstructorArgumentValues() && ObjectUtils.isEmpty(args)) {
ctors = mbd.getPreferredConstructors();
// 1 有参构造函数
// 2 默认构造函数:instantiateBean()通过getInstantiationStrategy().instantiate(mbd, beanName, this)
// 这里的策略是SimpleInstantiationStrategy
return ctors != null ? this.autowireConstructor(beanName, mbd, ctors, (Object[])null) : this.instantiateBean(beanName, mbd);
} else {
return this.autowireConstructor(beanName, mbd, ctors, args);
}
}
}
}
} // SimpleInstantiationStrategy
// 这里共有两种方式创建Bean:
// 其一,通过JVM反射;BeanUtils.instantiateClass(constructorToUse, new Object[0]);
// 其二,通过cgLib的动态代理机制;this.instantiateWithMethodInjection(bd, beanName, owner);<<CglibSubclassingInstantiationStrategy>> ---结束bean的实例化--- // 对bean属性包括依赖关系的处理,依据是BeanDefinition
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
if (bw == null) {
if (mbd.hasPropertyValues()) {
...
}
} else {
// 交由InstantiationAwareBeanPostProcessors处理是否对Bean实例进行依赖注入
boolean continueWithPropertyPopulation = true;
if (!mbd.isSynthetic() && this.hasInstantiationAwareBeanPostProcessors()) {
Iterator var5 = this.getBeanPostProcessors().iterator(); while(var5.hasNext()) {
BeanPostProcessor bp = (BeanPostProcessor)var5.next();
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor)bp;
if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
continueWithPropertyPopulation = false;
break;
}
}
}
} if (continueWithPropertyPopulation) {
PropertyValues pvs = mbd.hasPropertyValues() ? mbd.getPropertyValues() : null;
// 首先处理autowire依赖注入,根据Bean的名字或类型进行注入
// 我们可以在配置文件中指定注入方式:autowire="byName"
if (mbd.getResolvedAutowireMode() == 1 || mbd.getResolvedAutowireMode() == 2) {
MutablePropertyValues newPvs = new MutablePropertyValues((PropertyValues)pvs);
if (mbd.getResolvedAutowireMode() == 1) {
// 按变量名注入
this.autowireByName(beanName, mbd, bw, newPvs);
}
if (mbd.getResolvedAutowireMode() == 2) {
// 按类型注入
this.autowireByType(beanName, mbd, bw, newPvs);
}
pvs = newPvs;
} boolean hasInstAwareBpps = this.hasInstantiationAwareBeanPostProcessors();
boolean needsDepCheck = mbd.getDependencyCheck() != 0;
PropertyDescriptor[] filteredPds = null;
// 在为Bean注入依赖前进行后置处理,比如检查@Required是否满足,添加或移除Property
if (hasInstAwareBpps) {
if (pvs == null) {
pvs = mbd.getPropertyValues();
} Iterator var9 = this.getBeanPostProcessors().iterator(); while(var9.hasNext()) {
BeanPostProcessor bp = (BeanPostProcessor)var9.next();
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor)bp;
PropertyValues pvsToUse = ibp.postProcessProperties((PropertyValues)pvs, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
if (filteredPds == null) {
filteredPds = this.filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
} pvsToUse = ibp.postProcessPropertyValues((PropertyValues)pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
return;
}
} pvs = pvsToUse;
}
}
}
// 进行依赖检查
if (needsDepCheck) {
if (filteredPds == null) {
filteredPds = this.filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
} this.checkDependencies(beanName, mbd, filteredPds, (PropertyValues)pvs);
} if (pvs != null) {
// 对属性进行注入★
this.applyPropertyValues(beanName, mbd, bw, (PropertyValues)pvs);
} }
}
} protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
if (!pvs.isEmpty()) {
if (System.getSecurityManager() != null && bw instanceof BeanWrapperImpl) {
((BeanWrapperImpl)bw).setSecurityContext(this.getAccessControlContext());
}
// 注入的Property
MutablePropertyValues mpvs = null;
List original;
// pvs是MutablePropertyValues实例,且可强制类型转换,则可以直接设置为注入的Property
if (pvs instanceof MutablePropertyValues) {
mpvs = (MutablePropertyValues)pvs;
if (mpvs.isConverted()) {
try {
bw.setPropertyValues(mpvs);
return;
} catch (BeansException var18) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Error setting property values", var18);
}
} original = mpvs.getPropertyValueList();
} else {
original = Arrays.asList(pvs.getPropertyValues());
} TypeConverter converter = this.getCustomTypeConverter();
if (converter == null) {
converter = bw;
}
// BeanDefinitionValueResolver用于解析BeanDefinition中的Property
BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, (TypeConverter)converter);
// 创建一个深拷贝副本,这个副本持有的Property会被注入到Bean中
List<PropertyValue> deepCopy = new ArrayList(original.size());
boolean resolveNecessary = false;
Iterator var11 = original.iterator(); while(true) {
while(var11.hasNext()) {
PropertyValue pv = (PropertyValue)var11.next();
if (pv.isConverted()) {
deepCopy.add(pv);
} else {
String propertyName = pv.getName();
Object originalValue = pv.getValue();
// 利用valueResolver解析PropertyValue
// 对value的类型进行判断,然后解析,如果是依赖bean ref的话,会调用getBean方法
Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
Object convertedValue = resolvedValue;
boolean convertible = bw.isWritableProperty(propertyName) && !PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName);
if (convertible) {
convertedValue = this.convertForProperty(resolvedValue, propertyName, bw, (TypeConverter)converter);
} if (resolvedValue == originalValue) {
if (convertible) {
pv.setConvertedValue(convertedValue);
} deepCopy.add(pv);
} else if (convertible && originalValue instanceof TypedStringValue && !((TypedStringValue)originalValue).isDynamic() && !(convertedValue instanceof Collection) && !ObjectUtils.isArray(convertedValue)) {
pv.setConvertedValue(convertedValue);
deepCopy.add(pv);
} else {
resolveNecessary = true;
deepCopy.add(new PropertyValue(pv, convertedValue));
}
}
} if (mpvs != null && !resolveNecessary) {
mpvs.setConverted();
} try {
// BeanWrapper的setPropertyValues
// 将拷贝副本中的PropertyValues注入到Bean中<<PropertyAccessor>>
// 具体实现通过AbstractNestablePropertyAccessor.PropertyTokenHolder
// 然后根据tokens.keys处理本地值或键值
bw.setPropertyValues(new MutablePropertyValues(deepCopy));
return;
} catch (BeansException var19) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Error setting property values", var19);
}
}
}
}

lazy-init=false

会在容器初始化的过程中将所有的singleton bean提前进行实例化和依赖注入,因此singleton bean的依赖注入是容器初始化过程的一部分,这也是我们常用的ApplicationContext的默认配置。

对于非延迟单例bean的初始化在refresh()方法中的finishBeanFactoryInitialization(beanFactory)中完成。

    protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
...
beanFactory.preInstantiateSingletons(); // <<ConfigurableListableBeanFactory>>
}
// 具体实现:DefaultListableBeanFactory
public void preInstantiateSingletons() throws BeansException {
if (this.logger.isTraceEnabled()) {
this.logger.trace("Pre-instantiating singletons in " + this);
}
// 这里的beanDefinitionNames上一章有提过~
List<String> beanNames = new ArrayList(this.beanDefinitionNames);
Iterator var2 = beanNames.iterator(); while(true) {
String beanName;
Object bean;
do {
while(true) {
RootBeanDefinition bd;
do {
do {
do {
if (!var2.hasNext()) {
var2 = beanNames.iterator(); while(var2.hasNext()) {
beanName = (String)var2.next();
// ★
Object singletonInstance = this.getSingleton(beanName);
if (singletonInstance instanceof SmartInitializingSingleton) {
SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton)singletonInstance;
if (System.getSecurityManager() != null) {
AccessController.doPrivileged(() -> {
smartSingleton.afterSingletonsInstantiated();
return null;
}, this.getAccessControlContext());
} else {
smartSingleton.afterSingletonsInstantiated();
}
}
} return;
} beanName = (String)var2.next();
bd = this.getMergedLocalBeanDefinition(beanName);
} while(bd.isAbstract());
} while(!bd.isSingleton());
} while(bd.isLazyInit()); // 只会对非延迟单例bean进行初始化 if (this.isFactoryBean(beanName)) {
bean = this.getBean("&" + beanName);
break;
} this.getBean(beanName);
}
} while(!(bean instanceof FactoryBean)); FactoryBean<?> factory = (FactoryBean)bean;
boolean isEagerInit;
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
SmartFactoryBean var10000 = (SmartFactoryBean)factory;
((SmartFactoryBean)factory).getClass();
isEagerInit = (Boolean)AccessController.doPrivileged(var10000::isEagerInit, this.getAccessControlContext());
} else {
isEagerInit = factory instanceof SmartFactoryBean && ((SmartFactoryBean)factory).isEagerInit();
} if (isEagerInit) {
// 触发依赖注入
this.getBean(beanName);
}
}
} // DefaultSingletonBeanRegistry
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && this.isSingletonCurrentlyInCreation(beanName)) {
synchronized(this.singletonObjects) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
ObjectFactory<?> singletonFactory = (ObjectFactory)this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
} return singletonObject;
}

spring(四):DI流程的更多相关文章

  1. spring mvc处理流程概述

    大部分Java应用都是Web应用,展现层是Web应用不可忽略的重要环节.Spring为展现层提供了一个优秀的Web框架-Spring MVC.和众多其他Web框架一样,它基于MVC设计理念,此外,它采 ...

  2. Spring+IOC(DI)+AOP概念及优缺点

    Spring pring是一个轻量级的DI和AOP容器框架. 说它轻量级有一大部分原因是相对与EJB的(虽然本人从没有接触过EJB的应用),重要的是,Spring是非侵入式的,基于spring开发的应 ...

  3. Python第四天 流程控制 if else条件判断 for循环 while循环

    Python第四天   流程控制   if else条件判断   for循环 while循环 目录 Pycharm使用技巧(转载) Python第一天  安装  shell  文件 Python第二天 ...

  4. Spring MVC 编程流程步骤

    Spring MVC 编程流程步骤 1. 建立Maven工程 2. 添加Spring MVC依赖 <dependencies> <dependency> <groupId ...

  5. Excel VBA入门(四)流程控制2-循环控制

    所谓循环控制,即在循环执行一段代码,用于完成一些重复性任务. VBA中的循环控制语句主要有3种:for.while.loop.对于大多数人来说,for的使用频率最高,而我个人也觉得for是最为灵活的, ...

  6. 从prototype beandefinition 谈 spring 的关闭流程和 prototype 的特性

    背景介绍: 服务端期望使用 面向对象编程, 和 spring 结合的话只能是通过 prototype 的 bean 定义,并通过 getBean 获取. 优雅停机探究: 代码说明: 1. 类关系 Si ...

  7. 一文读懂Spring MVC执行流程

    说到Spring MVC执行流程,网上有很多这方面的文章介绍,但是都不太详细,作为一个初学者去读会有许多不理解的地方,今天这篇文章记录一下我学习Spring MVC的心得体会 话不多说,先上图:   ...

  8. Spring Boot启动流程分析

    引言 早在15年的时候就开始用spring boot进行开发了,然而一直就只是用用,并没有深入去了解spring boot是以什么原理怎样工作的,说来也惭愧.今天让我们从spring boot启动开始 ...

  9. spring四种依赖注入方式(转)

    spring四种依赖注入方式!! 平常的java开发中,程序员在某个类中需要依赖其它类的方法,则通常是new一个依赖类再调用类实例的方法,这种开发存在的问题是new的类实例不好统一管理,spring提 ...

  10. Java——一文读懂Spring MVC执行流程

    说到Spring MVC执行流程,网上有很多这方面的文章介绍,但是都不太详细,作为一个初学者去读会有许多不理解的地方,今天这篇文章记录一下我学习Spring MVC的心得体会 话不多说,先上图: Sp ...

随机推荐

  1. 使用Scanner类

    import java.util.Scanner;   public class HelloWorld {     public static void main(String[] args) {   ...

  2. 在javascript编程语言中,数据类型boolean的相关知识

    一. 1.字符串类型: 空字符串返回false,非空字符串均返回true; 2.数值类型: 0或NaN返回false,其他数值返回true; 3.布尔类型: false返回false,true返回tr ...

  3. WebApp开发-Zepto

    zepto.js自己去官网下载哈. DOM操作 $(document).ready(function(){ var $cr = $("<div class='cr'>插入的div ...

  4. openlayers图层加标注

    <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title&g ...

  5. js替换时,空格被替换为双引号

    替换代码 str.replace(/\"/g, "'") 将双引号替换为单引号,如果字符串中,存在space(空格)时,使用以上语句将会导致空格被替换为双引号,可以使用如 ...

  6. UVA10791-Minimum Sum LCM(唯一分解定理基本应用)

    原题:https://vjudge.net/problem/UVA-10791 基本思路:1.借助唯一分解定理分解数据.2.求和输出 知识点:1.筛法得素数 2.唯一分解定理模板代码 3.数论分析-唯 ...

  7. mybatis第二天02

    MyBatis第二天内容 1.mybatis的执行原理 通过: 1.全局配置文件SqlMapConfig.xml  映射文件mapper.xml 获取得到SqlSessinFactory工厂 2.由工 ...

  8. LeetCode 572. 另一个树的子树

    题目链接:https://leetcode-cn.com/problems/subtree-of-another-tree/ 给定两个非空二叉树 s 和 t,检验 s 中是否包含和 t 具有相同结构和 ...

  9. 问题 C: To Fill or Not to Fill

    #include <cstdio> #include <vector> #include <algorithm> #include <cmath> us ...

  10. 自定义Keras Layer

    Keras的Layer其实就是一个Class, 要具有以下几个方法: (1) build(input_shape): 定义权重的地方, 如果不需要定义权重, 也要有self.built = True; ...