1. Spring Boot 简介
1.1 Spring 是什么?
Spring 包括了用来简化 java 开发的多种框架,用于不同的场景,其中最为基础的是 Spring Framework,功能有:
-
IoC - 整合其他框架,Spring 两大核心技术之一
-
AOP - 通用操作的横切处理,Spring 两大核心技术之一
-
事务 - 无需编写代码,即可实现数据库事务管理
-
测试 - 与测试框架集成、web 单元测试
-
MVC - 开发 web 应用程序
-
缓存 - 对缓存进行抽象
-
调度 - 延时任务、定时任务
Spring Framework 在开发中的作用:
-
分层解耦 - 让单体应用的可扩展性更强
-
整合框架 - 整合第三方框架,使之协同工作
-
实用技术 - 自身强大,提供各种实用功能
1.2 Spring Boot 是什么?
Spring Boot 可以帮助我们开发【基于Spring的】、【独立的】、【生产级的】应用程序
它的主要目标是:
-
为所有 Spring 开发提供更快的入门体验
-
开箱即用,提供了自动配置
-
提供一系列大型项目通用的非功能性特性
-
外部化配置
-
嵌入式服务器
-
安全性
-
健康检查
-
指标
-
-
完全不需要代码生成,也不需要XML配置
基于版本:2.6.3
1.3Spring核心
一、让Spring容器确定要加载的类
@Component
public class MyService {}
二、获取Spring容器对象
ConfigurableApplicationContext context = SpringApplication.run(DemoApplication.class, args);
三、获取Spring容器管理的对象
MyService myService = context.getBean(MyService.class);
1.4入门案例
Spring Boot 提供了方便的手段来快速生成项目骨架
1)创建新模块
2)输入项目信息
3)选择项目依赖和Springboot的版本
4)创建
5)创建service包,并创建MyService类
@Component
public class MyService {
}
6)在DemoApplication类中编写代码
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
//获取Spring容器
ConfigurableApplicationContext context = SpringApplication.run(DemoApplication.class, args);
//获取容器的对象
System.out.println(context.getBean(MyService.class));
}
}
其中 @SpringBootApplication 代表此类是 Spring Boot 程序的入口,也称为引导类 .
1.5 单元测试
Spring 可以结合 JUnit 完成单元测试,测试用例中也可以利用 @Autowired 来注入待测对象,只要它被 Spring 所管
@SpringBootTest
class DemoApplicationTests {
@Autowired
private MyService myService; // 注入任意由容器管理的对象
@Test
void test1() {
// 使用 service
}
}
容器对象自身也可以使用 @Autowired 注入,容器类型可以使用接口类型:ApplicationContext
@SpringBootTest
class Demo1ApplicationTests {
@Autowired
private ApplicationContext context; // 注入容器自身
@Test
void test2() {
// 使用 context
}
}
2. IoC
2.1 控制反转
刚才解耦的例子中,涉及到 Spring 的两个核心概念
-
把对象的控制权交给容器管理,称之为控制反转
-
建立容器管理对象之间的依赖关系,称之为依赖注入
控制反转:即用容器管理对象。原本由程序(员)干的活:对象创建、生命周期方法调用、读取外部配置等,都交给了容器负责。控制权发生了转移
IoC 容器负责管理:对象的创建权、生命周期、外部配置等
-
未应用 IoC 之前,是我们自己去创建对象、调用它们的初始化方法等
-
应用了 IoC 之后,是由容器来创建和管理对象
1) bean 的扫描
要把某个对象交给 Spring 管理,需要向类上标注如下注解之一
-
@Controller - 把标注的控制器类交给 Spring 管理
-
@Service - 把标注的业务服务类交给 Spring 管理
-
@Repository - 把标注的数据访问类交给 Spring 管理(用得少,因为与 MyBatis 整合)
-
@Component - 不属于上述三类的用此注解
这些注解
-
都是加在类上,不能加在接口上(没有意义)
-
都可以用来指定 bean 的 id,如果没有指定,默认 id 为类名的小驼峰命名,例如 MyService 类的默认 id 为 myService
隐藏的注解 @ComponentScan
-
它被包含在引导类的 @SpringBootApplication 注解内,用来扫描前面的四大注解
-
默认扫描的范围为引导类的所在包内
2) bean 的获取
Spring 容器启动时,会把其中的 bean 都创建准备好,如果想要主动获取这些 bean,可以使用如下方法
-
根据类型获取 bean -
<T> T getBean(Class<T> requiredType)
-
可以传递父类型,返回子类型
-
可以传递接口类型,返回实现类型
-
-
根据 id 获取 bean -
Object getBean(String name)
-
根据 id 获取 bean(带类型转换) -
<T> T getBean(String name, Class<T> requiredType)
getBean 例子
@Component
public class MyService1 {
}
测试
@Test
@DisplayName("测试两种不同 getBean")
public void test01() {
MyService1 bean1 = context.getBean(MyService1.class);
Assertions.assertNotNull(bean1);
MyService1 bean2 = context.getBean("myService1", MyService1.class);
Assertions.assertNotNull(bean2);
}
3) bean 的 scope
Spring 支持五种作用域,后三种在 web 环境才生效
-
singleton - 容器内同 id 的 bean 只有一个实例(默认)
-
prototype - 每次使用该 bean 时会创建新的实例
-
request - 在 web 环境中,每个请求范围内会创建新的实例
-
session - 在 web 环境中,每个会话范围内会创建新的实例
-
application- 在 web 环境中,每个应用范围内会创建新的实例
以上五种作用域,配合 @Scope 注解来进行配置
singleton 例子
@Component
@Scope("singleton") // 不加一样
public class MyService2 {
}
测试1
@Test
@DisplayName("测试 scope=singleton 的特征")
public void test02() {
MyService2 bean1 = context.getBean("myService2", MyService2.class);
MyService2 bean2 = context.getBean("myService2", MyService2.class);
Assertions.assertEquals(bean1, bean2);
}
测试2
@Test
@DisplayName("测试 scope=singleton 的特征(不同容器)")
public void test03() {
ConfigurableApplicationContext context1 = SpringApplication.run(Demo1Application.class);
ConfigurableApplicationContext context2 = SpringApplication.run(Demo1Application.class);
MyService2 bean1 = context1.getBean("myService2", MyService2.class);
MyService2 bean2 = context2.getBean("myService2", MyService2.class);
Assertions.assertNotEquals(bean1, bean2);
}
prototype 例子
@Component
@Scope("prototype")
public class MyService3 {
}
测试
@Test
@DisplayName("测试 scope=prototype 的特征")
public void test04() {
MyService3 bean1 = context.getBean(MyService3.class);
MyService3 bean2 = context.getBean(MyService3.class);
Assertions.assertNotEquals(bean1, bean2);
}
4) bean 的初始化与销毁
-
标注了 @PostConstruct 的方法是初始化方法,会在 bean 被创建之后调用
-
标注了 @PreDestroy 的方法是销毁方法,singleton 的 bean 的销毁方法会在容器关闭前被调用
初始化例子
@Component
public class MyService4 {
private boolean initialized = false;
@PostConstruct
public void init() {
initialized = true;
}
public boolean isInitialized() {
return initialized;
}
}
测试
@Test
@DisplayName("测试 init-method 的特征")
public void test05() {
MyService4 bean = context.getBean(MyService4.class);
Assertions.assertTrue(bean.isInitialized());
}
销毁例子
@Component
public class MyService5 {
private boolean destroyed = false;
@PreDestroy
public void destroy() {
destroyed = true;
}
public boolean isDestroyed() {
return destroyed;
}
}
测试
@Test
@DisplayName("测试 destroy-method 的特征")
public void test06() {
// 当前容器 close 会导致测试错误,因此新建一个容器来测试 close
ConfigurableApplicationContext context = SpringApplication.run(Demo1Application.class);
MyService5 bean = context.getBean(MyService5.class);
context.close();
Assertions.assertTrue(bean.isDestroyed());
}
延迟初始化例子
-
默认情况下 singleton 的 bean 是容器创建时,就会创建
-
如果希望用到时才创建,可以使用
@Lazy
注解标注在类上来延迟创建
@Component
@Lazy
public class MyService6 {
public static boolean isConstructed = false;
public MyService6() {
isConstructed = true;
}
}
5) 管理第三方的 bean
如果要管理的对象来自于第三方,这时是无法用 @Component 等注解来实现的,解决方法要用到 @Bean
管理第三方 bean 例子
已知 DruidDataSource 基本用法如下
1. 创建 druid 连接池对象
DruidDataSource dataSource = new DruidDataSource();
2. 设置连接池属性
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/test?useSSL=false&useUnicode=true&characterEncoding=UTF-8");
dataSource.setUsername("root");
dataSource.setPassword("root");
dataSource.setMaxActive(3);
dataSource.setMinIdle(1);
dataSource.setInitialSize(1);
3. 初始化方法
dataSource.init();
4. 销毁方法
dataSource.close();
尝试用 Spring 管理它,并设置其初始化和销毁方法,连接信息注意改为自己的
1)pom.xml
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.16</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
2)Demo1Application.java
@SpringBootApplication
public class Demo1Application {
@Bean
public DruidDataSource dataSource() {
DruidDataSource dataSource = new DruidDataSource();
// 2. 设置连接池属性
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/aaaa?useSSL=false&useUnicode=true&characterEncoding=UTF-8");
dataSource.setUsername("root");
dataSource.setPassword("1234");
dataSource.setMaxActive(3);
dataSource.setMinIdle(1);
dataSource.setInitialSize(1);
return dataSource;
}
// ...
@Bean 标注的方法放在引导类中,它返回的对象由 Spring 管理,如果未加指定,则使用方法名作为 bean 的 id
3)测试
@Test
@DisplayName("测试 @Bean 的特征")
public void test08() {
System.out.println(context.getBean(DataSource.class));
}
注意
-
对于 @Bean 来说,销毁方法如果不设置,默认会找名为 close 或 shutdown 的方法当做销毁方法
关注我不迷路,持续更新中.....