SpringDay01

张皓岚

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

评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值