#Spring 学习# 入门
久仰Spring MVC大名,现在公司要求学习Spring框架,打算借这个机会将Spring系列的东西学习一遍。接下来的学习任务:
- Spring
- Spring boot
- Mybatis
参考资料:
Spring 概述
2019-09-09 14:18
概述
Spring 由Rod Johnson编写,于2003 年 6 月在首次在 Apache 2.0 Licence下发布,是目前最受欢迎的企业级Java应用程序开发框架。Spring是一个开源的轻量级Java平台。
**编程模型:POJO, Plain Old Java Object. **
POJO
是一个简单的Java类,没有extends
, implements
or @annotations
. 不需要遵守任何Java模型,约定或者框架的Java对象。在实际应用中,可能会有annotations存在。如下3种都不是POJO :
public class Foo extends javax.servlet.http.HttpServlet {
... }
public class Foo implements javax.ejb.EntityBean {
.. }
@javax.persistence.Entity public class Baz {
... }
JavaBean
是一种可以被serializable
,拥有一个no-argument constructor
,并且允许用过getter and setter or is
来访问properties
的 POJO . 下面是一个JavaBean的例子:
<h:input value="#{MyBean.someProperty}" />
public class MyBean {
private String someProperty;
public String getSomeProperty() return someProperty;
public void setSomeProperty(String someProperty) this.someProperty = someProperty;
}
面向切面的程序设计(AOP): AOP( Aspect Oriented programming )是一种面向业务逻辑的编程方式,目的是为了减少模块间的耦合性。例如实现 persistent, transaction, security等。
面向对象模型(OOP)是面向对象的编程方式,目的是为了隔离实体,封装属性和操作, 例如 Employee, Student 。这两种方式的侧重点不同。
控制反转(IoC) 与 依赖注入(DI): 控制反转(Invension of Control, IoC)
, 是OOP种的一种设计原则,用来减低计算机代码之间的耦合度。最常见的方式为 依赖注入(Dependency Injection, DI)
,和 依赖查找(Dependency Lookup)
。详细参考控制反转.
Spring 体系结构
2019-09-09 15:23
Spring 的体系结构如下:
Core Container
- spring-core : 提供了框架的基本组成部分,包括 IoC 和 注解功能。
- spring-beans : 提供了 BeanFactory。
- context: 以一种类似于JNDI注册的方式访问对象。ApplicationContext是Context模块的焦点。
- spring-expression : 提供了强大的表达式语言,用于在运行时查询和操作对象。它是JSP2.1规范中定义的统一表达式语言的扩展。
Data Access/Integration
- JDBC : Java 和 DB的连接控制。
- ORM : 对象关系映射(Object Relation Mapping) 提供来对流行的对象关系映射API的集成,包括JPA, JDO和Hibernate。
- OXM
- JMS : 提供了 producer-consumer 的消息功能。
- transaction
Web
- Web :提供了面向Web的基本功能和面向Web应用上下文, eg: multipart files upload, servlet , etc.
- Web-MVC : 为Web应用提供来了模型视图控制(MVC)和 REST Web服务的实现。
- Web-Socket : 为 WebSocket-based 提供了支持,在Web应用程序中提供来Server和Client之间通信的两种方式。
- Web-Portlet : 提供来用于Portlet环境的MVC实现,并反映来spring-webmvc的功能。
Spring 环境配置
2019-09-09 18:38
-
安装jdk,配置环境变量; 安装IDE,如 eclipse 或者 IntelliJ IDEA。
-
安装 Apache Commons Logging API.
从 http://commons.apache.org/logging/ 下载最新二进制版本,目前是
commons-logging-1.2-bin.tar.gz
,将其解压到/usr/local/commons-logging-1.2
目录下。 -
安装 Spring 框架库
从 http://repo.spring.io/release/org/springframework/spring 下载最新的Spring二进制框架文件,目前是 spring-framework-5.1.9.RELEASE-dist.zip,将其解压到
/usr/local/spring-framework-5.1.9.RELEASE
。
如果使用的 IDE 是 eclipse , 那么将这些类库添加到build path
, add external jar
,不需要将这些类库添加到 CLASSPATH
环境变量,否则需要。
另外,也可以使用 maven 配置 spring. Spring 在 Maven Central 的位置为: https://search.maven.org/search?q=g:org.springframework. 由于 Spring 是高度模块化的,各个模块之间的耦合度很小甚至没有互相依赖。下面列出 Maven Central 中 Spring 的几个基本模块:
Group ID | Artifact ID | Latest Version | Updated |
---|---|---|---|
org.springframework | spring-core | 5.1.9.RELEASE[(99+)](https://search.maven.org/search?q=g:org.springframework AND a:spring-core&core=gav) | 02-Aug-2019 |
org.springframework | spring-beans | 5.1.9.RELEASE[(99+)](https://search.maven.org/search?q=g:org.springframework AND a:spring-beans&core=gav) | 02-Aug-2019 |
org.springframework | spring-context | 5.1.9.RELEASE[(99+)](https://search.maven.org/search?q=g:org.springframework AND a:spring-beans&core=gav) | 02-Aug-2019 |
org.springframework | spring-context-support | 5.1.9.RELEASE[(99+)](https://search.maven.org/search?q=g:org.springframework AND a:spring-beans&core=gav) | 02-Aug-2019 |
org.springframework | spring-expression | 5.1.9.RELEASE[(99+)](https://search.maven.org/search?q=g:org.springframework AND a:spring-beans&core=gav) | 02-Aug-2019 |
org.springframework | spring-aop | 5.1.9.RELEASE[(99+)](https://search.maven.org/search?q=g:org.springframework AND a:spring-beans&core=gav) | 02-Aug-2019 |
org.springframework | spring-jdbc | 5.1.9.RELEASE[(99+)](https://search.maven.org/search?q=g:org.springframework AND a:spring-beans&core=gav) | 02-Aug-2019 |
org.springframework | spring-orm | 5.1.9.RELEASE[(99+)](https://search.maven.org/search?q=g:org.springframework AND a:spring-beans&core=gav) | 02-Aug-2019 |
org.springframework | spring-jms | 5.1.9.RELEASE[(99+)](https://search.maven.org/search?q=g:org.springframework AND a:spring-beans&core=gav) | 02-Aug-2019 |
org.springframework | spring-messaging | 5.1.9.RELEASE[(82)](https://search.maven.org/search?q=g:org.springframework AND a:spring-messaging&core=gav) | 02-Aug-2019 |
org.springframework | spring-oxm | 5.1.9.RELEASE[(99+)](https://search.maven.org/search?q=g:org.springframework AND a:spring-beans&core=gav) | 02-Aug-2019 |
org.springframework | spring-web | 5.1.9.RELEASE[(99+)](https://search.maven.org/search?q=g:org.springframework AND a:spring-beans&core=gav) | 02-Aug-2019 |
org.springframework | spring-webmvc | 5.1.9.RELEASE[(99+)](https://search.maven.org/search?q=g:org.springframework AND a:spring-beans&core=gav) | 02-Aug-2019 |
org.springframework | spring-websocket | 5.1.9.RELEASE[(99+)](https://search.maven.org/search?q=g:org.springframework AND a:spring-beans&core=gav) | 02-Aug-2019 |
org.springframework | spring-aspect | 5.1.9.RELEASE[(99+)](https://search.maven.org/search?q=g:org.springframework AND a:spring-beans&core=gav) | 02-Aug-2019 |
org.springframework | spring-instrument | 5.1.9.RELEASE[(99+)](https://search.maven.org/search?q=g:org.springframework AND a:spring-beans&core=gav) | 02-Aug-2019 |
org.springframework | spring-test | 5.1.9.RELEASE[(99+)](https://search.maven.org/search?q=g:org.springframework AND a:spring-beans&core=gav) | 02-Aug-2019 |
Maven 配置方法:在 pom.xml
文件中,添加依赖:
<properties>
<org.springframework.version>5.1.9.RELEASE</org.springframework.version>
</properties>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${org.springframework.version}</version>
<scope>runtime</scope> <!-- 运行时范围,确保在任何特定于Spring的API上没有编译时依赖性 -->
</dependency>
<!-- 继续添加其他 spring 模块依赖, 如 spring-beans 等 -->
Spring Hello World 实例
2019-09-09 20:56
这部分开始实际的编程。
-
创建Java项目:用 eclipse 创建Java项目。
-
添加必要的库:为HelloWorld项目添加必要spring依赖,如 spring-core, spring-beans, spring-context, 等。添加 common-logging 依赖。
添加完后的项目如下:
-
创建源文件:
-
在 src 目录下创建 com.gthncz 包,创建 源文件
HelloWorld.java
:package com.gthncz; public class HelloWorld { private String msg; public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } }
-
在 com.gthncz 包下,创建 源文件
MainApp.java
:package com.gthncz; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class MainApp { public static void main(String[] args) { @SuppressWarnings("resource") ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml"); HelloWorld helloWold = (HelloWorld) context.getBean("helloWorld"); String msg = helloWold.getMsg(); System.out.println("Get message : " + msg); } }
这里使用框架API
ClassPathXmlApplicationContext
来创建应用程序的上下文。这个API加载beans的配置文件并最终基于所提供的API,它处理创建并初始化所有的对象,即在配置中指定的Beans.xml
文件的beans 。第二步是使用
getBean(id)
方法获取所需的bean。 -
-
创建bean配置文件
该文件是一个XML文件,在
src
目录下创建:<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans spring-beans.xsd"> <!-- 出现错误: org.xml.sax.SAXParseException; lineNumber: 4; columnNumber: 57; cvc-elt.1: Cannot find the declaration of element 'beans'. 原因: 命名空间错误。使用 spring-beans.xsd 创建的xml文件中的 xmlns 为 xmlns:p,改过来就好了, 另外, xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd" 改过来 --> <bean id="helloWorld" class="com.gthncz.HelloWorld"> <property name="msg" value="Hello World!" /> </bean> </beans>
我在创建
Beans.xml
文件时使用create from XSD schema
,使用springframework-5.1.9.RELEASE/schema/beans
中的beans.xsd
文件。注意需要修改namespace
,xsi:schemaLocation
。通常开发人员保存该文件的名称为 Beans.xml 文件,当然你也可以设置成任何你喜欢的名称。但是你必须确保这个文件在 CLASSPATH 中是可用的,并在主应用程序中使用相同的名称,而在 MainApp.java 文件中创建应用程序的上下文。
Beans.xml 用于给不同的 bean 分配唯一的 ID,并且控制不同值的对象的创建,而不会影响 Spring 的任何源文件。例如,使用下面的文件,你可以为 “message” 变量传递任何值,因此你就可以输出信息的不同值,而不会影响的 HelloWorld.java和MainApp.java 文件。当 Spring 应用程序被加载到内存中时,框架利用了上面的配置文件来创建所有已经定义的 beans,并且按照标签的定义为它们分配一个唯一的 ID。你可以使用标签来传递在创建对象时使用不同变量的值。
-
运行程序
运行结果:
到此,Hello World项目就结束了。 先回去睡了。。。
Spring IoC容器
2019-09-10 08:28
Spring容器是Spring框架的核心。容器将创建对象(称为 Spring Bean),配置对象,并管理(通过依赖注入, DI)他们的从创建到销毁的整个生命周期。
上图是Spring的工作视图,Spring IoC容器利用Java 的 POJO类和配置元数据(Metadata)来生成和配置应用程序。Metadata 可以通过XML, Java注释 以及 Java Code来表示,Metadata指明了哪些类需要实例化。
IoC容器是具有依赖注入的容器。通常,我们使用new
关键字新建Class Instance,控制权由程序员控制,而"控制反转"是指new实例工作不由程序员来完成,而是由Spring Container实现。
两种不同类型的Spring Container:
序号 | 容器 & 描述 |
---|---|
1 | Spring BeanFactory 容器,是Spring中最简单的容器,给ID提供了最基本的支持。 |
2 | Spring ApplicationContainer 容器,该容器添加了更多的企业特性,比如从一个属性文件中解析文本信息的能力。 |
ApplicationContainer
容器的功能包括BeanFactory
的所有功能,一般情况下建议使用ApplicationContainer
。当然,BeanFactory
仍然可以用于轻量级的应用程序,如移动设备或者基于applet的应用程序。在这些情况下BeanFactory的数据量和速度比ApplicationContainer更加显著。
Spring BeanFactory 容器
2019-09-10 09:09
它是最简单的容器,提供DI支持,在org.springframework.beans.factory.BeanFactory
中定义。
在Spring中,有大量对BeanFactory的实现,其中最常用的是XmlBeanFactory类。这个容器从XML文件中读取配置元数据,由这些元数据生成一个被配置化的系统或应用。
下面是一个使用 XmlBeanFactory的例子,其他文件使用前面的HelloWorld项目中的文件:
package com.gthncz;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;
@SuppressWarnings("deprecation")
public class BeanFactoryDemo {
public static void main(String[] args) {
XmlBeanFactory factory = new XmlBeanFactory(new ClassPathResource("Beans.xml"));
HelloWorld helloWorld = (HelloWorld) factory.getBean("helloWorld");
System.out.println("Get Message: " + helloWorld.getMsg());
}
}
执行输出:
注意到,我目前的Spring版本是5.1.9.RELEASE,在使用 XmlBeanFactory 时提示 deprecation
warnning。StackOverflow 上面也有相关问题,但是大家都推荐使用 ClassPathXmlApplicationContext
了。。。
ApplicationContext 容器
2019-09-10 10:08
Application Context是BeanFactory的字接口,也被称为 Spring 上下文
。
Application Context 具有 BeanFactory的全部功能,另外还增加了企业所需要的功能,比如从属性文件中解析文本信息和将事件传递给所指定的监听器。
最常用的 Application Context 接口实现如下,都是从XML文件中加载已被定义的bean:
FileSystemXmlApplicationContext
:需要提供XML文件的完整路径。ClassPathXmlApplicationContext
:从 CLASSPATH 路径下查找XML配置文件,不需要完整路径,但是需要正确配置 CLASSPATH 环境变量。WebXmlApplicationContext
:该容器在一个Web应用程序的范围内加载在Xml文件中已经被定义的bean。
接下来是各个 Application Context的demo:
-
FileSystemApplicationContext
package com.gthncz; import org.springframework.context.ApplicationContext; import org.springframework.context.support.FileSystemXmlApplicationContext; public class FileSystemApplicationContextDemo { public static void main(String[] args) { @SuppressWarnings("resource") ApplicationContext context = new FileSystemXmlApplicationContext("src/Beans.xml"); HelloWorld helloWorld = (HelloWorld) context.getBean("helloWorld"); System.out.println("Get Message: " + helloWorld.getMsg()); } }s
执行输出:
需要注意的是,前面的Beans.xml文件中 xsi:schemaLocation 位置只写了一个相对路径,需要改成完整的路径。 -
ClassPathXmlApplicationContext
这个前面已经描述过了,这里不再赘述。
-
WebXmlApplicationContext
TODO 后续添加。
Spring Bean 定义
2019-09-10 11:20
Spring Bean是由容器用配置元数据创建的,例如,前面看到的XML中表单中的定义。
定义 bean 的属性:
属性 | 描述 |
---|---|
class | 强制的,指定用来创建 bean 的 类(packageName + className, 完整路径)。 |
name | 指定唯一的 bean 标识符,可以使用 id 或name 属性来指定。 |
scope | 指定由创建的对象的作用域。 |
constructor-arg | 用来注入依赖关系, 构造函数参数 |
properties | 用来注入依赖关系, bean 的属性 |
autowiring mode | 用来注入依赖关系, 自动装配模式 |
lazy-initialization mode | 延迟初始化的 bean 告诉 IoC 容器在它第一次被请求时创建实例,而不是在启动时创建实例。 |
initialization 方法 | 在 bean 的所有必需的属性被容器设置之后,调用的回调方法。 |
destruction 方法 | 当包含该 bean 的容器被销毁时,调用的回调方法。 |
Bean 与 Spring 容器的关系
Spring 配置元数据
Spring IoC 容器完全由实际编写的配置元数据的格式解藕。有3种配置元数据的方法:
- 基于 XML 的配置文件
- 基于 annotation 的配置
- 基于 Java 的配置
对于基于 XML 的配置,Spring 2.0 以后使用 Schema 的格式,使得不同类型的配置拥有了自己的命名空间,使得配置文件更具有扩展性。下面是一个更加完整的 XML 格式配置:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<!-- A simple bean definition -->
<bean id="" class="" >
<!-- collaborators and configuration for this bean go here -->
</bean>
<!-- A bean definition with lazy init set on -->
<bean id="" class="" lazy-init="true">
<!-- collaborators and configuration for this bean go here -->
</bean>
<!-- A bean definition with initialization method -->
<bean id="" class="" init-method="..." >
<!-- collaborators and configuration for this bean go here -->
</bean>
<!-- A bean definition with destruction method -->
<bean id="" class="" destroy-method="..." >
<!-- collaborators and configuration for this bean go here -->
</bean>
<!-- more bean definitions go here -->
</beans>
在上述示例中:
- xmlns=“http://www.springframework.org/schema/beans” 默认命名空间:它没有空间名,用于Spring Bean 的定义;
- xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance”, xsi 命名空间:这个命名空间用于为每个文档中命名空间指定相应的 Schema 样式文件,是标准组织定义的标准命名空间。
**Spring Bean Scope **(作用域)
当在 Spring 中定义一个 Bean 时, 必需声明这个 Bean 的 scope。Spring 框架支持5种作用域,如下:
scope | description |
---|---|
singleton | 单例模式,Spring IoC 容器中只存在一个 Bean 实例; **默认值 ** |
prototype | 每次从容器中调用 Bean 时,都创建一个新的 Bean 实例,即每次调用 getBean() 时,相当于调用 newXXXBean() |
request | 每次 HTTP 请求都会创建一个 Bean 实例,该 scope 仅作用于WebApplicationContext 环境 |
session | 同一个 HTTP Session 共用一个 Bean 实例,不同 Session 使用不同 Bean 实例,该 scope 仅作用于 WebApplicationContext 环境 |
global-session | 一般用于Portlet应用环境,该运用域仅适用于WebApplicationContext环境 |
以下是测试 singleton
和 prototype
scope 的例子,其它 scope 在后面添加。
- Beans_scope.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="singletonBean" class="com.gthncz.HelloWorld" scope="singleton" >
<property name="msg" value="Hello world !"></property>
</bean>
<bean id="prototypeBean" class="com.gthncz.HelloWorld" scope="prototype" >
<property name="msg" value="Hello world !"></property>
</bean>
<bean id="requestBean" class="com.gthncz.HelloWorld" scope="request" >
<property name="msg" value="Hello world !"></property>
</bean>
<bean id="sessionBean" class="com.gthncz.HelloWorld" scope="session" >
<property name="msg" value="Hello world !"></property>
</bean>
<bean id="globalSessionBean" class="com.gthncz.HelloWorld" scope="global-session" >
<property name="msg" value="Hello world !"></property>
</bean>
</beans>
这里继续使用 HelloWorld 类,创建5个不同 scope 的 Bean。
- ScopeDemo.java文件
package com.gthncz;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class ScopeDemo {
public static void main(String[] args) {
@SuppressWarnings("resource")
ApplicationContext context = new ClassPathXmlApplicationContext("Beans_scope.xml");
/**
* test singleton scope
*/
HelloWorld singletonBean1 = (HelloWorld) context.getBean("singletonBean");
HelloWorld singletonBean2 = (HelloWorld) context.getBean("singletonBean");
// 比较两个对象的地址
System.out.println("Singleton Bean is equal ? " + (singletonBean1 == singletonBean2));
/**
* test prototype scope
*/
HelloWorld prototypeBean1 = (HelloWorld) context.getBean("prototypeBean");
HelloWorld prototypeBean2 = (HelloWorld) context.getBean("prototypeBean");
System.out.println("Prototype Bean is equal ? " + (prototypeBean1 == prototypeBean2));
// more information about bean scope
}
}
执行输出:
由结果可以看出,singleton scope 获取得到的 Bean 是单例模式,而 prototype scope 获取得到新实例。
Spring Bean 生命周期
Bean 的生命周期: Bean 的定义 -> Bean 的初始化 -> Bean 的使用 -> Bean 的销毁
在 Bean 的生命周期中的 初始化 和 销毁 阶段,存在方法回调,允许用户处理一些自己的逻辑。有两种不同的方式实现回调:Java 接口回调 , XML 方法声明。
-
Java 接口回调
org.springframework.beans.factory.InitializingBean
定义了 初始化回调。public void afterPropertiesSet() throws Exception;
org.springframework.beans.factory.DisposableBean
定义来 销毁回调。public void destroy throws Exception;
-
XML 方法声明
在 XML 配置文件中可以声明
init-method
属性和destroy-method
属性。<bean id="lifeCircleBean" class="com.gthncz.LifeCircleBean" init-method="xml_initialize" destroy-method="xml_destroy" > <property name="msg" value="value on xml" /> </bean>
下面是 Spring Bean 生命周期回调方法的测试:
- Beans_lifecircle.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd" >
<bean id="lifeCircleBean" class="com.gthncz.LifeCircleBean"
init-method="xml_initialize" destroy-method="xml_destroy" >
<property name="msg" value="value on xml" />
</bean>
</beans>
XML 配置文件中指定了 init-method 和 destroy-method。
- LifeCircleBean.java
package com.gthncz;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
public class LifeCircleBean implements InitializingBean, DisposableBean {
private String msg;
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
/**
* implement of InitializingBean
*/
@Override
public void afterPropertiesSet() throws Exception {
System.out.println(" run on afterPropertiesSet ... ");
System.out.println("Msg on afterPropertiesSet: " + this.msg);
}
/**
* implement of DisposableBean
*/
@Override
public void destroy() throws Exception {
System.out.println(" run on destroy ... ");
System.out.println("Msg on destroy: " + this.msg);
}
/**
* implement of init-method which definite in xml
*/
public void xml_initialize() {
System.out.println(" run on xml_initialize ... ");
System.out.println("Msg on xml_initialize: " + this.msg);
}
/**
* implement of destroy-method which definite in xml
*/
public void xml_destroy() {
System.out.println(" run on xml_destroy ... ");
System.out.println("Msg on xml_destroy: " + this.msg);
}
}
Bean 中实现了 Java 接口回调 和 XML 指定的回调方法。
- BeanLifeCircleDemo.java
package com.gthncz;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class BeanLifeCircleDemo {
public static void main(String[] args)