Spring框架的介绍和使用
Spring
以业务为驱动,开发业务的同时接触学习新知识
明确和记住开发某个业务的流程、顺序、套路。
Spring
Spring MVC 和 Spring Boot
-
SpringMVC:
Controller,页面和java的交互,都是SpringMvc的功能。M:Model模型:实体类
V:View视图:html页面,显示给用户看的界面
C:Controller控制器:Controller类,视图与java进行数据交互
SpringMVC框架简化了V和C之间的数据交互过程 -
Spring Boot
boot:启动
支持Spring Boot框架的项目内置了许多的配置
使用该框架时,省去了繁琐配置的过程
除了这些配置,还有一些约定,如static文件夹存放静态资源
什么是Spring
Spring是一个基础框架,是Spring MVC和Spring Boot等众多以Spring开头命名的框架的基础。
它的出现,是Java能够长盛不衰的原因。因为它提供了Java开发的生态环境。
几乎任何需求,Spring都有相应的解决方案。
IOC
IOC:控制反转
正常的控制称之为主动控制
主动控制:我们编写的程序主动控制对象组件的产生,再编写对象组件互相调用完成程序功能。
控制反转:程序需要的对象组件保存在外部容器中,需要时从容器中获取后调用相应的对象组件。
一. Spring 实现 IOC
1. 创建Spring项目
1. 依赖问题
<dependencies>
<!-- Spring依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.16</version>
</dependency>
<!-- Junit测试依赖-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
2. 创建实体类
//实体类即要保存的对象组件
//设置类是用来将组件保存到容器中
//实体类 Stu
public class Stu {
private String name;
private Integer age;
}
3. 创建配置类
使用 @Configuration 注解和 @Bean 注解
设置类:Config
package cn.zx.entity;
// 配置类,配置Spring容器下的内容
// 标准情况下,Spring的配置类要添加下面的注解
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class Config {
// 编写下面的 @Bean 注解
// 这个注解下面,写个方法,该方法返回对象就会保存在容器中.
// 每个保存到Spring容器的对象都要有一个唯一的名字,该名字就是这个方法的方法名
@Bean
public Stu stu() {
Stu stu = new Stu();
stu.setName("杨过");
stu.setAge(22);
return stu;
}
}
2. 获取容器对象
1. 通过xml配置文件
<!--resources文件夹创建xml文件->spring-->
application.xml
<!--spring配置文件格式-->
<?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="" class="类全限定名称"></bean>
</beans>
1)根标签是beans
2)beans后面是约束文件说明
3)beans里面是bean声明
4)什么是bean:bean就是java对象,spring容器管理的java对象,叫做bean
2. 通过注解 @Bean
之前使用的是文件配置,现在使用了注解的方式,配置类使用注解 @Configuration,然后使用AnnotationConfigApplicationContext 获取 context对象,通过context对象获取 对象组件。
// AnnotationConfigApplicationContext 和 getBean("name"),getBean(XX.class),
// getBean("name",xx.class);
package cn.zx.entity;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Test {
public static void main(String[] args) {
// 初始化Spring容器 ACAC , 使用反射 ,通过注解,使spring容器创建该对象组件
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
// 从Spring容器获取对象
Stu stu = context.getBean("stu", Stu.class);
System.out.println(stu);
}
}
单元测试Junit
使用单元测试 运行Spring
Junit测试程序
<!-- Junit测试依赖-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
测试类的包名建议和源文件的包名相同,这样会被视为是同一个包。
测试类的类名不能叫Test,测试类的方法上方添加注解:@Test,被视为测试方法,可直接运行。
import cn.zx.entity.Config;
import cn.zx.entity.Teacher;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class T {
@Test
public void test01() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
Teacher teacher = context.getBean("teacher", Teacher.class);
System.out.println(teacher);
context.close();
}
}
发现context的实例化和关闭每次都要执行,可以利用Junit的@Before和@After这两个注解减少冗余,简化编写,代码如下:
// Before会在Test运行之前运行
// After会在Test运行之后运行
public class T {
AnnotationConfigApplicationContext context = null;
// 该方法会在@Test注解运行之前运行
@Before
public void init() {
context = new AnnotationConfigApplicationContext(Config.class);
}
@Test
public void test01() {
Teacher teacher = context.getBean("teacher", Teacher.class);
System.out.println(teacher);
context.close();
}
// 该方法会在@Test注解运行之后运行
@After
public void destory() {
context.close();
}
}
3. 组件扫描方式@ComponentScan
除了@Bean方式保存到容器,还有组件扫描方式保存到Spring容器。
1. 创建实体类
@Component
/*
@Component该注解意思是组件,
一旦被标记,表示当前类要自动实例化对象,并保存在Spring容器中
这个对象保存在Spring容器中的id名就是当前类名,首字母小写
*/
@Component
public class Hero {
private String name;
private String job;
}
2. 创建配置类
@ComponentScan 声明组件扫描,后面的() 填写要扫描的包名,扫描填写的包名及子包等等的所有的包中带有 @Component的类。并将其添加到 Spring容器中。
package cn.zx.dao;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
//创建配置类
// 启动组件扫描的主动方式,如果向让Hero类上的@Component生效,还要配置类中声明扫描的包
@Configuration
@ComponentScan("cn.zx.dao")
public class Config {
}
测试类
package cn.zx.dao;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class T {
AnnotationConfigApplicationContext context;
@Before
public void init() {
context = new AnnotationConfigApplicationContext(Config.class);
;
}
@After
public void destory() {
context.close();
}
@Test
public void test() {
Hero hero = context.getBean(Hero.class);
System.out.println(hero);
}
}
微总结:
目前了解了两种 将 对象组件保存到容器中的方法
1. 使用@Bean方法
- 通过创建配置类,@Configuration , 其中的方法配以@Bean注解,
- 该方法的方法名就是对象组件名。
- 该方法的返回值就是即将保存到容器中的对象组件。
2. 使用组件扫描方法 ComponentScan
- 实体类 即 要被保存到容器中的对象组件需要首先进行组件声明@Component
- 创建配置类,配置类不仅声明配置类,还要声明组件扫描@ComponentScan(包名)
- 组件扫描包名,扫描该包及其子包所有,只要发现有组件声明的对象组件
- 则将其保存到容器中。该对象组件的id就是该对象的Class名,不过首字母小写。
这两种方法可以混用,反正Spring容器只有一个。
获取Spring容器的方法:
AnnotationConfigApplicationContext context;
context = new AnnotationConfigApplicationContext(Config.class);
Config.class 就是配置类的反射。
通过该配置类,将对象组件添加到Spring容器中。
----- day01 pm 1小时处。
4. 保存到Spring的细节
-
除了@Component还有以下常见注解有相同功能
- @Controller\RestController
- @Service
- Reposity
- ......
为什么相同功能设置不同注解?
见到注解名称就知道类的作用。
-
关于特殊的类名
- 组件扫描,当前类型对象的 id 是类名首字母小写,如果类名有连续两个字母大写,则该类名就是 id 名,不再需要小写。
-
自定义组件id
- 不希望组件id是类名,可以自定义id,在@Component("id")(并不推荐)
例如: @Component("pn") public class Person { @Value("木鱼") private String name; @Value("21") private Integer age; }
二. Spring中对象的作用域
1. 作用域概述
作用域英文:scope
单例(singleton):从程序开始到程序结束,某个类型的对象只有一个。
原型(prototype):从程序开始到程序结束,某个类型不断出现新的对象,没有数量限制
/*
Spring默认获取的对象都是单例的,也就是获取的对象都是同一个,可以通过查看内存地址查看
查看内存地址的方法,需要先添加依赖
<dependency>
<groupId>org.openjdk.jol</groupId>
<artifactId>jol-core</artifactId>
<version>0.9</version>
</dependency>
然后使用VM.current().addressOf( 对象 )
*/
package cn.zx.so;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.openjdk.jol.vm.VM;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class T {
AnnotationConfigApplicationContext context;
@Before
public void init() {
context = new AnnotationConfigApplicationContext(Config.class);
}
@Test
public void test() {
Person p1 = (Person) context.getBean("pn");
Person p2 = (Person) context.getBean("pn");
System.out.println(p1 == p2);
System.out.println(VM.current().addressOf(p1));
}
@After
public void destory() {
context.close();
}
}
2. 修改作用域为prototype
将单例作用域修改成原型作用域,将对象修改成prototype(原型)的scope
1. @Bean的保存方式
在@Bean下添加@Scope("prototype")
@Bean
@Scope("prototype")
public Stu stu() {
Stu stu = new Stu();
stu.setName("杨过");
stu.setAge(22);
return stu;
}
2. @Component的保存方式
在@Component下添加 @Scope("prototype") 注解
原型模式下,每次获得对象,Spring都会实例化一个新的对象返回,每个对象都是不同的引用。
@Component("pn")
@Scope("prototype")
public class Person {
private String name;
private Integer age;
}
今后使用Spring的时候,如果需要修改Scope,根据这两个特性来设置修改即可。
3. 惰性初始化(懒惰初始化)
单例模式,验证容器中的对象初始化时机。
原型模式本来就是 懒惰初始化,因此 @Scope("prototype") 和 @Lazy没必要共存。
/*
Spring在初始化的时候就已经创建好了 对象实例,这叫惰性初始化。
也就是在获取Spring容器对象的时候,容器内的对象已经实例化了。只有单例模式才会惰性初始化。
原型模式中的初始化,是在获取具体对象的时候,才会实例化该对象。
简而言之:实例化容器对象的时候,也会实例化容器内保存的大量对象。
*/
@Scope("singleton")
@Before
public void init() {
// 这里的时候容器中的对象已经实例化了。
context = new AnnotationConfigApplicationContext(Config.class);
}
@Test
public void test() {
System.out.println("----------");
Person p1 = (Person) context.getBean("pn");
Person p2 = (Person) context.getBean("pn");
System.out.println(p1 == p2);
System.out.println(VM.current().addressOf(p1));
System.out.println(VM.current().addressOf(p2));
}
针对实例化会消耗较多资源,但是运行过程不一定用到的对象,我们设置为懒惰初始化。
什么时候需要用到该对象,什么时候懒惰初始化的对象才会实例化。
使用 @Lazy 来设置惰性加载。
1. @Bean对象设置懒惰加载
@Bean
@Lazy
public Stu stu() {
Stu stu = new Stu();
stu.setName("杨过");
stu.setAge(22);
return stu;
}
2. @Component对象设置懒惰加载
@Component("pn")
@Lazy
public class Person {
private String name;
private Integer age;
}
添加 @Lazy 注解后,表示Spring容器实例化的时候,便不再实例化所需对象。只有在需要的时候,Spring容器才会实例化所需的对象。
惰性初始化不宜大范围使用,会引起运行缓慢。
三. DI
1. 什么是DI
Dependency Injection,依赖注入。
IOC是控制反转,是一种编程思想。DI是基于控制反转思想的一种操作。
2. 什么是依赖
依赖:程序中A类的操作执行需要使用B类对象的情况,就说A类依赖B类。
实现依赖注入:
实体类
首先声明一个警察,一个手枪,警察要拿着枪
public class Police {
private String name;
private Gun weapon;
set/get略
}
public class Gun {
private String type = "左轮";
set/get略
}
Config类
Config类 设置Spring容器保存Police对象和Gun对象
@Configuration
public class Config {
@Bean
public Gun gun(){
return new Gun();
}
@Bean
public Police police() {
return new Police();
}
}
测试类:
此时的police需要拿起枪,police也就是依赖于gun,那么能不能让police自己去Spring容器中去找Gun类型的依赖。
@Test
public void test() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
// 获取Gun
Gun gun = context.getBean("gun", Gun.class);
// 获取Police对象
Police police = context.getBean("police", Police.class);
police.setName("大卫");
// Police对象拿起枪
police.setWeapon(gun);
// 输出查看
System.out.println(police);
context.close();
}
修改Config,让police自动寻找依赖
@Configuration
public class Config {
@Bean
public Gun gun() {
return new Gun();
}
/*
所谓依赖注入,就是将两个或更多类的依赖关系,实现在Spring容器内部。
只需要在police方法中添加Gun形参,然后再方法体中,将gun赋给police即可。
*/
@Bean
public Police police(Gun gun) {
Police police = new Police();
police.setWeapon(gun);
return police;
}
}
测试类:
@Test
public void test() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
// 获取Gun
Gun gun = context.getBean("gun", Gun.class);
// 获取Police对象
Police police = context.getBean("police", Police.class);
police.setName("大卫");
// 输出查看
System.out.println(police);
context.close();
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!