spring(四):DI流程
在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流程的更多相关文章
- spring mvc处理流程概述
大部分Java应用都是Web应用,展现层是Web应用不可忽略的重要环节.Spring为展现层提供了一个优秀的Web框架-Spring MVC.和众多其他Web框架一样,它基于MVC设计理念,此外,它采 ...
- Spring+IOC(DI)+AOP概念及优缺点
Spring pring是一个轻量级的DI和AOP容器框架. 说它轻量级有一大部分原因是相对与EJB的(虽然本人从没有接触过EJB的应用),重要的是,Spring是非侵入式的,基于spring开发的应 ...
- Python第四天 流程控制 if else条件判断 for循环 while循环
Python第四天 流程控制 if else条件判断 for循环 while循环 目录 Pycharm使用技巧(转载) Python第一天 安装 shell 文件 Python第二天 ...
- Spring MVC 编程流程步骤
Spring MVC 编程流程步骤 1. 建立Maven工程 2. 添加Spring MVC依赖 <dependencies> <dependency> <groupId ...
- Excel VBA入门(四)流程控制2-循环控制
所谓循环控制,即在循环执行一段代码,用于完成一些重复性任务. VBA中的循环控制语句主要有3种:for.while.loop.对于大多数人来说,for的使用频率最高,而我个人也觉得for是最为灵活的, ...
- 从prototype beandefinition 谈 spring 的关闭流程和 prototype 的特性
背景介绍: 服务端期望使用 面向对象编程, 和 spring 结合的话只能是通过 prototype 的 bean 定义,并通过 getBean 获取. 优雅停机探究: 代码说明: 1. 类关系 Si ...
- 一文读懂Spring MVC执行流程
说到Spring MVC执行流程,网上有很多这方面的文章介绍,但是都不太详细,作为一个初学者去读会有许多不理解的地方,今天这篇文章记录一下我学习Spring MVC的心得体会 话不多说,先上图: ...
- Spring Boot启动流程分析
引言 早在15年的时候就开始用spring boot进行开发了,然而一直就只是用用,并没有深入去了解spring boot是以什么原理怎样工作的,说来也惭愧.今天让我们从spring boot启动开始 ...
- spring四种依赖注入方式(转)
spring四种依赖注入方式!! 平常的java开发中,程序员在某个类中需要依赖其它类的方法,则通常是new一个依赖类再调用类实例的方法,这种开发存在的问题是new的类实例不好统一管理,spring提 ...
- Java——一文读懂Spring MVC执行流程
说到Spring MVC执行流程,网上有很多这方面的文章介绍,但是都不太详细,作为一个初学者去读会有许多不理解的地方,今天这篇文章记录一下我学习Spring MVC的心得体会 话不多说,先上图: Sp ...
随机推荐
- 使用Scanner类
import java.util.Scanner; public class HelloWorld { public static void main(String[] args) { ...
- 在javascript编程语言中,数据类型boolean的相关知识
一. 1.字符串类型: 空字符串返回false,非空字符串均返回true; 2.数值类型: 0或NaN返回false,其他数值返回true; 3.布尔类型: false返回false,true返回tr ...
- WebApp开发-Zepto
zepto.js自己去官网下载哈. DOM操作 $(document).ready(function(){ var $cr = $("<div class='cr'>插入的div ...
- openlayers图层加标注
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title&g ...
- js替换时,空格被替换为双引号
替换代码 str.replace(/\"/g, "'") 将双引号替换为单引号,如果字符串中,存在space(空格)时,使用以上语句将会导致空格被替换为双引号,可以使用如 ...
- UVA10791-Minimum Sum LCM(唯一分解定理基本应用)
原题:https://vjudge.net/problem/UVA-10791 基本思路:1.借助唯一分解定理分解数据.2.求和输出 知识点:1.筛法得素数 2.唯一分解定理模板代码 3.数论分析-唯 ...
- mybatis第二天02
MyBatis第二天内容 1.mybatis的执行原理 通过: 1.全局配置文件SqlMapConfig.xml 映射文件mapper.xml 获取得到SqlSessinFactory工厂 2.由工 ...
- LeetCode 572. 另一个树的子树
题目链接:https://leetcode-cn.com/problems/subtree-of-another-tree/ 给定两个非空二叉树 s 和 t,检验 s 中是否包含和 t 具有相同结构和 ...
- 问题 C: To Fill or Not to Fill
#include <cstdio> #include <vector> #include <algorithm> #include <cmath> us ...
- 自定义Keras Layer
Keras的Layer其实就是一个Class, 要具有以下几个方法: (1) build(input_shape): 定义权重的地方, 如果不需要定义权重, 也要有self.built = True; ...