# Spring 快速入门
# 1. 介绍
# 1.1. 为什么要学
- 简化开发
- 框架整合
# 1.2. 初识 Spring
全家桶:
- Spring Framework - 底层框架
- Spring Boot
- Spring Cloud
- ...
Spring 5:
- 全面支持 JDK8
# 1.3. 核心概念
概念:
- IOC / DI
- IoC 容器
- Bean
IoC:
- Inversion of Control, 控制反转,是思想
- 不主动 new 对象,由外部创建对象
IoC 容器:
- 充当 IoC 思想的 “外部”
- 容器里面创建、管理的对象,叫做 bean
DI:
- Dependency Injection, 依赖注入
- 在容器中建立 bean 与 bean 之间的依赖关系的过程,称为依赖注入
目标:充分解耦
- 使用 IoC 容器管理 bean (IoC)
- 在 IoC 容器内将有依赖关系的 bean 进行关系绑定 (DI)
最终效果
- 使用对象时不仅可以直接从 IoC 容器中夫取,并且获取到的 bean 已经绑定了所有的依赖关系
# 2. IoC
# 2.1. 入门案例
目录:
project/
src/main/
java/
org.example/
dao/
BookDao.java
impl/
BookDaoImpl.java
service/
BookService.java
impl/
BookServiceImpl.java
App.java
resources/
applicationContext.xml
文件:
App.java:
package org.example; import org.example.service.BookService; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class App { public static void main( String[] args ) { ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); BookService bookService = (BookService) ctx.getBean("bookService"); bookService.save(); } }
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" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="bookDao" class="org.example.dao.impl.BookDaoImpl"/> <bean id="bookService" class="org.example.service.impl.BookServiceImpl"> <property name="bookDao" ref="bookDao"/> </bean> </beans>
BookService.java
package org.example.service; public interface BookService { void save(); }
BookServiceImpl.java
package org.example.service.impl; import org.example.dao.BookDao; import org.example.service.BookService; public class BookServiceImpl implements BookService { private BookDao bookDao; public void save() { System.out.println("BookServiceImpl: save()!"); bookDao.save(); } public void setBookDao(BookDao bookDao) { this.bookDao = bookDao; } }
BookDao.java
package org.example.dao; public interface BookDao { void save(); }
BookDaoImpl.java
package org.example.dao.impl; import org.example.dao.BookDao; public class BookDaoImpl implements BookDao { public void save() { System.out.println("BookDaoImpl save!"); } }
# 2.2. bean 配置
别名:
- 属性:
name
- 说明: 可定义多个,用 逗号、分号、空格 分隔
- 示例:
<bean name="service, bookServiceImpl" />
作用范围:
- 属性:
scope
- 说明:
singleton
(单例、默认),prototype
(非单例) - 示例:
<bean ... scope="prototype">
# 2.3. 实例化 bean 的四种方式
默认构造函数
/* <bean id="bookDao" class="org.example.dao.impl.bookDaoImpl" /> */ public class BookDaoImpl implements BookDao { public void save() { System.out.println("BookDaoImpl save!"); } }
静态工厂
/* <bean id="orderDaoFactory" class="org.example.factory.OrderDaoFactory" factory-method="getOrderDao" /> */ public class OrderDaoFactory { public static OrderDao getOrderDao() { return new OrderDaoImpl(); } }
实例工厂
/* <bean id="userDao" factory-method="getUserDao" factory-bean="org.example.factory.userDaoFactory" /> */ public class UserDaoFactory { public UserDao getUserDao() { return new UserDaoImpl(); } }
实例工厂(FactoryBean)
/* <bean id="userDao" class="org.example.factory.UserDaoFactoryBean" /> */ public class UserDaoFactoryBean implements FactoryBean<UserDao> { public UserDao getObject() throws Exception { return new UserDaoImpl(); } public Class<?> getObjectType() { return UserDao.class; } }
# 2.4. bean 生命周期
生命周期:
初始化容器
- 创建对象(内存分配)
- 执行构造方法
- 执行属性注入(set 操作)
- 执行 bean 初始化方法
使用 bean
- 执行业务操作
关闭/销毁容器
- 执行 bean 销毁方法
生命周期方法:
方式一:
/* <bean id="bookService" class="org.example.service.impl.BookServiceImpl" init-method="init" destroy-method="destory"> </bean> */ public class BookServiceImpl implements BookService { public void init() { System.out.println("init"); } public void destory() { System.out.println("destory"); } }
方式二:
/* <bean id="bookService" class="org.example.service.impl.BookServiceImpl"> </bean> */ public class BookServiceImpl implements BookService, InitializingBean, DisposableBean { public void afterPropertiesSet() throws Exception { System.out.println("init2"); } public void destroy() throws Exception { System.out.println("destory2"); } }
关闭容器的方法:
手动关闭
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); ctx.close();
注册关闭钩子
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); ctx.registerShutdownHook();
# 3. DI
# 3.1. 依赖注入方式
setter 注入
- 简单类型
- 引用类型
构造器注入
- 简单类型
- 引用类型
# 3.1.1. setter 注入
注入简单类型:
/*
<bean
id="bookService"
class="org.example.service.impl.BookServiceImpl"
>
<property name="id" value="abc" />
<property name="total" value="100" />
</bean>
*/
public class BookServiceImpl {
private int total;
private String id;
public void setTotal(int total) {
this.total = total;
}
public void setId(String id) {
this.id = id;
}
}
注入引用类型:
/*
<bean id="bookDao" class="org.example.dao.impl.BookDaoImpl"/>
<bean
id="bookService"
class="org.example.service.impl.BookServiceImpl"
>
<property name="bookDao" ref="bookDao"/>
</bean>
*/
public class BookServiceImpl implements BookService {
private BookDao bookDao;
public void setBookDao(BookDao bookDao) {
this.bookDao = bookDao;
}
}
# 3.1.2. 构造器注入
示例:
/*
<bean id="bookDao" class="org.example.dao.impl.BookDaoImpl"/>
<bean
id="bookService"
class="org.example.service.impl.BookServiceImpl"
>
<constructor-arg name="bookDao" ref="bookDao"/>
<constructor-arg name="id" value="xyz" />
<constructor-arg name="total" value="123" />
</bean>
*/
public class BookServiceImpl implements BookService {
private BookDao bookDao;
private int total;
private String id;
public BookServiceImpl(BookDao bookDao, int total, String id) {
this.bookDao = bookDao;
this.total = total;
this.id = id;
}
}
# 3.1.3. 总结
依赖注入方式选择:
- 强制依赖 使用构造器注入
- setter 注入有概率不进行注入 导致 nu11 对象出现;
- 可选依赖使用 setter 注入进行,灵活性强;
- Spring 框架推荐使用构造器注入,第三方框架背部大多数采用构造器注入的形式进行数据初始化,相对严谨;
- 如果有必要可以两者同时使用,使用构造器入完成强制依赖的注入,使用 setter 注入完成可选依赖的注入;
- 实际开发过程中还要根据实际情况分析,如果受控对象没有提供 setter 方法就必须使用构造器注入;
- 自己开发的模块推荐使用 setter 注入
# 3.2. 依赖自动装配
# 3.2.1. 说明
自动装配:
- IoC 容器根据 bean 所依赖的资源 在容器中自动查找 并注入到 bean 中的过程称为自动装配
自动装配方式:
- 按类型(常用)
- 按名称
- 按构造方法
- 不启用自动装配
# 3.2.2. 按类型
示例:
/*
<bean class="org.example.dao.impl.BookDaoImpl" />
<bean
id="bookService"
class="org.example.service.impl.BookServiceImpl"
autowire="byType"
/>
*/
public class BookServiceImpl implements BookService {
private BookDao bookDao;
public void setBookDao(BookDao bookDao) {
this.bookDao = bookDao;
}
}
# 3.2.3. 按名称
示例:
/*
<bean
id="bookDao"
class="org.example.dao.impl.BookDaoImpl"
/>
<bean
id="bookService"
class="org.example.service.impl.BookServiceImpl"
autowire="byName"
/>
*/
public class BookServiceImpl implements BookService {
private BookDao bookDao;
public void setBookDao(BookDao bookDao) {
this.bookDao = bookDao;
}
}
# 3.2.4. 注意
- 自动装配用于引用类型依注入,不能对简单类型进行操作
- 使用按类型装配时(
byType
) 必须保障容器中相同类型的 bean 唯一,推荐使用 - 使用按名称装配时(
byName
) 必须保障容器中具有指定名称的 bean,因变量名与配置耦合,不推荐使用 - 自动装配优先级低于 setter注入 与 构造器注入,同时出现时自动装配配置失效
# 3.3. 集合注入
集合:
- Array
- List
- Set
- Map
- Properties
示例:
/*
<bean id="bookService" class="org.example.service.impl.BookServiceImpl">
<property name="myArray">
<array>
<value>1</value>
<value>2</value>
<value>3</value>
</array>
</property>
<property name="myList">
<list>
<value>list1</value>
<value>list2</value>
<value>list3</value>
</list>
</property>
<property name="mySet">
<set>
<value>set1</value>
<value>set2</value>
<value>set3</value>
</set>
</property>
<property name="myMap">
<map>
<entry key="key1" value="val1" />
<entry key="key2" value="val2" />
<entry key="key3" value="val3" />
</map>
</property>
<property name="myProperties">
<props>
<prop key="prop1">value1</prop>
<prop key="prop2">value2</prop>
<prop key="prop3">value3</prop>
</props>
</property>
</bean>
*/
public class BookServiceImpl implements BookService {
private int[] myArray;
private List<String> myList;
private Set<String> mySet;
private Map<String, String> myMap;
private Properties myProperties;
public void setMyArray(int[] myArray) {
this.myArray = myArray;
}
public void setMyList(List<String> myList) {
this.myList = myList;
}
public void setMySet(Set<String> mySet) {
this.mySet = mySet;
}
public void setMyMap(Map<String, String> myMap) {
this.myMap = myMap;
}
public void setMyProperties(Properties myProperties) {
this.myProperties = myProperties;
}
public void save() {
System.out.println("myArray: " + Arrays.toString(myArray));
System.out.println("myList: " + myList);
System.out.println("mySet: " + mySet);
System.out.println("myMap: " + myMap);
System.out.println("myProperties: " + myProperties);
}
}
# 3.4. 读取 properties 文件
步骤:
开启 context 命名空间:
<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/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd " >
加载配置文件
<!-- jdbc.username=root jdbc.password=123456 --> <context:property-placeholder location="jdbc.properties" /> <bean id="bookService" class="org.example.service.impl.BookServiceImpl"> <property name="username" value="${jdbc.username}"/> </bean>
注意:
<!--
不加载系统属性,当 properties 文件中的 key 与环境变量冲突的情况
-->
<context:property-placeholder location="jdbc.properties" system-properties-mode="NEVER" />
<!--
加载多个 properties 文件, 逗号分隔
-->
<context:property-placeholder location="jdbc.properties,xyz.properties" />
<!--
加载当前项目下所有 properties 文件
-->
<context:property-placeholder location="*.properties" />
<!--
加载当前项目下所有 properties 文件, 标准格式
-->
<context:property-placeholder location="classpath:*.properties" />
<!--
加载当前项目及依赖的 jar 包中的所有 properties 文件
-->
<context:property-placeholder location="classpath*:*.properties" />
# 3.5. 容器
创建容器的方式:
ClassPathXmlApplicationContext
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
FileSystemXmlApplicationContext
ApplicationContext ctx = new FileSystemXmlApplicationContext("W:\\spring_07_container\\src\\main\\resources\\applicationContext.xml");
获取 bean 的方式:
名称 + 强转
BookService bookService = (BookService) ctx.getBean("bookService");
名称 + 类型
BookService bookService = ctx.getBean("bookService", BookService.class);
类型
BookService bookService = ctx.getBean(BookService.class);
BeanFactory:
- IoC 容器的顶层接口
- 加载的 bean 默认延迟加载
# 4. 注解开发
# 4.1. 注解开发定义 bean
说明:
- Spring 2.0 开启注解功能,通过注解配置 bean
步骤:
配置文件(
applicationContext.xml
)中设置组件扫描加载 bean<beans ...> <!-- base-package: 扫描当前包及其所有后代包 --> <context:component-scan base-package="org.example" /> </beans>
使用
@Component
定义 bean@Component("bookService") public class BookServiceImpl implements BookService { public void save() { System.out.println("BookServiceImpl.save()"); } } @Component public class BookDaoImpl implements BookDao { public void save() { System.out.println("BookDaoImpl.save()"); } } public class App { public static void main( String[] args ) { ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); BookService bookService = (BookService) ctx.getBean("bookService"); bookService.save(); BookDao bookDao = ctx.getBean(BookDao.class); bookDao.save(); } }
Spring 提供 @Component 注解的三个衍生注解(功能完全一致):
- @Controller: 表现层 bean
- @Service: 业务层 bean
- @Repository: 数据层 bean
# 4.2. 纯注解开发
说明:
- Spring 3.0 升级了纯注解开发模式,使用 Java 类替代配置文件
步骤:
配置类:
// 替代 <beans></beans> @Configuration // 替代 <context:component-scan base-package="org.example" /> @ComponentScan({"org.example.dao", "org.example.service"}) public class SpringConfig { }
容器类
public class App { public static void main( String[] args ) { ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class); BookService bookService = (BookService) ctx.getBean("bookService"); bookService.save(); BookDao bookDao = ctx.getBean(BookDao.class); bookDao.save(); } }
# 4.3. bean 管理
bean 作用范围:
- @Scope
bean 生命周期:
- @PostConstruct
- @PreDestroy
示例:
@Component
// @Scope("prototype") // 非单例
@Scope("singleton") // 单例,默认
public class BookDaoImpl implements BookDao {
// 构造之后
@PostConstruct
public void init() {
System.out.println("init()");
}
// 销毁之前
@PreDestroy
public void destroy() {
System.out.println("destroy()");
}
public void save() {
System.out.println("BookDaoImpl.save()");
}
}
public class App {
public static void main( String[] args ) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
System.out.println(ctx.getBean(BookDao.class));
System.out.println(ctx.getBean(BookDao.class));
ctx.close();
}
}
# 4.4. 依赖注入
自动装配:
@Autowired
: 按类型自动装配@Qualifier("bookDaoImpl2")
: 按名称装配,需配合@Autowired
使用@Value
: 注入简单类型
读取 properties 文件:
@PropertySource("jdbc1.properties", ...)
:
示例:
@Configuration
@ComponentScan({"org.example.dao", "org.example.service"})
@PropertySource({"user.properties"})
public class SpringConfig {
}
/*
# src/main/resources/user.properties
age=18
*/
@Service
public class BookServiceImpl implements BookService {
@Autowired
@Qualifier("bookDaoImpl2")
private BookDao bookDao;
@Value("张三")
private String name;
@Value("${age}")
private String age;
public void save() {
System.out.println("BookServiceImpl.save()");
bookDao.save();
System.out.println("name=" + name);
System.out.println("age=" + age);
}
}
# 4.5. 第三方 bean 管理
第三方 bean 管理:
定义 bean
/* <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.16</version> </dependency> */ public class JdbcConfig { // 1. 定义一个方法,返回要管理的对象 // 2. 添加 @Bean,标记返回的对象是一个 bean @Bean public DataSource dataSource() { DruidDataSource ds = new DruidDataSource(); ds.setDriverClassName("com.mysql.jdbc.Driver"); ds.setUrl("jdbc:mysql://localhost:3306/spring_db"); ds.setUsername("root"); ds.setPassword("root"); return ds; } }
导入 bean
@Configuration @Import({JdbcConfig.class}) public class SpringConfig { }
第三方 bean 依赖注入:
public class JdbcConfig {
// 通过成员变量,注入简单类型
@Value("com.mysql.jdbc.Driver")
private String driverClass;
// 通过方法参数,注入引用类型 (按类型自动装配)
@Bean
public DataSource dataSource(BookDao bookDao) {
System.out.println(bookDao);
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName(driverClass);
return ds;
}
}
# 4.6. 注解开发总结
XML 配置 VS 注解配置
定义 bean:
XML 配置:
<bean id="xx" class="xx">
注解配置:
@Component
(@Controller
/@Service
/@Repository
)@ComponentScan
依赖注入:
XML 配置:
- setter 注入
- 构造器注入
- 自动装配
注解配置:
@Autowired
(@Qualifier
)@Value
第三方 bean:
XML 配置:
- 静态工厂
- 实例工厂
注解配置:
@Bean
作用范围:
XML 配置:
- scope 属性
注解配置:
@Scope
生命周期:
XML 配置:
- 标准接口
init-method
/destroy-method
注解配置:
@PostConstructor
@PreDestroy
# 5. Spring 整合 MyBatis
上一篇: 下一篇: