Spring 框架
一. Spring入门
Spring模块都打包成JAR文件,其命名格式如下:
spring-maluleName-x.y.z.RELEASE.jar
其中module name是模块的名字,而x.y.z是spring的 版本号。例如:Spring的4.1.12版本中的beans模块的包 全名为:spring-beans-4.1.12.RELEASE.jar。
推荐采用Maven或Gradle工具来下载Spring模块, 具体操作步骤可以参见Spring官网:
http://projects.spring.io/spring-framework
使用maven加载Spring需要在pom.xml文件加入
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1..RELEASE</version>
</dependency>
采用类似Maven以及Gradle这样的工具有一个好 处,即下载一个Spring模块时会自动下载其所依赖的模 块。
如果不熟悉以上两种工具,则可以通过如下链接下 载包括所有模块的压缩文件:
http://repo.spring.io/release/org/springframework/spring/
注意:压缩文件中包括依赖库,必须单独下载。
二. 依赖注入
在过去数年间,依赖注入技术作为代码可测试性的 一个解决方案已经被广泛应用。实际上,Spring、谷歌 Guice等伟大框架都采用了依赖注入技术。那么,什么 是依赖注入技术?
很多人在使用中并不区分依赖注入和控制反转 (IoC),尽管Martin Fowler在其文章中已分析了二者 的不同。
http://martinfowler.com/articles/injection.html
简单来说,依赖注入的情况如下。 有两个组件A和B,A依赖于B。假定A是一个类, 且A有一个方法importantMethod使用到了B,如下:
public class A {
public void importantMethod() {
B b = ... // get an instance of B
b.usefulMethod();
...
}
...
}
要使用B,类A必须先获得组件B的实例引用。若B 是一个具体类,则可通过new关键字直接创建组件B实 例。但是,如果B是接口,且有多个实现,则问题就变 得复杂了。我们固然可以任意选择接口B的一个实现 类,但这也意味着A的可重用性大大降低了,因为无法 采用B的其他实现。
依赖注入是这样处理此类情景的:接管对象的创建 工作,并将该对象的引用注入需要该对象的组件。以上 述例子为例,依赖注入框架会分别创建对象A和对象 B,将对象B注入到对象A中。
为了能让框架进行依赖注入,程序员需要编写特定 的set方法或者构建方法。例如,为了能将B注入到A 中,类A会被修改成如下形式:
public class A {
private B b;
public void importantMethod() {
// no need to worry about creating B anymore
// B b = ... // get an instance of B
b.usefulMethod();
...
}
public void setB(B b) {
this.b = b;
}
}
修改后的类A新增了一个setter方法,该方法将会被 框架调用,以注入一个B的实例。由于对象依赖由依赖 注入,类A的importantMethod方法不再需要在调用B的 usefulMethod方法前去创建一个B的实例。
当然,也可以采用构造器方式注入,如下所示:
public class A {
private B b;
public A(B b) {
this.b = b;
}
public void importantMethod() {
// no need to worry about creating B anymore
// B b = ... // get an instance of B
b.usefulMethod();
...
}
}
本例中,Spring会先创建B的实例,再创建实例 A,然后把B注入到实例A中。
注意: Spring管理的对象称为beans。
通过提供一个控制反转容器(或者依赖注入容 器),Spring为我们提供一种可以“聪明”地管理Java对 象依赖关系的方法。其优雅之处在于,程序员无须了解 Spring框架的存在,更不需要引入任何Spring类型。
从1.0版本开始,Spring就同时支持setter和构造器 方式的依赖注入。从2.5版本开始,通过Autowired注 解,Spring支持基于field方式的依赖注入,但缺点是程 序必须引入 org.springframework.beans.factory.annotation.Autowired, 这对Spring产生了依赖,这样,程序无法直接迁移到另 一个依赖注入容器内。
使用Spring,程序几乎将所有重要对象的创建工作 移交给Spring,并配置如何注入依赖。Spring支持XML 和注解两种配置方式。此外,还需要创建一个 ApplicationContext对象,代表一个Spring控制反转容 器,org.springframework.context.ApplicationContext接口 有多个实现,包括ClassPathXmlApplicationContext和 FileSystemXmlApplicationContext。这两个实现都需要 至少一个包含beans信息的XML文件。 ClassPathXmlApplicationContext尝试在类加载路径中加 载配置文件,而FileSystemXmlApplicationContext则从 文件系统中加载。
下面为从类路径中加载config1.xml和config2.xml的 ApplicationContext创建的一个代码示例:
ApplicationContext context = new ClassPathXmlApplicationContext
(
new String[] {"config1.xml", "config2.xml"});
可以通过调用ApplicationContext的getBean方法获 得对象:
Product product = context.getBean("product", Product.class);
Product product = context.getBean("product", Product.class);
注:
理想情况下,我们仅需在测试代码中创建一个 ApplicationContext,应用程序本身无须处理。对于Spring MVC应用, 可以通过一个Spring Servlet来处理ApplicationContext,而无须直接处 理。
三.XML配置文件
从1.0版本开始,Spring就支持基于XML的配置, 从2.5版本开始,增加了通过注解的配置支持。下面介 绍如何配置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/bea
ns
http://www.springframework.org/schema/beans/spring-beans.xsd"
>
...
</beans>
如果需要更强的Spring配置能力,可以在schema location属性中添加相应的schema。配置文件可以是一 份,也可以分解为多份,以支持模块化配置。 ApplicationContext的实现类支持读取多份配置文件。另 一种选择是,通过一份主配置文件,将该文件导入到其 他配置文件
下面是一个导入其他配置文件的示例:
<?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/bea
ns
http://www.springframework.org/schema/beans/spring-beans.xsd"
>
<import resource="config1.xml"/>
<import resource="module2/config2.xml"/>
<import resource="/resources/config3.xml"/>
...
</beans>
bean元素的配置后面将会详细介绍。
xml配置文件必须在classes目录下面
四.Spring控制反转容器的使用
1. 通过构造器创建一个bean实例
前面已经介绍,通过调用ApplicationContext的 getBean方法可以获取到一个bean的实例。下面的配置 文件中定义了一个名为product的bean。
<?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/bea
ns
http://www.springframework.org/schema/beans/spring-beans.xsd"
>
<bean name="product" class="app15a.bean.Product"/>
</beans>
该bean的定义告诉Spring通过默认无参的构造器来 初始化Product类。如果不存在该构造器(因为类作者 重载了构造器,且没有显式定义默认构造器),则 Spring将抛出一个异常。
注意,应采用id或者name属性标识一个bean。为了 让Spring创建一个Product实例,应将bean定义的name 值“product”(具体实践中也可以是id值)和Product类型 作为参数传递给ApplicationContext的getBean方法:
ApplicationContext context =
new ClassPathXmlApplicationContext(
new String[] {"spring-config.xml"});
Product product1 = context.getBean("product", Product.class);
product1.setName("Excellent snake oil");
System.out.println("product1: " + product1.getName());
2. 通过工厂方法创建一个bean实例
除了通过类的构造器方式,Spring还同样支持通过 调用一个工厂的方法来初始化类。下面的bean定义展示 了通过工厂方法来实例化java.util.Calendar:
<bean id="calendar" class="java.util.Calendar"
factory-method="getInstance"/>
本例中采用了id属性,而非name属性来标识bean, 并采用了getBean方法来获取Calendar实例:
ApplicationContext context =
new ClassPathXmlApplicationContext(
new String[] {"spring-config.xml"});
Calendar calendar = context.getBean("calendar", Calendar.class);
3. Destroy Method的使用
有时,我们希望一些类在被销毁前能执行一些方 法。Spring考虑到了这样的需求。可以在bean定义中配 置destroy-method属性,来指定在销毁前要被执行的方 法。
下面的例子中,我们配置Spring通过 java.util.concurrent.Executors的静态方法newCached ThreadPool来创建一个 java.uitl.concurrent.ExecutorService实例,并指定了 destroy-method属性值为shutdown方法。这样,Spring会 在销毁ExecutorService实例前调用其shutdown方法:
<bean id="executorService" class="java.util.concurrent.Executors"
factory-method="newCachedThreadPool"
destroy-method="shutdown"/>
4. 向构造器传递参数
Spring支持通过带参数的构造器来初始化类。
Product类
package bean; import java.io.Serializable; public class Product implements Serializable {
private static final long serialVersionUID = 748392348L;
private String name;
private String description;
private float price; public Product() {
} public Product(String name, String description, float price) {
this.name = name;
this.description = description;
this.price = price;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public String getDescription() {
return description;
} public void setDescription(String description) {
this.description = description;
} public float getPrice() {
return price;
} public void setPrice(float price) {
this.price = price;
}
}
如下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 name="featuredProduct" class="bean.Product">
<constructor-arg name="name" value="Ultimate Olive Oil"/>
<constructor-arg name="description"
value="The purest olive oil on the market"/>
<constructor-arg name="price" value="9.95"/>
</bean>
</beans>
这样,在创建Product实例时,Spring会调用如下构 造器:
public Product(String name, String description, float price) {
this.name = name;
this.description = description;
this.price = price;
}
除了通过名称传递参数外,Spring还支持通过指数 方式传递参数,具体如下:
<bean name="featuredProduct" class="bean.Product">
<constructor-arg index="" value="Ultimate Olive Oil"/>
<constructor-arg index=""
value="The purest olive oil on the market"/>
<constructor-arg index="" value="9.95"/>
</bean>
需要说明的是,采用这种方式,对应构造器的所有 参数必须传递,缺一不可。
servlet页面
package servlet;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.http.*;
import javax.servlet.Servlet;
import javax.servlet.annotation.*; import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.web.*; import bean.Product;
@WebServlet(name="test" ,urlPatterns= {"/test"})
public class Test extends HttpServlet{
ApplicationContext context = new ClassPathXmlApplicationContext(
new String[] { "springmvc-servlet.xml"});
Product str1= new Product(); public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException { response.setContentType("text/html charset='utf-8' ");
PrintWriter writer = response.getWriter();
Product featured = (Product) context.getBean("featuredProduct",Product.class);
writer.println( featured.getDescription()); }
}
可以通过调用ApplicationContext的getBean方法获 得对象,getBean方法会查询id为product且类型为Product的 bean对象。
注:
理想情况下,我们仅需在测试代码中创建一个 ApplicationContext,应用程序本身无须处理。对于Spring MVC应用, 可以通过一个Spring Servlet来处理ApplicationContext,而无须直接处 理。
5. setter方式依赖注入
下面以Employee类和Address类为例,介绍setter方 式依赖注入。
Employee类
package bean; public class Employee {
private String firstName;
private String lastName;
private Address homeAddress; public Employee() {
} public Employee(String firstName, String lastName, Address homeAddress) {
this.firstName = firstName;
this.lastName = lastName;
this.homeAddress = homeAddress;
} public String getFirstName() {
return firstName;
} public void setFirstName(String firstName) {
this.firstName = firstName;
} public String getLastName() {
return lastName;
} public void setLastName(String lastName) {
this.lastName = lastName;
} public Address getHomeAddress() {
return homeAddress;
} public void setHomeAddress(Address homeAddress) {
this.homeAddress = homeAddress;
} @Override
public String toString() {
return firstName + " " + lastName + "\n" + homeAddress;
} }
Address类
package bean; public class Address {
private String line1;
private String line2;
private String city;
private String state;
private String zipCode;
private String country; public Address(String line1, String line2, String city, String state, String zipCode, String country) {
this.line1 = line1;
this.line2 = line2;
this.city = city;
this.state = state;
this.zipCode = zipCode;
this.country = country;
} // getters and setters omitted
@Override
public String toString() {
return line1 + "\n" + line2 + "\n" + city + "\n" + state + " " + zipCode + "\n" + country;
}
}
Employee依赖于Address类,可以通过如下配置来 保证每个Employee实例都能包含Address实例:
<?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 name="simpleAddress" class="bean.Address'">
<constructor-arg name="line1" value="151 Corner Street"/>
<constructor-arg name="line2" value=""/>
<constructor-arg name="city" value="Albany"/>
<constructor-arg name="state" value="NY"/>
<constructor-arg name="zipCode" value=""/>
<constructor-arg name="country" value="US"/>
</bean>
<bean name="employee1" class="bean.Emploee" >
<property name="homeAddress" ref="simpleAddress"/>
<property name="firstName" value="Junior"/>
<property name="lastName" value="Moore"/>
</bean> </beans>
simpleAddress对象是Address类的一个实例,其通 过构造器方式实例化。employee1对象则通过配置 property元素来调用setter方法以设置值。需要注意的 是,homeAddress属性配置的是simpleAddress对象的引 用。
被引用对象的配置定义无须早于引用其对象的定 义。本例中,employee1对象可以出现在simpleAddress 对象定义之前。
6. 构造器方式依赖注入
Employee类提供了一个可以传递参 数的构造器,我们还可以将Address对象通过构造器注 入,如下所示:
<bean name="employee2" class="app15a.bean.Employee">
<constructor-arg name="firstName" value="Senior"/>
<constructor-arg name="lastName" value="Moore"/>
<constructor-arg name="homeAddress" ref="simpleAddress"/>
</bean>
<bean name="simpleAddress" class="app15a.bean.Address">
<constructor-arg name="line1" value="151 Corner Street"/>
<constructor-arg name="line2" value=""/>
<constructor-arg name="city" value="Albany"/>
<constructor-arg name="state" value="NY"/>
<constructor-arg name="zipCode" value=""/>
<constructor-arg name="country" value="US"/>
</bean>
Spring 框架的更多相关文章
- Spring框架概述
Spring是最流行的Java企业级应用开发框架,全球数以百万的开发者在使用Spring框架创建高性能.易测试.可重用的代码. Spring框架的核心特性可以应用于任何Java应用,但扩展的JavaE ...
- 初识Spring框架实现IOC和DI(依赖注入)
学习过Spring框架的人一定都会听过Spring的IoC(控制反转) .DI(依赖注入)这两个概念,对于初学Spring的人来说,总觉得IoC .DI这两个概念是模糊不清的,是很难理解的, IoC是 ...
- Spring 框架的架包分析、功能作用、优点,及jar架包简介
Spring 框架的架包详解 Spring的作用 Spring的优势 由于刚搭建完一个MVC框架,决定分享一下我搭建过程中学习到的一些东西.我觉得不管你是个初级程序员还是高级程序员抑或 ...
- 最新 Eclipse IDE下的Spring框架配置及简单实例
前段时间开始着手学习Spring框架,又是买书又是看视频找教程的,可是鲜有介绍如何配置Spring+Eclipse的方法,现在将我的成功经验分享给大家. 本文的一些源代码来源于码农教程:http:// ...
- spring框架学习(三)
一.Spring自动组件扫描 Spring 提供组件扫描(component scanning)功能.它能从指定的classpath里自动扫描.侦测和实例化具有特定注解的组件. 基本的注解是@Comp ...
- Spring框架学习(一)
一. spring概述 Spring 框架是一个分层架构,由 7 个定义良好的模块组成.Spring 模块构建在核心容器之上,核心容器定义了创建.配置和管理 bean 的方式,如图 1 所示. 图 1 ...
- Spring 系列: Spring 框架简介 -7个部分
Spring 系列: Spring 框架简介 Spring AOP 和 IOC 容器入门 在这由三部分组成的介绍 Spring 框架的系列文章的第一期中,将开始学习如何用 Spring 技术构建轻量级 ...
- 使用 Spring Boot 快速构建 Spring 框架应用--转
原文地址:https://www.ibm.com/developerworks/cn/java/j-lo-spring-boot/ Spring 框架对于很多 Java 开发人员来说都不陌生.自从 2 ...
- 【Spring】浅析Spring框架的搭建
c目录结构: // contents structure [-] Spring是什么 搭建Spring框架 简单Demo 1,建立User类 2,建立Test类 3,建立ApplicationCont ...
- Spring框架总结
Spring(由Rod Johnson创建的一个开源框架) Spring是一个开源框架,Spring是于2003 年兴起的一个轻量级的Java 开发框架,由Rod Johnson创建.简单来说,Spr ...
随机推荐
- NIO原理及案例使用
什么是NIO Java提供了一个叫作NIO(New I/O)的第二个I/O系统,NIO提供了与标准I/O API不同的I/O处理方式.它是Java用来替代传统I/O API(自Java 1.4以来). ...
- jmeter学习记录--08--第三方测试组件
我们安装的JMeter版本,功能仍然有欠缺,插件是一种补充,官方提供了很多插件. 官网地址:http://www.jmeter-plugins.org/, 里面有很多可以安装到JMeter的插件,基本 ...
- JDK环境配置(Windows)
JDK环境配置(Windows): 1.下载jdk版本: https://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads ...
- centos7之rsync+serrsync
Rsync+Inotify-tools与Rsync+sersync这两种架构有什么区别 1.Rsync+Inotify-tools(1):Inotify-tools只能记录下被监听的目录发生了变化(包 ...
- aop通知加参数的匹配规则
- kubernetes 报错汇总
一. pod的报错: 1. pod的容器无法启动报错: 报错信息: Normal SandboxChanged 4m9s (x12 over 5m18s) kubelet, k8sn1 Pod san ...
- #!/usr/bin/python3的作用 解决vscode ImportError: No module named xxxx
在 Python 脚本的第一行经常见到这样的注释: #!/usr/bin/env python3 或者 #!/usr/bin/python3 含义 在脚本中, 第一行以 #! 开头的代码, 在计算机行 ...
- 倍增\ tarjan求lca
对于每个节点v,记录anc[v][k],表示从它向上走2k步后到达的节点(如果越过了根节点,那么anc[v][k]就是根节点). dfs函数对树进行的dfs,先求出anc[v][0],再利用anc[v ...
- Java 找出四位数的所有吸血鬼数字 基础代码实例
/** * 找出四位数的所有吸血鬼数字 * 吸血鬼数字是指位数为偶数的数字,可以由一对数字相乘而得到,而这对数字各包含乘积的一半位数的数字,其中从最初的数字中选取的数字可以任意排序. * 以两个 ...
- Java【第四篇】基本语法之--循环
循环语句功能 在循环条件满足的情况下,反复执行特定代码 循环语句的四个组成部分 初始化部分(init_statement)循环条件部分(test_exp) 循环体部分(body_statement) ...