Spring是什么?
Spring 是目前主流的 Java Web 开发框架,是 Java 世界最为成功的框架。该框架是一个轻量级的开源框架,具有很高的凝聚力和吸引力。
Spring 是分层的 Java SE/EE 一站式轻量级开源框架,以 IoC(Inverse of Control,控制反转)和 AOP(Aspect Oriented Programming,面向切面编程)为内核。
- IoC 指的是将对象的创建权交给 Spring 去创建。使用 Spring 之前,对象的创建都是由我们使用 new 创建,而使用 Spring 之后,对象的创建都交给了 Spring 框架。
- AOP 用来封装多个类的公共行为,将那些与业务无关,却为业务模块所共同调用的逻辑封装起来,减少系统的重复代码,降低模块间的耦合度。另外,AOP 还解决一些系统层面上的问题,比如日志、事务、权限等。
在 Spring 中:
- 认为一切 Java 类都是资源,而资源都是类的实例对象(Bean),容纳并管理这些 Bean 的是 Spring 所提供的 IoC 容器
- Spring 是一种基于 Bean 的编程,它深刻地改变着 Java 开发世界,使用基本的 JavaBean 来完成以前只有 EJB 才能完成的工作,使得很多复杂的代码变得优雅和简洁,避免了 EJB 臃肿、低效的开发模式,极大的方便项目的后期维护、升级和扩展。迅速地取代 EJB 成为了实际的开发标准。
在实际开发中,服务器端通常采用三层体系架构,分别为表现层(web)、业务逻辑层(service)、持久层(dao)。
Spring 致力于 Java EE 应用各层的解决方案,对每一层都提供了技术支持。
- 在表现层提供了与 Spring MVC、Struts2 框架的整合
- 在业务逻辑层可以管理事务和记录日志等,
- 在持久层可以整合 MyBatis、Hibernate 和 JdbcTemplate 等技术。
- 这就充分体现出 Spring 是一个全面的解决方案,对于已经有较好解决方案的领域,Spring 绝不做重复的事情。
Spring的优点:
- Spring是一个免费的开源的框架(容器)
- Spring是一个轻量级的、非入侵式的框架
- 控制反转(IOC)面向切面编程(AOP)
- 支持事务的处理,对框架整合的支持
第一个Spring程序
- 在idea中创建一个普通的Maven项目命名为HelloSpring
- 在pom.xml文件中添加相关依赖:
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>x.x.x</version>
</dependency>
这里导入的spring-webmvc的依赖,足够满足spring所需要的相关的jar包
- 创建一个实体类
public class User {
private String name;
public User(String name){
this.name=name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void show(){
System.out.println("name:"+this.name);
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
'}';
}
}
- 在resource文件夹中创建配置文件bean.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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="user" class="pojo.User">
<!-- 对属性name赋值"HelloSpring"-->
<property name="name" value="HelloSpring"/>
</bean>
</beans>
你也可以将该配置文件命名为其它有效的名称。需要注意的是,该文件名必须与下面 Test.java 中读取的配置文件名称一致。
beans.xml 用于给不同的 Bean 分配唯一的 ID,并给相应的 Bean 属性赋值。例如,在以上代码中,我们可以在不影响其它类的情况下,给 name变量赋值。
- 编写测试文件测试文件Test.java
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import pojo.User;
public class Test {
public static void main(String[] args) {
//获取spring的上下文对象
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
//对象都在spring容器中管理,使用直接从里面取出即可
User user = (User) context.getBean("user");
user.show();
}
}
需要注意以下两点:
- 创建 ApplicationContext 对象时,我们使用了 ClassPathXmlApplicationContext 类。该类用于加载 Spring 配置文件、创建和初始化所有对象,也就是配置文件中提到的 Bean。
- ApplicationContext.getBean() 方法用来获取 Bean,该方法返回值类型为 Object,通过强制类型转换为实体类的实例对象,根据该对象调用类中的方法。
运行Test文件执行结果为
至此,我们就成功创建了第一个 Spring 应用程序。
SpringIoC容器
IoC 容器是 Spring 的核心,也可以称为 Spring 容器。Spring 通过 IoC 容器来管理对象的实例化和初始化,以及对象从创建到销毁的整个生命周期。
Spring 中使用的对象都由 IoC 容器管理,不需要我们手动使用 new 运算符创建对象。由 IoC 容器管理的对象称为 Spring Bean,Spring Bean 就是 Java 对象,和使用 new 运算符创建的对象没有区别。
Spring 通过读取 XML 或 Java 注解中的信息来获取哪些对象需要实例化。
Spring 提供 2 种不同类型的 IoC 容器
- BeanFactory
简单来说,BeanFactory 就是一个管理 Bean 的工厂,它主要负责初始化各种 Bean,并调用它们的生命周期方法。 - ApplicationContext
ApplicationContext 继承了 BeanFactory 接口,在 BeanFactory 的基础上增加了很多企业级功能,例如 AOP、国际化、事件支持等。
需要注意的是,BeanFactory 和 ApplicationContext 都是通过 XML 配置文件加载 Bean 的。
二者的主要区别在于,如果 Bean 的某一个属性没有注入,使用 BeanFacotry 加载后,第一次调用 getBean() 方法时会抛出异常,而 ApplicationContext 则会在初始化时自检,这样有利于检查所依赖的属性是否注入。
因此,在实际开发中,通常都选择使用 ApplicationContext,只有在系统资源较少时,才考虑使用 BeanFactory。
SpringBean解析
由 Spring IoC 容器管理的对象称为 Bean,Bean 根据 Spring 配置文件中的信息创建。
Spring 配置文件支持两种格式,即 XML 文件格式和 Properties 文件格式。
- Properties 配置文件主要以 key-value 键值对的形式存在,只能赋值,不能进行其他操作,适用于简单的属性配置。
- XML 配置文件是树形结构,相对于 Properties 文件来说更加灵活。XML 配置文件结构清晰,但是内容比较繁琐,适用于大型复杂的项目。
通常情况下,Spring 的配置文件使用 XML 格式。XML 配置文件的根元素是 <beans>
,该元素包含了多个子元素 。每一个 <bean>
元素都定义了一个 Bean,并描述了该 Bean 如何被装配到 Spring 容器中。
例如:上面的bean.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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="user" class="pojo.User">
<!-- 对属性name赋值"HelloSpring"-->
<property name="name" value="HelloSpring"/>
</bean>
</beans>
使用 id 属性定义了 Bean,并使用 class 属性指定了 Bean 对应的类。
Spring依赖注入
Spring 依赖注入(Dependency Injection,DI)和控制反转含义相同,它们是从两个角度描述的同一个概念。使用依赖注入可以更轻松的管理和测试应用程序。
-
控制反转:当某个 Java 实例需要另一个 Java 实例时,传统的方法是由调用者创建被调用者的实例(例如,使用 new 关键字获得被调用者实例),而使用 Spring 框架后,被调用者的实例不再由调用者创建,而是由 Spring 容器创建。
-
依赖注入:Spring 容器在创建被调用者的实例时,会自动将调用者需要的对象实例注入给调用者,调用者通过 Spring 容器获得被调用者实例。
依赖注入主要有两种实现方式,分别是 setter 注入(又称设值注入)和构造函数注入。具体介绍如下。
- 构造函数注入
指 IoC 容器使用构造函数注入被依赖的实例。可以通过调用带参数的构造函数实现依赖注入,每个参数代表一个依赖。
使用构造注入时,在配置文件中,主要使用 <constructor-arg>
标签定义构造方法的参数,使用其 value 属性(或子元素)设置该参数的值。
- setter 注入
指 IoC 容器使用 setter 方法注入被依赖的实例。通过调用无参构造器或无参 static 工厂方法实例化 Bean 后,调用该 Bean 的 setter 方法,即可实现基于 setter 的 DI。
在 Spring 实例化 Bean 的过程中,首先会调用默认的构造方法实例化 Bean 对象,然后通过 Java 的反射机制调用 setXxx() 方法进行属性的注入。
因此,setter 注入要求 Bean 的对应类必须满足以下两点要求。- 必须提供一个默认的无参构造方法。
- 必须为需要注入的属性提供对应的 setter 方法。
使用 setter 注入时,在 Spring 配置文件中,需要使用 <bean>
元素的子元素 <property>
为每个属性注入值。
下面演示setter注入
使用 标签实现 setter 注入。
- 在 标签中,包含 name、ref、value 等属性。
- name 用于指定参数名称;
- value 属性用于注入基本数据类型以及字符串类型的值;
- ref 属性用于注入已经定义好的 Bean。
- 创建两个实体类Student,Address
import java.util.*;
public class Student {
private Address address;
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
@Override
public String toString() {
return "Student{" +
"address=" + address.getAddress() +
'}';
}
}
public class Address {
private String address;
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
- 编写bean.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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 将address类放入Spring容器中交由spring管理-->
<bean id="address" class="pojo.Address">
<property name="address" value="北京"/>
</bean>
<bean id="student" class="pojo.Student">
<!-- 类注入-->
<property name="address" ref="address"/>
</bean>
</beans>
运行结果为:Student{ address="北京"}
Spring注入集合
如果需要传递类似于 Java Collection 类型的值,例如 List、Set、Map 和 properties,可以使用 Spring 提供的集合配置标签
标签 | 说明 |
---|---|
<list> | 用于注入 list 类型的值,允许重复 |
<set> | 用于注入 set 类型的值,不允许重复 |
<map> | 用于注入 key-value 的集合,其中 key-value 可以是任意类型 |
<props> | 用于注入 key-value 的集合,其中 key-value 都是字符串类型 |
示例:
- 创建实体类Student
import java.util.*;
public class Student {
private String[] book;
private List<String> hobbies;
private Map<String,String> card;
private Set<String> games;
private Properties info;
public String[] getBook() {
return book;
}
public void setBook(String[] book) {
this.book = book;
}
public List<String> getHobbies() {
return hobbies;
}
public void setHobbies(List<String> hobbies) {
this.hobbies = hobbies;
}
public Map<String, String> getCard() {
return card;
}
public void setCard(Map<String, String> card) {
this.card = card;
}
public Set<String> getGames() {
return games;
}
public void setGames(Set<String> games) {
this.games = games;
}
public Properties getInfo() {
return info;
}
public void setInfo(Properties info) {
this.info = info;
}
@Override
public String toString() {
return "Student{" +
", book=" + Arrays.toString(book) +
", hobbies=" + hobbies +
", card=" + card +
", games=" + games +
", info=" + info +
'}';
}
}
- 编写bean.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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="student" class="pojo.Student">
<!-- 数组注入-->
<property name="book">
<array>
<value>红楼梦</value>
<value>三国演义</value>
<value>水浒传</value>
<value>西游记</value>
</array>
</property>
<!-- list注入-->
<property name="hobbies">
<list>
<value>dayouxi</value>
</list>
</property>
<!-- Map类型数据注入-->
<property name="card">
<map>
<entry key="账号:" value="723657832678"/>
<entry key="密码:" value="238748923989"/>
</map>
</property>
<!-- set类型数据注入-->
<property name="games">
<set>
<value>cf</value>
<value>lol</value>
</set>
</property>
<property name="info">
<props>
<prop key="username">小明</prop>
<prop key="password">823748</prop>
</props>
</property>
</bean>
</beans>
- 测试类文件
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import pojo.Student;
public class Test {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
Student student = (Student) context.getBean("student");
System.out.println(student.toString());
}
}
运行结果为:
注入null和空字符串的值
Spring 会把属性的空参数直接当成空字符串来处理,如果您需要传递一个空字符串值,可以这样写:
<bean id = "..." class = "exampleBean">
<property name = "name" value = ""/>
</bean>
如果需要传递 NULL 值,<null/>
元素用来处理 Null 值。
<bean id = "..." class = "exampleBean">
<property name = "name">
<null/>
</property>
</bean>