第2章 ◄Spring基础►

​ 在上一章节中,我们学习了Java的注解与反射,在这一章节我们将了解一下Spring框架,并学习Spring框架中重要的编程思想控制反转(IOC)、面向切面编程(AOP)。语言只是工具,最重要的是编程思想。掌握了编程思想,不仅是Java,其他编程语言也就容易学习了。
本章主要涉及的知识点:

​ ● Spring概述:了解Spring框架的起源、简介、结构。
​ ● 依赖注入:什么是依赖注入?依赖注入的好处是什么?
​ ● 控制反转:什么是控制反转?依赖注入与控制反转的联系是什么?
​ ● 面向切面编程:什么是面向切面编程?面向切面编程的原理。
​ ● 实例应用:通过本章IOC、AOP示例,演示Spring中IOC、AOP的简单应用,通过动手实践加深对IOC、AOP的理解。

2.1 Spring框架介绍

​ 本节主要对Spring框架进行简单介绍,了解框架起源、框架组成结构,对Spring框架有一个大概的认识。官网地址:https://spring.io/

2.1.1 起源

​ 首先,追根溯源,了解它是怎么来的。在Spring框架出现之前,使用EJB开发J2EE应用可没那么容易。EJB要严格地实现各种不同类型的接口,代码复用性低,配置也比较复杂和单调,同样使用JNDI进行对象查找的代码也是单调而枯燥,而且EJB不容易学,开发效率低。Spring出现的初衷就是为了解决类似的这些问题。

​ Spring最大的目的之一就是使J2EE开发更加容易。同时,Spring不仅仅是一个单层的框架,而是类似一个平台或者生态体系。在这个平台或者生态体系中,可以将Struts、Hibernate等单层框架最佳的方式融合在一起,为企业级应用提供完美的解决方案。Spring的形成,最初来自Rod Jahnson所著的一本很有影响力的图书《Expert One-on-One J2EE Design and Development》(出版于2002年),就是在这本书中第一次出现了Spring的一些核心思想。另外,《Expert One-on-One J2EE Development without EJB》更进一步地阐述了在不使用EJB开发J2EE企业级应用的一些设计思想和具体的做法。

2.1.2 简介

​ 了解了Spring框架的起源之后,下面来了解一下Spring到底是什么。用一句话概括,Spring就是一个开源的轻量级的控制反转(IoC)和面向切面(AOP)的容器框架。下面来分析一下这句话。

  • (1)开源:因为开源、免费,用户无须经过任何人同意即可修改代码,可控制性强,不受他人限制。
  • (2)轻量级:从大小与开销两方面而言,Spring都是轻量的。完整的Spring框架可以在一个大小只有1MB多的JAR文件里发布,并且Spring所需的处理开销也是微不足道的。此外,Spring是非侵入式的,Spring应用中的对象不依赖于Spring的特定类。
  • (3)控制反转:软件设计中通常用耦合度和内聚度作为衡量模块独立程度的标准,划分模块的一个准则就是高内聚低耦合,Spring通过控制反转技术降低了耦合度。
  • (4)面向切片:Spring支持面向切片的编程,允许通过分离应用的业务逻辑与系统级服务进行内聚性的开发,应用对象只需实现业务逻辑,它们并不负责(甚至是意识)其他系统级关注点,例如日志或事务支持。
  • (5)容器:容器就是用来装东西的。Spring容器包含并管理应用对象的配置和生命周期。
  • (6)框架:Spring可以将简单的组件配置、组合成为复杂的应用,相当于是一个脚手架,开发者要做的就是把组件放进去,实现业务逻辑。

2.1.3 框架结构

Spring框架结构如图2-1所示。

​ Spring由20多个模块组成,可以分为核心容器(Core Container)、数据访问/集成(Data Access/Integration)、Web、面向切面编程(AOP,Aspect Oriented Programming)、设备(Instrumentation)、消息发送(Messaging)和测试(Test)。

1.核心容器

​ 核心容器包含spring-core、spring-beans、spring-context、spring-context-support和spring-expression(Spring Expression Language)这些模块。
​ spring-core和spring-beans构成了框架最基础的部分,包括控制反转和依赖注入功能。
​ spring-context是基于spring-core和spring-beans构建的,提供了一种以框架风格来访问对象的方式,类似于JNDI注册。ApplicationContext接口是spring-context的焦点。
​ spring-context-support为集成第三方库(如定时器Quartz)提供支持。
​ spring-expression提供了一种强大的表达式语言,可以在运行时查询和操作对象。

2.AOP

​ spring-aop模块提供了一个AOP面向切面编程的实现。
​ spring-aspects模块提供与AspectJ的集成。
​ spring-instrument模块提供一些类级的工具支持和ClassLoader级的实现,用于服务器。spring-instrument-tomcat模块针对tomcat的instrument实现。

3.消息发送

​ 从Spring 4开始包含了一个spring-messaging模块,对Spring集成项目Message、MessageChannel和MessageHandler进行了重要的抽象,是基于消息发送应用的基础。

4.数据访问/集成

​ 数据访问/集成层包含JDBC(spring-jdbc)、ORM(spring-orm)、OXM(spring-oxm)、JMS(spring-jms)和事务(spring-tx)模块。
5.Web
​ Web层包含spring-web、spring-webmvc、spring-websocket和spring-webflux模块。其中,spring-web提供了面向Web集成的基本特性,比如文件上传功能。Spring-webmvc模块包含了Spring的MVC和REST Web Service实现。spring-webflux是一个新的非堵塞函数式Reactive Web框架,可以用来建立异步的、非阻塞、事件驱动的服务,并且扩展性非常好。

6.测试

​ Spring-test模块支持Spring组建JUnit和TestNG的单元测试和集成测试。

2.2 依赖注入DI与控制反转IOC

​ 本节主要介绍依赖注入与控制反转的基本概念,理解什么是依赖注入、什么是控制反转。在此基础上通过示例动手操作加深理解。

维基百科对“依赖反转”相关概念的叙述
早在2004年,Martin Fowler就提出了“哪些方面的控制被反转了?”这个问题。他得出的结论是:依赖对象的获得被反转了。基于这个结论,他为控制反转创造了一个更好的名字:依赖注入。许多非凡的应用(比HelloWorld.java更加优美、更加复杂)都是由两个或多个类通过彼此的合作来实现业务逻辑的,这使得每个对象都需要与其合作的对象(也就是它所依赖的对象)的引用。如果这个获取过程要靠自身实现,那么如你所见,这将导致代码高度耦合并且难以测试。

2.2.1 什么是依赖注入

​ 从汉字的字面意思理解,可以把“依赖注入”分为两个词,一个是“依赖”,一个是“注入”。那什么是依赖、什么是注入呢?依赖是依靠别人或事物而不能自立或自给,通俗的理解就是,不是自身的,但没有就活不下去,比如人没有了空气、水、阳光,那就活不下去,所以人依赖空气、水、阳光。注入是之前内部没有通过外部灌入的。
​ 上面是从字面意思理解了一下依赖注入,接着从编程的角度分析一下。依赖注入是组件之间依赖关系由容器在运行期决定的,即由容器动态地将某个依赖关系注入到组件之中。依赖注入的目的并非为软件系统带来更多功能,而是为了解耦,提升组件重用的频率,并为系统搭建一个灵活、可扩展的平台。通过依赖注入机制,我们只需要通过简单的配置,而无须任何代码就可以指定目标需要的资源,完成自身的业务逻辑,不需要关心具体的资源来自何处、由谁实现。

​ ● 依赖注入是组件之间依赖关系由容器在运行期决定的,即由容器动态地将某个依赖关系注入到组件之中。这句话总结依赖注入的核心原理,比如分别把人(Person)和空气(Air)都当作一个组件(类),人依赖空气,那么这个依赖关系不是人和空气两个组件关联的,需要一个容器决定,而且不是一开始就决定的,是运行期决定的。
​ ● 依赖注入的目的并非为软件系统带来更多功能,而是为了解耦,提升组件重用的频率,并为系统搭建一个灵活、可扩展的平台。这句话是使用依赖注入的目的。使用依赖注入可以进一步解耦,也是软件设计中高内聚低耦合的体现。
​ ● 通过依赖注入机制,我们只需要通过简单的配置,而无须任何代码就可以指定目标需要的资源,完成自身的业务逻辑,不需要关心具体的资源来自何处、由谁实现。这句话是实现依赖注入的方法,通过简单配置就能实现依赖注入。

​ 理解DI的关键是:“谁依赖谁,为什么需要依赖,谁注入谁,注入了什么”,接着使用人和空气来深入分析一下:
​ ● 谁依赖谁:人依赖空气。
​ ● 为什么需要依赖:人需要空气,没有空气,人就不存在,就是一个空对象。
​ ● 谁注入谁:人通过容器注入空气。
​ ● 注入了什么:注入了人所需要的空气。

2.2.2 什么是控制反转

​ 与依赖注入一样,我们还是先从字面意思理解一下控制反转。它也可以分为两个词,一个是“控制”,一个是“反转”。那什么是控制,什么又是反转呢?

​ ● 控制:为掌握住对象不使任意活动或超出范围;或使其按控制者的意愿活动。
​ ● 反转:向相反的方向转动。

​ 上面是从中文字面对控制反转的理解,下面从编程的角度分析一下。IOC意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制。理解IOC的关键是:“谁控制谁,控制什么,为何是反转(有反转就应该有正转了),哪些方面反转了”。我们接着使用人和空气来深入分析一下:
​ ● 谁控制谁,控制什么:以往我们是通过new关键字来创建对象的,比如人(Person)依赖空气(Air),在Person中如果要使用Air对象,就需要通过New关键字来主动创建,在IOC中有一个专门的容器来创建这些对象,即由IOC容器来控制对象的创建。

  • 谁控制谁?当然是IOC容器控制对象了。
    
    •  控制什么?主要控制了外部资源获取(不只是对象,还包括文件等)。
      
    •  为何是反转,哪些方面反转了:有反转就有正转,正转就是我们通过New主动获取依赖对象;反转则是由容器来帮忙创建及注入依赖对象。
      
    •  为何是反转?因为由容器帮我们查找及注入依赖对象,对象只是被动地接受依赖对象,所以是反转。
      
    •  哪些方面反转了?依赖对象的获取被反转了。Air对象通过容器注入给Person对象。
      

2.2.3 依赖注入的优缺点

​ 可能有人会纳闷为什么只介绍使用依赖注入的优缺点,那控制反转就没有优缺点吗?其实它们是同一个概念的不同角度描述,由于控制反转概念比较含糊(可能只是理解为容器控制对象这一个层面,很难让人想到谁来维护对象关系),所以2004年大师级人物Martin Fowler又给出了一个新的名字:“依赖注入”。相对IOC而言,“依赖注入”明确描述了“被注入对象依赖IOC容器配置依赖对象”。
​ 俗话说,每个硬币都有两面。同样,IOC也是有优点和缺点的。

  • 优点,也是使用依赖注入的目的:实现组件之间的解耦,提高程序的灵活性和可维护性,提升组件重用的频率,并为系统搭建一个灵活、可扩展的平台。

  • 缺点也是存在的。一是它创建对象的方式变复杂了。二是因为使用反射来创建对象,所以在效率上会有些损耗。但相对于程序的灵活性和可维护性来说,这点损耗是微不足道的。三是使用XML进行配置时太复杂,一旦类有改变,XML就需要改变。有了注解之后,与使用XML进行配置相比简单很多。

2.2.4 IOC实例

光说不练假把式,特别是IT技术,经常会出现看能看懂但写不出来的尴尬局面。上面分析了一下依赖注入与控制反转,本节将通过示例来加深理解。这里还是使用人与空气的例子。
人依赖空气,在传统的方式创建两个类:一个是Person类,一个是CleanAir类。

class CleanAir{public  String toString(){return "CleanAir";}
}class Person{CleanAir air;public Person(CleanAir air){this.air = air;}public  String toString(){return "Person";}public void breath(){System.out.println(air.toString());}
}

​ 上面两个类实现了依赖的关系,还有就是注入。在了解注入之前,我们还有一个问题要思考。有这样一句话:世界上唯一不变的就是变化。之前干净的空气不复存在,而Person依赖的不再是CleanAir,而是比CleanAir更有内涵的DirtyAir。如果还是按照上面的方式来,那就需要在增加一个DirtyAir类的同时修改Person。这种强依赖有很大的弊端,一个地方变化引起其他地方变化,而且改变的只是Air,但Person也要改变。怎么样才能尽量减少修改的地方呢?于是面向接口的编程出现了。下面先定义一个接口IAir,类CleanAir实现接口IAir,在Person中不再直接依赖CleanAir,而是依赖接口IAir,这样即使是DirtyAir也只需要给Person修改不同的Air就行了。这个注入的过程,利用Spring框架只需要改一下配置即可实现。

interface IAir {}class CleanAir implements IAir{public  String toString(){return "CleanAir";}
}class DirtyAir implements IAir{public  String toString(){return "DirtyAir";}
}class Person{IAir air;public Person(IAir air){this.air = air;}public  String toString(){return "Person";}public void breath(){System.out.println(air.toString());}
}

​ 上面定义IAir接口算是对依赖关系的优化,降低了人与空气的耦合度,但是并没有使用New关键字创建对象,只是定义了依赖关系。下面用Spring实现注入。

  • (1)创建一个Maven Project,archetype选择quickstart,如图2-2所示。

图2-2

  • (2)创建之后,既然要使用Spring框架来实现注入,那肯定要在项目中引入Spring框架,配置pom.xml,添加依赖。
    ① 在properties节点配置要引入Spring的版本号,这里用的是5.0.0.RELEASE。
  <properties><spring.version>5.0.0.RELEASE</spring.version></properties>

② 引入。

 <dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-core</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>${spring.version}</version></dependency></dependencies>
  • (3)实现依赖注入。

    前面创建的IAir接口、Person类、CleanAir类、DirtyAir类实现了依赖关系,但是怎么让Spring框架识别到呢?不可能把各个类创建好就结束了,还需要进行配置才能让Spring知道哪些是组件。这里对Person类、CleanAir类、DirtyAir类在上面定义的基础上进行修改。

public interface IAir {
}@Component
public class CleanAir implements IAir {public  String toString(){return "CleanAir";}
}@Component
public class DirtyAir implements IAir {public  String toString(){return "DirtyAir";}
}@Component
public class Person {IAir air;@Autowired //对构造函数进行标注public Person(@Qualifier("dirtyair") IAir air){this.air = air;}public  String toString(){return "Person";}public void breath(){System.out.println(air.toString());}
}

​ 在上面的代码中使用了@Component将类注解成组件,使用@Autowired将IAir类型对象注入Person中。CleanAir类、DirtyAir类都实现了IAir接口,怎么让Person具体注入哪个对象呢?使用@Qualifier关键字来进行区分,这里使用的是qualifier=dirtyair。同时这些组件定义之后还要告诉Spring框架组件位置在哪,所以在scr/main/resources下新建了ApplicationContext.xml进行配置。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd"><context:component-scan base-package="spring.tutorial.chapter2.*" /><bean id="CleanAir" class="spring.tutorial.chapter2.air.impl.CleanAir"><qualifier value="cleanair"/></bean><bean id="DirtyAir" class="spring.tutorial.chapter2.air.impl.DirtyAir"><qualifier value="dirtyair"/></bean><bean id="person" class="spring.tutorial.chapter2.Person" />
</beans>
  • (4)测试。
    在main中获取到应用上下文,通过getBean方法获取Person对象,然后调用Breath()方法。不了解ClassPathXmlApplicationContext、getBean这些方法也没关系,在后面的章节会有详细介绍。
public class Chapter1
{public static void main( String[] args ){ApplicationContext context = new ClassPathXmlApplicationContext(new  String[] {"ApplicationContext.xml"});BeanFactory factory = context;Person person = (Person) factory.getBean("person");person.breath();}
}

输出结果:

DirtyAir

​ 如果想使用CleanAir对象,只需要把Person类中@Qualifier注解value的值改为CleanAir对应的beanId:cleanair。

  • (5)小结
    参考上面的示例思考2.2.1和2.2.2节中的概念,就会发现依赖注入、控制反转其实也不难。理解了依赖注入、控制反转对后面Spring框架的学习会有更大的帮助。

2.3 面向切面编程

​ 本节主要认识横切、纵切,理解什么是AOP(Aspect-Oriented Programming,面向切面编程)以及AOP的实现原理。在此基础上通过示例动手操作加深理解。

2.3.1 认识横切和纵切

​ 首先认识一下什么是横切、纵切,这就要利用生物方面的知识了。切面的方向是这样规定的:拿植物的茎举例,纵切就是沿长轴来切,横切即是垂直与纵切的切法。编程相对来说是比较抽象的,有时候我们通过身边的事物来将抽象的具体化,这样也能更容易理解。
​ 利用百度搜索“横切”,“纵切”时,首先搜出来的结果是剖宫产的结果,内容是这样描述的:“由于人体和血管、神经系统等都是纵向的走向,所以纵切更有利于皮肤和伤口的愈合,通常在1年到2年就可以彻底恢复。但纵切的缺点是伤口较大,会留下明显的疤痕,会影响美观。横切的方法出血较少,并且出现伤口感染的机率要低于纵切,所以安全性比纵切高一些,只是不利再次进行剖宫产手术。”这里的横切、纵切与编程中的还是挺相似的。

2.3.2 什么是AOP

​ AOP,可以说是OOP(Object-Oriented Programing,面向对象编程)的补充和完善。OOP引入封装、继承和多态性等概念来建立一种对象层次结构,用以模拟公共行为的一个集合。当我们需要为分散的对象引入公共行为(日志、安全、事务)的时候,OOP则显得无能为力。也就是说,OOP允许你定义从上到下的关系,但并不适合定义从左到右的关系。例如,日志功能。日志代码往往水平地散布在所有对象层次中,而与它所散布到的对象的核心功能毫无关系。对于其他类型的代码,如安全性、异常处理和透明的持续性也是如此。这种散布在各处的无关的代码被称为横切(cross-cutting)代码。在OOP设计中,它导致了大量代码重复、模块间的藕合度高,不利于各个模块的重用。
​ AOP技术则恰恰相反,它利用一种称为“横切”的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其命名为“Aspect”,即切面。所谓“切面”,简单地说,就是将那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可操作性和可维护性。

2.3.3 AOP原理

​ AOP实际上是由目标类的代理类实现的。AOP代理其实是由AOP框架动态生成的一个对象,该对象可作为目标对象使用。AOP代理包含了目标对象的全部方法(见图2-3),但AOP代理中的方法与目标对象的方法存在差异,AOP方法在特定切入点添加了增强处理,并回调了目标对象的方法。

图2-3
由于是代理实现AOP,因此有必要学习一下代理。下面通过实例一步一步地了解静态代理和动态代理。新建一个ServiceImplA类,实现IService接口,想在调用service方法前后增加日志打印或为service方法增加try catch,那么该怎么做呢?

package spring.tutorial.chapter2.AOP;public interface IService {public void service(String name) throws Exception;
}package spring.tutorial.chapter2.AOP.impl;public class ServiceImplA implements IService {@Overridepublic void service(String name) throws Exception {System.out.println("ServiceImplA name"+name);}
}

1.在每处调用的地方增加日志和try catch

 这也是一种方法,但缺点是很明显的,就是每处都要更改,量也会很大,显然不可取。这里是每个点都要加,一个方法可能被调用多处,就要写多次。而且以后再进行修改时也不方便,每个地方都要修改。

2.代理模式

 代理模式又分为动态代理模式和静态代理模式。
  • (1)静态代理
    静态代理关键是在代理对象和目标对象实现共同的接口,并且代理对象持有目标对象的引用。这里用类ProxyServiceA来实现IService接口,同时将实现IService接口的对象作为一个属性。
package spring.tutorial.chapter2.AOP.impl;import spring.tutorial.chapter2.AOP.IService;public class ProxyServiceA implements IService {private IService service;public ProxyServiceA(IService service){this.service = service;}@Overridepublic void service(String name) throws Exception {System.out.println("log start");try {service.service(name);}catch (Exception e){throw e;}System.out.println("log end");}public static void main(String[] args) throws Exception {IService service = new ServiceImplA();service= new ProxyServiceA(service);service.service("CYW");}
}

输出结果:

log start
ServiceImplA nameCYW
log end

​ 有了ProxyServiceA之后,打印日志和增加try-catch只需放在ProxyServiceA类里面,便于后续修改,比如现在打印日志是输出在操作台的,哪天需要输入到日志文件时也只需修改ProxyServiceA中的打印操作即可。但问题来了:项目中的接口可不止一个,可能会有很多,而且每个接口中的方法也会有好多,这样一个一个地增加也是问题,于是有了动态代理。

  • (2)动态代理
    在Java的动态代理机制中,有两个重要的类或接口:一个是InvocationHandler(Interface),另一个是Proxy(Class)。这一个类和接口是实现动态代理所必须用到的
package spring.tutorial.chapter2.AOP.impl;public class DynaProxyService implements InvocationHandler {private Object target;//目标对象public  Object bind(Object object){this.target = object;//生产动态代理对象Object obj = Proxy.newProxyInstance(this.target.getClass().getClassLoader(), this.target.getClass().getInterfaces(), this);return  obj;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {Object result = null;System.out.println("method:"+ method);System.out.println("args:"+ args);System.out.println("target:"+ this.target);System.out.println("log start");try {result = method.invoke(this.target, args);}catch (Exception e){throw e;}System.out.println("log end");return  result;}public static void main(String[] args) throws Exception {IService service = (IService) new DynaProxyService().bind(new ServiceImplA());service.service("CYM");}
}

输出结果

method:public abstract void spring.tutorial.chapter2.AOP.IService.service(java.lang.String) throws java.lang.Exception
args:[Ljava.lang.Object;@1d44bcfa
target:spring.tutorial.chapter2.AOP.impl.ServiceImplA@266474c2
log start
ServiceImplA nameCYM
log end

​ 通过Proxy.newProxyInstance()生成的动态代理对象A都会与实现InvocationHandler接口的对象B关联,动态代理对象A调用目标对象方法时都会变成调用B中的invoke方法。在invoke方法中织入增强处理,并通过反射回调目标对象方法。在本例中,通过bind()生成目标对象ServiceImplA的动态代理对象A,A关联了实现InvocationHandler接口对象的DynaProxyServiceA,当动态代理对象A调用目标对象方法时会执行DynaProxyServiceA的invoke方法,增加try-catch、打印日志,并回调目标对象的方法。
​ 与前面的静态代理比较发现,动态代理不用再为每个接口手动创建代理类,其他对象只要与InvocationHandler接口对象bind,就能获得该InvocationHandler接口对象的织入增强。

2.4 小结

​ 我们回顾一下这一章节的主要内容,主要了解了Spring框架,学习了IOC、AOP。在Spring框架部分,了解了框架的来源、七大模块。在IOC部分,介绍了依赖注入、控制反转以及两者的区别,以人与空气为例,使用Spring框架演示什么是依赖注入,也对Spring有一个大概的认识。在AOP部分,主要介绍了横切和纵切的概念、AOP的概念,并通过实例来了解AOP的原理。

参考

Spring Context 你真的懂了吗

https://www.cnblogs.com/deveypf/p/11406940.html

源码下载

[Spring 深度解析]第2章 Spring基础相关推荐

  1. [Spring 深度解析]第1章 Java基础

    第1章 ◄Java基础► 在学习Spring之前我们需要对Java基础语法有一定的了解,Java中最重要的两个知识点是注解和反射.注解和反射在Spring框架中应用的最广泛.掌握注解和反射,有助于后面 ...

  2. [Spring 深度解析]第6章 Spring的IoC容器系列

    6. Spring的IoC容器系列 ​ IoC容器为开发者管理对象之间的依赖关系提供了很多便利和基础服务.有许多IoC容器供开发者选择,SpringFramework的IoC核心就是其中一个,它是开源 ...

  3. [Spring 深度解析]第5章 Spring之DAO

    第5章 ◄Spring之DAO► ​ 在上一章节中,我们了解了Spring框架中的AOP模块,这一章节我们开始学习Spring框架中的DAO模块. 本章主要涉及的知识点: ​ ● JDBC基本用法:S ...

  4. [Spring 深度解析]第4章 Spring之AOP

    第4章 ◄Spring之AOP► 在上一章节中,我们大致了解了Spring核心容器,了解了IOC思想在Spring中的具体应用Bean容器以及Bean的配置与使用,这一章我们将开始学习AOP在Spri ...

  5. [Spring 深度解析]第3章 核心容器

    第3章 ◄核心容器► ​ 在上一章节中,我们大致了解了Spring框架,并学习了控制反转(IOC)和面向切面编程(AOP)两个重要的编程思想,这一章我们将开始学习Spring框架中的核心容器. 本章主 ...

  6. [Spring 深度解析]第7章 IoC容器的初始化过程

    7. IoC容器的初始化过程 ​ 简单来说,IoC容器的初始化是由前面介绍的refresh()方法来启动的,这个方法标志着IoC容器的正式启动.具体来说,这个启动包括BeanDefinition的Re ...

  7. Spring源码深度解析(郝佳)-学习-Spring Boot体系原理

      Spring Boot是由Pivotal团队提供的全新框架,其设计目的用来简化新Spring应用初始化搭建以及开发过程,该框架使用了我写的方式进行配置,从而开发人员不再需要定义样板化的配置,通过这 ...

  8. Spring实战 | 第一部分 Spring的核心(第一章 Spring之旅)

    Spring的bean容器 介绍Spring的核心模块 更为强大的Spring生态系统 Spring的新功能 一.简化java开发 为了降低Spring开发的复杂性,Spring采取了以下4钟关键策略 ...

  9. Spring入门篇——第6章 Spring AOP的API介绍

    第6章 Spring AOP的API介绍 主要介绍Spring AOP中常用的API. 6-1 Spring AOP API的Pointcut.advice概念及应用 映射方法是sa开头的所有方法 如 ...

最新文章

  1. 从 C++ 到 Objective-C
  2. win7多国语的安装说明
  3. html5 loader,7种基于GSAP的SVG Loader加载动画特效
  4. 计算机终止程序按钮,怎样在VisualBasic中终止计算机系统呢?
  5. SVN仓库迁移到Git遇到的两个问题和解决办法
  6. 删除误添加的本地github检查库文件
  7. 京东联盟新版API接口PHP版SDK的坑
  8. 打工人:是什么决定了你的薪资水平?一张图带你揭开涨薪秘诀!
  9. vx2阀(未完待续)
  10. MySQL-修改数据库密码
  11. 各种实用网站收集整理,不定期更新
  12. 学会制作html营销邮件,如何制作图文并茂的HTML邮件,做好EDM营销
  13. matlab生成代码veri,一种自动生成状态机RTL代码的方法
  14. 为什么不愿意专升本 学历有什么用
  15. Android底部弹窗实现方案
  16. Protocol 的用法
  17. 转换blob类型的数据,然后进行下载各种文件,还有各种blob转换的文件类型
  18. python-tkinter小程序之数独游戏
  19. python编写格斗游戏_基于C++语言编程格斗游戏毕业设计正文
  20. ubuntu系统U盘只能读取不能写入

热门文章

  1. Science Bulletin:上海植生所王二涛组发表基于绝对丰度的植物根际微生物群落“扩增-选择”组装模型
  2. NBT:利用细胞甘油三酯存储提高链霉菌中聚酮类化合物的效价
  3. Nature Protocols:整合宏基因组、代谢组和表型分析的的计算框架
  4. 16S+功能预测也能发Sciences:尸体降解过程中的微生物组
  5. pandas使用resample函数计算每个月的统计均值、使用matplotlib可视化特定年份的按月均值
  6. pandas使用Categorical函数将object数据数据列转化为categorical数据列并基于categorical的因子(分类)水平排序dataframe
  7. R语言使用ggplot2包使用geom_violin函数绘制分组小提琴图(自定义分组的次序)实战
  8. R语言层次聚类(hierarchical clustering):使用scale函数进行特征缩放、hclust包层次聚类(创建距离矩阵、聚类、绘制树状图dendrogram,在树状图上绘制红色矩形框)
  9. R语言dplyr包combine()函数实现数据拼接(concatenate)实战
  10. TED+肢体语言塑造你自己+power+fake it till you make it