- 浏览: 3152 次
文章分类
最新评论
菜鸟的spring 3.0源码学习之旅(5)
今天天气大范围降温,或许对于南方还是阳春三月的气候,但是对于我们这里,就将要进入千里冰封万里雪飘的季节了,不仅如此,我柔弱的手机也禁不住这大范围的降温也因此进入了休眠状态
不过阵阵的寒意毅然挡不住我学习的热情,我下定决心,在我变身成为冰雕之前,一定要先把spring的源码搞懂,因为吧spring都搞懂了,春天还远吗
不瞎扯了,言归正传吧
昨天呢,我们讲述了XmlBeanFactory的字段实例化所发生的动作,那么今天呢,我们主要是讨论一下构造器里发生的一切,
首先,我们再看一下这个构造器
public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
super(parentBeanFactory);
this.reader.loadBeanDefinitions(resource); //加载BeanDefinitions信息
}
在这个构造器里,第一句的意思是说,吧parentBeanFactory交给父类的构造器来处理,
public AbstractAutowireCapableBeanFactory() {
super();
ignoreDependencyInterface(BeanNameAware.class);
ignoreDependencyInterface(BeanFactoryAware.class);
ignoreDependencyInterface(BeanClassLoaderAware.class);
}
public AbstractAutowireCapableBeanFactory(BeanFactory parentBeanFactory) {
this();
setParentBeanFactory(parentBeanFactory);
}
在这个构造器里,我们可以看到,构造器里实际上做了两个工作,一个是调用ignoreDependencyInterface,一个是调用了其父类的setParentBeanFactory,第一个工作实际上是往private final Set<Class> ignoredDependencyInterfaces = new HashSet<Class>();这个字段里设置添加参数,第二个呢,是吧这个入参设置到父类的私有字段里
不过呢,当这个类在实例化的同时,这个静态代码会先获得执行
private static Class javaxInjectProviderClass = null;
static {
ClassLoader cl = DefaultListableBeanFactory.class.getClassLoader();
try {
javaxInjectProviderClass = cl.loadClass("javax.inject.Provider");
}
catch (ClassNotFoundException ex) {
}
}
这个是为该字段动态的添加类实例信息,这个我到目前还没有发现有什么有用的地方,所以咱们暂时先忽略这个地方
XmlBeanFactory构造器里第一行代码就执行完了,那么我们就开始研究第二行代码吧
this.reader.loadBeanDefinitions(resource);
这个呢,是XmlBeanFactory的字段调用了loadBeanDefinition方法,那么,我们就欣赏一下这个方法的实现吧
org.springframework.beans.factory.xml.XmlBeanDefinitionReader#loadBeanDefinitions
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
return loadBeanDefinitions(new EncodedResource(resource));
}
这个方法的主要作用是吧Resource封装成EncodedResource类,这个EncodedResource类呢,有两个字段,一个是字符串类型的编码格式字段,另一个是Resource信息,这样大家应该就了解的差不多了吧,所以也不再赘述,我们然后再往下看
org.springframework.beans.factory.xml.XmlBeanDefinitionReader#loadBeanDefinitions
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
Assert.notNull(encodedResource, "EncodedResource must not be null");
if (logger.isInfoEnabled()) {
logger.info("Loading XML bean definitions from " + encodedResource.getResource());
}
Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
if (currentResources == null) { //如果变量为null,则实例化,并添加到本地线程中
currentResources = new HashSet<EncodedResource>(4);
this.resourcesCurrentlyBeingLoaded.set(currentResources);
}
if (!currentResources.add(encodedResource)) { //如果currentResources包含encodedResource,则抛出异常
throw new BeanDefinitionStoreException(
"Detected cyclic loading of " + encodedResource + " - check your import definitions!");
}
try {
InputStream inputStream = encodedResource.getResource().getInputStream();
try {
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
}
finally {
inputStream.close();
}
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(
"IOException parsing XML document from " + encodedResource.getResource(), ex);
}
finally {
currentResources.remove(encodedResource);
if (currentResources.isEmpty()) {
this.resourcesCurrentlyBeingLoaded.remove();
}
}
}
这个方法貌似比较复杂,不过我们别着急,看我耐着心给大家分析
Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
if (currentResources == null) { //如果变量为null,则实例化,并添加到本地线程中
currentResources = new HashSet<EncodedResource>(4);
this.resourcesCurrentlyBeingLoaded.set(currentResources);
}
if (!currentResources.add(encodedResource)) { //如果currentResources包含encodedResource,则抛出异常
throw new BeanDefinitionStoreException(
"Detected cyclic loading of " + encodedResource + " - check your import definitions!");
}
这个主要是往字段中添加资源,这个字段是用本地线程包装的,我们来看这个字段
private final ThreadLocal<Set<EncodedResource>> resourcesCurrentlyBeingLoaded =
new NamedThreadLocal<Set<EncodedResource>>("XML bean definition resources currently being loaded");
然后我让大家看下面的这个语句段
InputStream inputStream = encodedResource.getResource().getInputStream();
try {
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
}
finally {
inputStream.close();
}
InputSource是对要解析的XML文件的一个抽象,资源返回输出流,然后由InputSource实例化,如果资源的编码方式不为null,则设置其格式,然后将会执行doLoadBeanDefinitions方法
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
int validationMode = getValidationModeForResource(resource); //XSD
Document doc = this.documentLoader.loadDocument(
inputSource, getEntityResolver(), this.errorHandler, validationMode, isNamespaceAware());
return registerBeanDefinitions(doc, resource);
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (SAXParseException ex) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(),
"Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
}
catch (SAXException ex) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(),
"XML document from " + resource + " is invalid", ex);
}
catch (ParserConfigurationException ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"Parser configuration exception parsing XML from " + resource, ex);
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"IOException parsing XML document from " + resource, ex);
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"Unexpected exception parsing XML document from " + resource, ex);
}
}
这个是本类的doLoadBeanDefinitions方法,在这个方法里,主要是吧InputSource还有资源文件解析成Document,我想这个大家应该一目了然,也不需要多说,
int validationMode = getValidationModeForResource(resource);
在此方法中的这个字段是为了获得validationMode的值,在这里,此值默认为xsd,
getEntityResolver()此方法是为了实例化EntityResolver,
不过,在这个方法里,真正的重点是这个
Document doc = this.documentLoader.loadDocument(
inputSource, getEntityResolver(), this.errorHandler, validationMode, isNamespaceAware());
这个字段正是此方法的核心所在,那么我们看看loadDocument方法都进行了什么处理了
public Document loadDocument(InputSource inputSource, EntityResolver entityResolver,
ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception {
DocumentBuilderFactory factory = createDocumentBuilderFactory(validationMode, namespaceAware);//实例化此类,并且把验证方式设为dtd验证,支持名称空间
if (logger.isDebugEnabled()) {
logger.debug("Using JAXP provider [" + factory.getClass().getName() + "]");
}
DocumentBuilder builder = createDocumentBuilder(factory, entityResolver, errorHandler); //实例化该类,并且指定使用 EntityResolver 解析要解析的 XML 文档中存在的实体,使用指定解析器要使用的 ErrorHandler
return builder.parse(inputSource);
}
大家看了这个方法,我想都明白了吧,我也就不多说什么了,接着继续
当执行完doLoadBeanDefinitions以后,紧接着就要执行registerBeanDefinitions方法了
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader(); //实例化BeanDefinitionDocumentReader
int countBefore = getRegistry().getBeanDefinitionCount();
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
return getRegistry().getBeanDefinitionCount() - countBefore;
}
在这个方法里,将完成对Document的解析的工作,而这个方法的核心是这个字段
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
那么我们就主要看一下registerBeanDefinition方法吧
org.springframework.beans.factory.xml. DefaultBeanDefinitionDocumentReader#registerBeanDefinitions
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
this.readerContext = readerContext;
logger.debug("Loading bean definitions");
Element root = doc.getDocumentElement(); //获得根元素
BeanDefinitionParserDelegate delegate = createHelper(readerContext, root); //初始化bean中的信息
preProcessXml(root); //空方法
parseBeanDefinitions(root, delegate);
postProcessXml(root);
}
那么我们看看createHelper方法都定义了什么吧
protected BeanDefinitionParserDelegate createHelper(XmlReaderContext readerContext, Element root) {
BeanDefinitionParserDelegate delegate = new BeanDefinitionParserDelegate(readerContext);
delegate.initDefaults(root); //初始化bean中的属性
return delegate;
}
在这个方法里,它的核心是这个字段
delegate.initDefaults(root);
那么我们再看看initDefaults方法吧
public void initDefaults(Element root) {
populateDefaults(this.defaults, root);
this.readerContext.fireDefaultsRegistered(this.defaults); //尚不清楚作用
}
下面的这个方法主要对资源中的各个属性取出,设置到DocumentDefaultsDefinition中,
protected void populateDefaults(DocumentDefaultsDefinition defaults, Element root) {
defaults.setLazyInit(root.getAttribute(DEFAULT_LAZY_INIT_ATTRIBUTE));
defaults.setMerge(root.getAttribute(DEFAULT_MERGE_ATTRIBUTE));
defaults.setAutowire(root.getAttribute(DEFAULT_AUTOWIRE_ATTRIBUTE));
defaults.setDependencyCheck(root.getAttribute(DEFAULT_DEPENDENCY_CHECK_ATTRIBUTE));
if (root.hasAttribute(DEFAULT_AUTOWIRE_CANDIDATES_ATTRIBUTE)) {
defaults.setAutowireCandidates(root.getAttribute(DEFAULT_AUTOWIRE_CANDIDATES_ATTRIBUTE));
}
if (root.hasAttribute(DEFAULT_INIT_METHOD_ATTRIBUTE)) {
defaults.setInitMethod(root.getAttribute(DEFAULT_INIT_METHOD_ATTRIBUTE));
}
if (root.hasAttribute(DEFAULT_DESTROY_METHOD_ATTRIBUTE)) {
defaults.setDestroyMethod(root.getAttribute(DEFAULT_DESTROY_METHOD_ATTRIBUTE));
}
defaults.setSource(this.readerContext.extractSource(root)); //尚不清楚作用
}
好了,讲到这里,我就把XmlBeanFactory的实例化过程大体上给梳理了一遍,本人愚笨,用了两天的时间才把其中的缘由搞明白,我想大家都比我聪明,所以还应多请教为是
不过阵阵的寒意毅然挡不住我学习的热情,我下定决心,在我变身成为冰雕之前,一定要先把spring的源码搞懂,因为吧spring都搞懂了,春天还远吗
不瞎扯了,言归正传吧
昨天呢,我们讲述了XmlBeanFactory的字段实例化所发生的动作,那么今天呢,我们主要是讨论一下构造器里发生的一切,
首先,我们再看一下这个构造器
public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
super(parentBeanFactory);
this.reader.loadBeanDefinitions(resource); //加载BeanDefinitions信息
}
在这个构造器里,第一句的意思是说,吧parentBeanFactory交给父类的构造器来处理,
public AbstractAutowireCapableBeanFactory() {
super();
ignoreDependencyInterface(BeanNameAware.class);
ignoreDependencyInterface(BeanFactoryAware.class);
ignoreDependencyInterface(BeanClassLoaderAware.class);
}
public AbstractAutowireCapableBeanFactory(BeanFactory parentBeanFactory) {
this();
setParentBeanFactory(parentBeanFactory);
}
在这个构造器里,我们可以看到,构造器里实际上做了两个工作,一个是调用ignoreDependencyInterface,一个是调用了其父类的setParentBeanFactory,第一个工作实际上是往private final Set<Class> ignoredDependencyInterfaces = new HashSet<Class>();这个字段里设置添加参数,第二个呢,是吧这个入参设置到父类的私有字段里
不过呢,当这个类在实例化的同时,这个静态代码会先获得执行
private static Class javaxInjectProviderClass = null;
static {
ClassLoader cl = DefaultListableBeanFactory.class.getClassLoader();
try {
javaxInjectProviderClass = cl.loadClass("javax.inject.Provider");
}
catch (ClassNotFoundException ex) {
}
}
这个是为该字段动态的添加类实例信息,这个我到目前还没有发现有什么有用的地方,所以咱们暂时先忽略这个地方
XmlBeanFactory构造器里第一行代码就执行完了,那么我们就开始研究第二行代码吧
this.reader.loadBeanDefinitions(resource);
这个呢,是XmlBeanFactory的字段调用了loadBeanDefinition方法,那么,我们就欣赏一下这个方法的实现吧
org.springframework.beans.factory.xml.XmlBeanDefinitionReader#loadBeanDefinitions
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
return loadBeanDefinitions(new EncodedResource(resource));
}
这个方法的主要作用是吧Resource封装成EncodedResource类,这个EncodedResource类呢,有两个字段,一个是字符串类型的编码格式字段,另一个是Resource信息,这样大家应该就了解的差不多了吧,所以也不再赘述,我们然后再往下看
org.springframework.beans.factory.xml.XmlBeanDefinitionReader#loadBeanDefinitions
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
Assert.notNull(encodedResource, "EncodedResource must not be null");
if (logger.isInfoEnabled()) {
logger.info("Loading XML bean definitions from " + encodedResource.getResource());
}
Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
if (currentResources == null) { //如果变量为null,则实例化,并添加到本地线程中
currentResources = new HashSet<EncodedResource>(4);
this.resourcesCurrentlyBeingLoaded.set(currentResources);
}
if (!currentResources.add(encodedResource)) { //如果currentResources包含encodedResource,则抛出异常
throw new BeanDefinitionStoreException(
"Detected cyclic loading of " + encodedResource + " - check your import definitions!");
}
try {
InputStream inputStream = encodedResource.getResource().getInputStream();
try {
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
}
finally {
inputStream.close();
}
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(
"IOException parsing XML document from " + encodedResource.getResource(), ex);
}
finally {
currentResources.remove(encodedResource);
if (currentResources.isEmpty()) {
this.resourcesCurrentlyBeingLoaded.remove();
}
}
}
这个方法貌似比较复杂,不过我们别着急,看我耐着心给大家分析
Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
if (currentResources == null) { //如果变量为null,则实例化,并添加到本地线程中
currentResources = new HashSet<EncodedResource>(4);
this.resourcesCurrentlyBeingLoaded.set(currentResources);
}
if (!currentResources.add(encodedResource)) { //如果currentResources包含encodedResource,则抛出异常
throw new BeanDefinitionStoreException(
"Detected cyclic loading of " + encodedResource + " - check your import definitions!");
}
这个主要是往字段中添加资源,这个字段是用本地线程包装的,我们来看这个字段
private final ThreadLocal<Set<EncodedResource>> resourcesCurrentlyBeingLoaded =
new NamedThreadLocal<Set<EncodedResource>>("XML bean definition resources currently being loaded");
然后我让大家看下面的这个语句段
InputStream inputStream = encodedResource.getResource().getInputStream();
try {
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
}
finally {
inputStream.close();
}
InputSource是对要解析的XML文件的一个抽象,资源返回输出流,然后由InputSource实例化,如果资源的编码方式不为null,则设置其格式,然后将会执行doLoadBeanDefinitions方法
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
int validationMode = getValidationModeForResource(resource); //XSD
Document doc = this.documentLoader.loadDocument(
inputSource, getEntityResolver(), this.errorHandler, validationMode, isNamespaceAware());
return registerBeanDefinitions(doc, resource);
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (SAXParseException ex) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(),
"Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
}
catch (SAXException ex) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(),
"XML document from " + resource + " is invalid", ex);
}
catch (ParserConfigurationException ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"Parser configuration exception parsing XML from " + resource, ex);
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"IOException parsing XML document from " + resource, ex);
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"Unexpected exception parsing XML document from " + resource, ex);
}
}
这个是本类的doLoadBeanDefinitions方法,在这个方法里,主要是吧InputSource还有资源文件解析成Document,我想这个大家应该一目了然,也不需要多说,
int validationMode = getValidationModeForResource(resource);
在此方法中的这个字段是为了获得validationMode的值,在这里,此值默认为xsd,
getEntityResolver()此方法是为了实例化EntityResolver,
不过,在这个方法里,真正的重点是这个
Document doc = this.documentLoader.loadDocument(
inputSource, getEntityResolver(), this.errorHandler, validationMode, isNamespaceAware());
这个字段正是此方法的核心所在,那么我们看看loadDocument方法都进行了什么处理了
public Document loadDocument(InputSource inputSource, EntityResolver entityResolver,
ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception {
DocumentBuilderFactory factory = createDocumentBuilderFactory(validationMode, namespaceAware);//实例化此类,并且把验证方式设为dtd验证,支持名称空间
if (logger.isDebugEnabled()) {
logger.debug("Using JAXP provider [" + factory.getClass().getName() + "]");
}
DocumentBuilder builder = createDocumentBuilder(factory, entityResolver, errorHandler); //实例化该类,并且指定使用 EntityResolver 解析要解析的 XML 文档中存在的实体,使用指定解析器要使用的 ErrorHandler
return builder.parse(inputSource);
}
大家看了这个方法,我想都明白了吧,我也就不多说什么了,接着继续
当执行完doLoadBeanDefinitions以后,紧接着就要执行registerBeanDefinitions方法了
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader(); //实例化BeanDefinitionDocumentReader
int countBefore = getRegistry().getBeanDefinitionCount();
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
return getRegistry().getBeanDefinitionCount() - countBefore;
}
在这个方法里,将完成对Document的解析的工作,而这个方法的核心是这个字段
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
那么我们就主要看一下registerBeanDefinition方法吧
org.springframework.beans.factory.xml. DefaultBeanDefinitionDocumentReader#registerBeanDefinitions
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
this.readerContext = readerContext;
logger.debug("Loading bean definitions");
Element root = doc.getDocumentElement(); //获得根元素
BeanDefinitionParserDelegate delegate = createHelper(readerContext, root); //初始化bean中的信息
preProcessXml(root); //空方法
parseBeanDefinitions(root, delegate);
postProcessXml(root);
}
那么我们看看createHelper方法都定义了什么吧
protected BeanDefinitionParserDelegate createHelper(XmlReaderContext readerContext, Element root) {
BeanDefinitionParserDelegate delegate = new BeanDefinitionParserDelegate(readerContext);
delegate.initDefaults(root); //初始化bean中的属性
return delegate;
}
在这个方法里,它的核心是这个字段
delegate.initDefaults(root);
那么我们再看看initDefaults方法吧
public void initDefaults(Element root) {
populateDefaults(this.defaults, root);
this.readerContext.fireDefaultsRegistered(this.defaults); //尚不清楚作用
}
下面的这个方法主要对资源中的各个属性取出,设置到DocumentDefaultsDefinition中,
protected void populateDefaults(DocumentDefaultsDefinition defaults, Element root) {
defaults.setLazyInit(root.getAttribute(DEFAULT_LAZY_INIT_ATTRIBUTE));
defaults.setMerge(root.getAttribute(DEFAULT_MERGE_ATTRIBUTE));
defaults.setAutowire(root.getAttribute(DEFAULT_AUTOWIRE_ATTRIBUTE));
defaults.setDependencyCheck(root.getAttribute(DEFAULT_DEPENDENCY_CHECK_ATTRIBUTE));
if (root.hasAttribute(DEFAULT_AUTOWIRE_CANDIDATES_ATTRIBUTE)) {
defaults.setAutowireCandidates(root.getAttribute(DEFAULT_AUTOWIRE_CANDIDATES_ATTRIBUTE));
}
if (root.hasAttribute(DEFAULT_INIT_METHOD_ATTRIBUTE)) {
defaults.setInitMethod(root.getAttribute(DEFAULT_INIT_METHOD_ATTRIBUTE));
}
if (root.hasAttribute(DEFAULT_DESTROY_METHOD_ATTRIBUTE)) {
defaults.setDestroyMethod(root.getAttribute(DEFAULT_DESTROY_METHOD_ATTRIBUTE));
}
defaults.setSource(this.readerContext.extractSource(root)); //尚不清楚作用
}
好了,讲到这里,我就把XmlBeanFactory的实例化过程大体上给梳理了一遍,本人愚笨,用了两天的时间才把其中的缘由搞明白,我想大家都比我聪明,所以还应多请教为是
相关推荐
马士兵老师提供的讲解,对于菜鸟或者是刚学习javaweb和SSH框架的人来说可谓是福音,马老师讲的内容非常详细,同时还会灌输学者一些在实际工作和开发中的一些技巧,特别是代码规范和编程习惯是非常重要的,所以特意...
文档内容是 www.runoob.com 官网的离线html文件,便于离线学习菜鸟教程,一共有42和html对应42个学习模块
spring5源码学习
struts2+hibernate3.2+spring3.0实现简单的增删改查
NULL 博文链接:https://messon619.iteye.com/blog/1340760
34--[菜鸟闯关].zip源码scratch2.0 3.0编程项目源文件源码案例素材源代码34--[菜鸟闯关].zip源码scratch2.0 3.0编程项目源文件源码案例素材源代码34--[菜鸟闯关].zip源码scratch2.0 3.0编程项目源文件源码案例素材源...
python菜鸟3.0-终于清楚python菜鸟⼊门教程 Python是⼀款功能强⼤的脚本语⾔,具有丰富和强⼤的库,重要的是,它还具有很强的可读性,易⽤易学,⾮常适合编程初学者⼊门。以 下是⼩编为你整理的python菜鸟⼊门教程 ...
spring菜鸟入门,spring入门,spring新手实例,spring教程
springcloud简单项目搭建,菜鸟学习Spring Cloud集成相关优质项目推荐 这些项目是Spring Cloud官方项目或是对Spring Cloud进行了有益的补充以及基于Spring Cloud最佳实践。
spring mvc+mybatis+redis 整合,分布式框架
5、templates_c smarty自动生成的文件 6、JS 常用的JS(当时顺手放的) 7、other 乱78遭的东西,以前学HTML时做的 8、html 生成的HTML文件自动放此处 主要文件 说明: controller 文件夹中 usercontroller.php ...
易语言源码易语言菜鸟背包游戏源码.rar 易语言源码易语言菜鸟背包游戏源码.rar 易语言源码易语言菜鸟背包游戏源码.rar 易语言源码易语言菜鸟背包游戏源码.rar 易语言源码易语言菜鸟背包游戏源码.rar 易语言源码...
您不需要任何Linux技能也能阅读本教程,Linux菜鸟过关全面解决您的Linux之旅问题。您现在要做的是了解一些Linux知识与安装方法,按照本教程的顺序阅读即可。本教程可以作为您短期突破Linux安装的教材,这一切都不...
菜鸟窝企业项目课程《菜鸟商城》的源码
51菜鸟到arm高手51菜鸟到arm高手51菜鸟到arm高手51菜鸟到arm高手51菜鸟到arm高手51菜鸟到arm高手51菜鸟到arm高手51菜鸟到arm高手
对于spring源码的深度解析,适合菜鸟向中级进阶的时候看看
仿菜鸟商城系统(源码),用于学习,请勿作商用,否则将追究法律责任。
本书适合as3.0菜鸟级别学习,高手就不用了
jar包:项目中除了使用了struts2,hibernate3.0和spring1.8以外(用spring2.0的包也可以.不能低于1.8的包.)还是用了junit,ajax,第三方的table组件.等等.所以需要下载相对应的包. 为了上传jar.我专门申请了一个网盘.所有...
菜鸟新闻完整源码