张皓岚
1.spring 2天
2.单体项目 10天
3.微服务项目 9天
本阶段大部分时间是做项目
老师带着做,同学们可以跟着做一遍
课下至少再做两遍
Spring Boot 和 Spring Mvc
- SpringMvc的功能
M(Model)模型:java中的实体类
V(View)视图:项目中的html页面
C(Controller)控制器:controller包中的控制器类
SpringMvc主要实现了V和C之间的数据传递和交互
像控制类中使用的注解,大部分是SpringMvc框架的
- Spring Boot的功能
boot:启动
SpringBoot就是spring框架提供的一种标准的启动方式
而这个启动方式必须在特定的格式下运行
1.SpringBoot是一定包含maven架构的
2.SpringBoot中添加maven依赖是可以包含配置信息的
在项目的开发中,能够减少大量配置信息,方便程序员开发
3.在使用SpringBoot启动项目时,会按照固定的格式读取配置信息,会在固定的位置保存静态资源,每个使用SpringBoot框架的项目整体都是标准一致的
Spring 框架
什么是Spring
Spring框架是SpringMvc和SpringBoot等很多SpringXXX框架的根框架
既由Spring开头命名的框架都是由Spring框架衍生\扩展\进化而来的
所以我们要学习Spring框架到底有什么功能
但是Spring框架本身的功能并不复杂,核心功能只有两个
1.Ioc(DI)
2.Aop
我们Spring课程前两天只讲Ioc(DI)
Aop放在课程最后一天讲
Ioc概念
Ioc(Inversion of Control)直接翻译为"控制反转"
- 我们之前所编写的程序都是使用"主动控制"思想,程序运行过程中,需要什么我们就实例化什么
在实际情况下,实例化简单对象使用主动控制思想没有任何问题
但是如果我们需要实例化复杂对象,并为各组件赋值时,代码会比较臃肿
- 控制反转:我们在编写程序之前,事先将需要的所有对象保存在"外部容器",而"外部容器"可以完成对象和相关组件拼装或赋值的过程,在需要时直接从"外部容器"中获得拼装赋值完成的对象,从而省去实例化\赋值\拼装对象的过程
简单来说,"外部容器"就是Spring
就是当我们需要什么类型的对象时,直接向Spring来索取
Spring会按照设置好的规则,将各个组件拼装赋值完成后,将成品直接返回给我们
第一个Ioc程序
创建一个maven项目
项目名称SpringTest
需要在pom.xml文件中添加Spring的依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>SpringTest</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<!-- Spring Context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.2.RELEASE</version>
</dependency>
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.3.2</version>
</dependency>
</dependencies>
</project>
完成依赖之后
我们开始编写Ioc的程序
可以分为3个步骤
1.定义要保存的类
2.编写代码,将这个类的对象保存到Spring容器
3.编写代码从Spring容器中获得该对象
定义Stu类
创建cn.tedu.stu包
包中创建Stu类,代码如下
public class Stu {
private Integer id;
private String name;
private String gender; //性别
// getters\setters\toString略
}
将Stu类对象保存到Spring容器
我们先使用@Bean的方式将对象保存在Spring容器中
先创建一个StuConfig类,进行配置
代码编写如下
// 建议遵循Spring框架规范
// 在配置类上添加@Configuration注解,表示当前类是spring的配置类
@Configuration
public class StuConfig {
// @Bean注解下面要编写一个方法
// 这个方法的返回值会保存到Spring容器中
// 这个方法的方法名会作为这个对象的唯一标识名称保存在Spring容器
// 我们也可以将这个名称称之为这个对象的id\name
@Bean
public Stu stu(){
// 实例化一个Stu对象,赋值属性之后返回,就能保存到Spring容器
Stu s=new Stu();
s.setId(1);
s.setName("猪八戒");
s.setGender("男");
return s;
}
}
从Spring容器中获得对象
定义一个包含main方法的类
在main方法中实例化Spring容器,并从中获得stu对象
代码如下
public static void main(String[] args) {
// 程序运行
// 先实例化\初始化Spring容器对象
AnnotationConfigApplicationContext acac=
new AnnotationConfigApplicationContext(StuConfig.class);
// acac对象实例化时需要传入配置类的反射做参数
// 这样acac对象实例化时,就可以按照配置类中的配置信息
// 将指定的对象保存在Spring容器中了
// 从Spring容器中获得配置类中保存的对象
Stu ss=acac.getBean("stu",Stu.class);
System.out.println(ss);
acac.close();
}
Git地址
https://gitee.com/jtzhanghl/spring2111.git
使用Junit测试
上面章节中,我们成功的完成了SpringIoc的第一个程序
下面我们继续学习的过程中需要反复运行多次ioc程序
需要很多运行和测试的代码
每个类只能定义一个main方法,测试较多的话,类的数量就会多
会造成代码冗余
Junit进行运行和测试能够减少这些冗余,实现一个类中多个可运行的方法
Junit翻译为Java 单元测试
要想使用还是需要先添加依赖
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13</version>
</dependency>
下面我们就可以在Junit环境中进行测试了
在src\test\java文件及中创建cn.tedu.stu包
包中创建JunitTest类(测试类名不能直接叫Test)
代码如下
public class JunitTest {
// Junit支持测试方法在运行之前或之后运行额外代码
// 以减少每次测试都要运行的代码冗余的情况
// 这样的话 acac对象就变成了多个方法需要使用的对象,
// 我们将它声明为成员变量(属性)
AnnotationConfigApplicationContext acac;
// 定义每个测试方法运行之前都会运行的方法
// @Before注解标记的方法会在@Test方法运行前运行
@Before
public void init(){
// 在@Test方法运行前实例化ACAC
acac=new AnnotationConfigApplicationContext(StuConfig.class);
System.out.println("init方法运行");
}
@After
public void destroy(){
// 在@Test方法运行之后运行,将acac资源关闭回收
acac.close();
System.out.println("destroy方法运行");
}
// 定义一个测试类
// 使用@Test标记,这个方法就能直接运行了
// 方法返回值void,方法名随意
@Test
public void stu(){
// AnnotationConfigApplicationContext acac=
// new AnnotationConfigApplicationContext(StuConfig.class);
Stu s=acac.getBean("stu",Stu.class);
System.out.println(s);
// acac.close();
}
}
课上作业
完成Teacher类的Ioc
创建cn.tedu.teacher包
包中创建Teacher类.属性可以和Stu类一致(或做合理修改)
再创建TeacherConfig使用@Bean注解向Spring容器保存一个老师对象
创建测试类的cn.tedu.teacher包
创建测试类TeacherTest,在类中编写方法获得Spring容器中的老师对象
可以使用@Before和@After注解实现运行前后的代码复用工作
组件扫描方式实现Ioc
上面章节我们一直使用@Bean注解的方式来将对象保存到Spring容器
下面我们开始学习一种新的方法
在创建一个新包cn.tedu.cat包
新建Cat类
代码如下
// 组件扫描方式实现保存到Spring容器
// 第一步是在类上添加@Component注解,Component意思是组件
@Component
public class Cat {
private String name;
private String color;
private Integer age;
// 其它代码略
}
上面代码相当于定义了"组件"
下面就要在配置类进行"扫描"
同包中创建配置类CatConfig
代码如下
@Configuration
//@ComponentScan注解,指定组件扫描的包
// 指定包中的所有类和子孙包中的所有类都会被扫描
// 如果被扫描的类上带有@Component注解,那么这个类就会被实例化并保存到Spring容器
// 这个对象在Spring容器中的id是当前类名首字母小写的字符串 Cat->cat
@ComponentScan("cn.tedu.cat")
public class CatConfig {
}
要想获得Spring容器中组件扫描方式保存的对象
具体代码和@Bean方式是没有区别的
在test\java测试文件夹创建cn.tedu.cat包
编写CatTest测试类代码如下
public class CatTest {
AnnotationConfigApplicationContext acac;
@Before
public void init(){
acac=new AnnotationConfigApplicationContext(CatConfig.class);
}
@After
public void destroy(){
acac.close();
}
@Test
public void cat(){
Cat cat=acac.getBean("cat",Cat.class);
System.out.println(cat);
}
}
本次测试运行输出结果:cat对象所有属性都是null
这也是@Bean方式保存到Spring容器和组件扫描方式保存到Spring容器的主要区别
如果希望组件扫描的对象能够属性有初值,只能在类中为其赋值
- 在属性上直接赋值
- 编写一个构造方法,在构造方法中赋值
组件扫描注意事项
在使用组件扫描保存对象到Spring容器的过程中,有一些细节是需要注意的
实现定义组件的多个注解
我们在上面章节学习时使用@Component注解来定义当前组件
实际上还有多个注解也有相同的功能,比较常用的有:
- @Controller:控制器
- @Service:业务逻辑
- @Repository:数据仓库
- @Component:组件
它们的区别仅仅是语义的区别
方便程序员在阅读代码时直接明确当前类的功能和程序的大体作用
自定义Spring容器id
我们之前学习了@Bean保存到Spring容器的方式
这个方式我们可以通过修改方法名来修改保存到Spring容器中对象的id
但是组件扫描方式Spring容器中对象的id是默认的
如果有修改的必要怎么去修改呢?
@Component("hehe")
public class Cat {
//....
}
组件扫描生成对象id的特殊情况
一般情况下
没有自定义id的对象会使用当前类类名首字母小写的字符串做id名称
例如
Cat -> cat
Dog -> dog
但是,如果类名是连续的两个或两个以上的大写字母开头,就没有这个变化了
会使用原类名做Spring容器中对象的id
例如
VIPStu -> VIPStu 不变
Spring Bean 管理
Bean其实就是Spring容器中保存的java对象
Bean管理就是对Spring容器中保存的对象的管理和配置
以达到各种场景下都可以以最合理的方式使用的目的
Bean的作用域
什么是作用域
作用域英文Scope
Bean的作用域就是指
Spring容器中某个id的对象在被多次获取时,返回的是同一个对象还是新对象
Spring 在设计这个需求时,分别设置了两个作用域来对应
- singleton(单例):Spring容器中多次获取相同id的对象时,获取的是同一个对象
- prototype(原型):Spring容器中多次获取相同id的对象时,每次获取都能获得一个新的对象
单例作用域
Spring框架默认情况下,保存到Spring容器中的对象就是单例的
我们可以通过代码来验证一下
@Test
public void singleton(){
// 单例作用域获得两次teacher对象的运行结果
Teacher t1=acac.getBean("teacher",Teacher.class);
Teacher t2=acac.getBean("teacher",Teacher.class);
t1.setName("小苍苍");
System.out.println(t2);
System.out.println(t1==t2);
}
运行结果
Teacher{id=1001, name='小苍苍', gender='男', major='java'}
true
由此证明,Spring框架默认情况下,容器中的同一id的对象多次被获取,返回的对象时同一引用的
这就"单例"作用域的特征
原型作用域
下面来了解原型作用域的设置和运行特征
@Bean方式设置为原型作用域
@Bean
@Scope("prototype")
组件扫描
@Component
@Scope("prototype")
设置完原型作用域
在对应的测试类中进行测试
@Test
public void prototype(){
// 原型作用域测试,每次获得相同id的对象都是新对象
Cat c1=acac.getBean("cat",Cat.class);
Cat c2=acac.getBean("cat",Cat.class);
c1.setColor("白");
System.out.println(c1);
System.out.println(c2);
System.out.println(c1==c2);
}
运行结果
Cat{name='小白', color='白', age=5}
Cat{name='小白', color='黑', age=5}
false
由此得知
在原型作用域下,c1和c2分别引用了不同的对象
所以修改c1并不会影响c2的属性值
Bean的惰性初始化
Spring中另外一个比较重要的Bean管理就是"惰性初始化"
惰性初始化也有个别名"懒加载"
什么是惰性初始化
指Spring容器中单例作用域的对象
是通过设置来修改实例化当前对象时机的配置
一种时机是在Spring容器实例化时就实例化当前对象
另一种时机是在Spring容器对象获得该对象时再实例化
为什么需要惰性初始化
程序的一次完整的执行可能需要很多Spring容器中的组件
如果有一个比较消耗内存的对象保存到了Spring容器,但是运行程序时没有使用到这个对象,那么这个对象占用的系统资源就白白浪费了
我们将这个对象设置为需要的时候再实例化,就能实现程序运行过程中使用不到这个对象时,避免实例化而浪费内存,提高内存利用率,以提升性能
默认情况下单例作用域的对象都是非惰性初始化的
惰性初始化的缺点
如果一个项目大范围使用惰性初始化
那么运行时可能每个对象都需要先实例化才能运行,这样就会拖慢程序的运行速度,所以惰性初始化需要设置针对性的使用
一般针对那些占用资源多的同时还有较大几率使用不到的对象时
测试惰性初始化效果
我们又创建了Dog类
代码基本和Cat类一致
只是在Dog类中添加了构造方法
//创建一个无参构造方法
public Dog(){
// 无参构造方法运行输出信息
System.out.println("Dog构造方法执行");
}
下面编写了测试类
public class DogTest {
AnnotationConfigApplicationContext acac;
@Before
public void init(){
acac=new AnnotationConfigApplicationContext(DogConfig.class);
System.out.println("init方法运行完毕");
}
@After
public void destroy(){
acac.close();
}
@Test
public void lazy(){
Dog d=acac.getBean("dog",Dog.class);
System.out.println(d);
}
}
运行结果为
Dog构造方法执行
init方法运行完毕
Dog{name='null', color='null', age=null}
证明默认情况下
Dog类会在acac对象实例化时就实例化了
设置惰性初始化
组件扫描:
@Component
@Lazy
@Bean方式
@Bean
@Lazy
设置惰性初始化之后
再次运行测试方法(测试方法代码没有任何变化)
而输出结果变为了
init方法运行完毕
Dog构造方法执行
Dog{name='null', color='null', age=null}
证明lazy的设置使原来在acac对象实例化时就要实例化的Dog对象
变为了在acac.getBean方法指定dog的id时才实例化
惰性初始化效果完成
英文
Inversion: 反转的
Control:控制
Config:配置
Annotation:注解
Application:程序
Context:上下文\环境\容器
major:专业
Component:组件
Scan:扫描
Bean:在程序中出现Bean表示Spring容器中保存的各种对象
bean本身的意思是种子,豆子的意思
available:可用的
Scope:作用域
CSDN 网站
www.csdn.net