目录
6、对象何时创建,何时销毁, 能不能延迟创建,初始化方法和销毁方法
一、spring
- spring全家桶
- spring、springmvc、springboot、springsecurity、springcloud
- spring包含的子模块:
- spring core ----- 最核心jar包 ioc、di
- spring dao ----- 针对jdbc封装
- spring orm ----- object relational mapping 对象关系映射思想
- spring aop ----- 面向切面管理 (事务切面、日志切面、权限控制、自定义切面)
- spring web ------ 针对servlet进行的封装,接收请求、响应数据给前端
- spring context ---- 上下文环境
- springmvc ---- spring webmvc ---包含spring core 、aop等
二、Spring的核心
2.1 三大思想
IOC、DI、AOP
2.2 两大思想
IOC|DI、AOP
- Spring Framework:Spring 的基础框架,可以视为 Spring 基础设施,基本上任何其他 Spring 项目都是以 Spring Framework 为基础的,其包含IOC/DI和AOP两大核心部分
核心概念 | 描述 |
---|---|
IOC | Inversion of Control 的简写,译为“控制反转”,指把创建对象过程交给 Spring 进行管理。 |
AOP | Aspect Oriented Programming 的简写,译为“面向切面编程”。AOP 用来封装多个类的公共行为,将那些与业务无关,却为业务模块所共同调用的逻辑封装起来,减少系统的重复代码,降低模块间的耦合度。另外,AOP 还解决一些系统层面上的问题,比如日志、事务、权限等。 |
2.3 IOC 控制反转思想
- inverse of control
- 控制权的反向转移。创建对象的权限转移给spring容器
- (原来创建对象,是谁用谁创建,现在应该有spring容器创建,使用时从容器中获取)
- User u1 = new User(); 创建需要消耗资源、存储消耗资源、回收消耗资源。
- User u2 = new User(); 频繁的创建对象、销毁对象。
1、创建容器
2、将对象放到容器中
3、用的时候从容器中获取
4、不用了,归还对象到容器。
2.4 IOC概念
- IOC全称Inversion Of Control 控制反转,核心的作用就是将原来由开发人员来控制的对象管理操作交由Spring来管理,spring创建出来的对象,会放到spring的一个容器中存储,使用对象的时候可以从容器直接拿,这个容器就称为spring ioc容器。
- 简单来说:原来我们自己new对象的操作不在做了,而是由spring帮我们创建对象,创建出来的对象spring会放到一个容器中管理,我们用对象的时候,从容器中去拿就行了。
2.5 IOC容器初始化方式
- xml配置文件配置方式【使用读取xml中的bean来创建对象】
- 纯注解方式
2.6 类关系
- BeanFactory接口:这是 IOC 容器的基本实现,是 Spring 内部使用的接口。面向 Spring 本身,不提供给开发人员使用。
- ApplicationContext接口:BeanFactory 的子接口,提供了更多高级特性。面向 Spring 的使用者,几乎所有场合都使用 ApplicationContext 而不是底层的 BeanFactory。
- ClassPathXmlApplicationContext:通过读取类路径下的 XML 格式的配置文件创建 IOC 容器对象。
- AnnotationConfigApplicationContext:通注解方式创建 IOC 容器对象。
三、搭建spring环境
1、单独引入需要的jar包,比如ioc(spring-core,spring-context)
2、直接引入所有常见的(建议选择)
- maven项目(ssm架构模式) pom中指定jar包
- springboot项目(更简单) 选择 直接创建springboot项目(自动引入相关jar包)
四、创建容器的两种方式
4.1 通过类创建
package com.hl.springboot01;
import org.springframework.context.annotation.Configuration;
//@Configuration 配置文件类
@Configuration
public class MyConfig {
}
package com.hl.springboot01;
import org.junit.jupiter.api.Test;
import
org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class MyBeanTest {
@Test
public void createContainer(){
//读取配置文件类,创建ioc容器
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(MyConfig.class);
//context 即为容器对象
}
}
4.2 通过配置文件
在resources目录中创建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">
</beans>
写一个测试类,加载配置文件,创建容器
五、容器内部创建对象(承接四)
1、配置类创建对象
- 创建javabean类
@Data
//创建当前类的对象,并交给spring容器进行管理
@Component
public class User {
private int id;
private String name;
}
- 在配置文件类定义组件扫描的包
//@Configuration 配置文件类
@Configuration
//定义组件扫描的包
@ComponentScan(basePackages = "com.hl.springboot01.pojo")
public class MyConfig {
}
2、配置文件模式创建对象
<?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">
<!--
创建一个对象
id="对象名“
class="类的全限定名"
-->
<bean id="u1" class="com.hl.springboot01.pojo.User"></bean>
</beans
六、底层通过构造方式、工厂方法创建对象
构造方式
- 无参构造
- 有参构造
@Component("goods")
public class Goods {
private int id;
private String name;
private int price;
public Goods() {
System.out.println("无参构造.......");
}
}
工厂方法
- 静态工厂
- 实例工厂
//创建对象 对象名,默认为方法名
@Bean //实例工厂方法
public Category category(){
return new Category();
}
@Bean //静态工厂方法
public static Category category2(){
return new Category();
}
七、获取对象的过程
package com.hl.springboot01;
import com.hl.springboot01.pojo.User;
import org.junit.jupiter.api.Test;
import
org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class MyBeanTest {
@Test
public void createContainer(){
//读取配置文件类,创建ioc容器
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(MyConfig.class);
//context 即为容器对象
//从容器中获取对象
User user = context.getBean(User.class);
//只要不报空指针异常,就证明从容器中获取对象
System.out.println(user.toString());
}
@Test
public void createContainer2(){
//读取配置文件,创建ioc容器
ClassPathXmlApplicationContext context =
new ClassPathXmlApplicationContext("applicationContext.xml");
//容器对象 context
//容器中获取对象
User user = context.getBean(User.class);
System.out.println(user.toString());
}
}
八、对象的生命周期
对象的生命周期:对象创建到销毁的整个过程
8.1 对象何时创建
- 单例模式:默认情况下,在创建ioc容器时,创建对象。
- 创建对象时,默认调用无参构造方法创建对象。 无参构造只执行一遍。
- 初始化方法(在对象创建后,自动调用的方法)。 初始化方法只执行一遍。
- 销毁前调用的方法(关闭ioc容器时,自动调用的) 。只执行一次。
- 懒加载:只针对单例模式有效。
- 懒加载:在首次使用对象时创建对象(而不是在创建容器时创建对象)。
- 多例模式下:可以创建很多对象,不是提前创建的对象,是使用时创建对象。
- 每获取一次对象,创建一个对象,执行一次构造方法,执行一次初始化方法。
8.2 对象何时销毁
- 单例模式下,关闭容器时销毁。
- 多例模式下:对象 由 jvm虚拟机 垃圾回收器 在 后台进程自动销毁。
示例代码:
package com.hl.springboot02.pojo;
import lombok.Getter;
import lombok.Setter;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
@Getter
@Setter
//创建类的对象 对象名默认为类名(首字母变小写)
//@Component("对象名")
//多例模式
//@Scope(value = "prototype")
//懒加载
@Lazy
@Component("goods")
public class Goods {
六、bean的作用域范围
private int id;
private String name;
private int price;
public Goods() {
System.out.println("goods....无参构造.......");
}
//@PostConstruct 初始化方法
@PostConstruct
public void init(){
System.out.println("init ..... 初始化方法");
}
//@PreDestroy 销毁前执行
@PreDestroy
public void destroy(){
System.out.println("destroy....销毁前执行");
}
}
@Test
public void objectLife(){
//单例模式下的对象 默认是在创建容器时,直接创建对象,销毁ioc容器时,销毁对象
AnnotationConfigApplicationContext context =
new
AnnotationConfigApplicationContext(Springboot02Application.class);
// //获取对象
// //多例模式下的对象 默认是在获取对象时创建,由jvm虚拟机自动销毁
Goods goods = context.getBean("goods", Goods.class);
Goods goods2 = context.getBean("goods", Goods.class);
//
// //优雅的销毁容器
context.registerShutdownHook();
}
九、bean的作用域范围
<?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">
<!--
创建一个对象
id="对象名“
class="类的全限定名"
在同一个容器中,对象名不能重复
单例模式: 一个类只有一个实例(对象) 默认 scope="singleton"
多例模式:一个类有多个实例(对象) scope="prototype"
spring-web 环境 接收前端请求
request: 一次request请求创建一个对象
global-session: 全局有效
-->
<bean id="u1" name="u2,u3" class="com.hl.springboot01.pojo.User"
scope="singleton"></bean>
<!-- <bean id="u4" class="com.hl.springboot01.pojo.User"></bean>-->
</beans>
@Test
public void createContainer2(){
//读取配置文件,创建ioc容器
ClassPathXmlApplicationContext context =
new ClassPathXmlApplicationContext("applicationContext.xml");
//容器对象 context
//容器中获取对象
User user1 = context.getBean("u1",User.class);
User user2 = context.getBean("u1",User.class);
System.out.println(user1);
System.out.println(user2);
}
//@Data
@Getter
@Setter
//创建当前类的对象,并交给spring容器进行管理
@Component
public class User {
private int id;
private String name;
}
十、如何从容器内部获取对象(从容器中获取对象的三种方
式)
// 方式一: 推荐 名称+类型
Goods goods = context.getBean("goods", Goods.class);
System.out.println(goods);
// 方式二: 名称 需要强制类型转换
Goods goods2 = (Goods)context.getBean("goods");
System.out.println(goods2);
// 方式三: 通过类型获取
Goods goods3 = context.getBean(Goods.class);
System.out.println(goods3);
@Getter
@Setter
//创建类的对象 对象名默认为类名(首字母变小写)
//@Component("对象名")
@Component("goods")
public class Goods {
private int id;
private String name;
private int price;
}
十一、总结面试题
1、Spring的三大核心思想 ioc、di、aop
核心思想 | 全称与定义 | 关键作用 | 典型应用场景 | 实现方式 |
---|---|---|---|---|
IoC | Inversion of Control(控制反转) 将对象的创建、依赖管理权交给容器(Spring),而非程序员手动控制。 | 解耦对象间的依赖关系,提升灵活性。 | Bean 的生命周期管理、模块化开发 | 通过 IoC 容器(如 ApplicationContext )实现对象的创建和依赖注入。 |
DI | Dependency Injection(依赖注入) IoC 的具体实现方式,由容器动态注入对象所需的依赖(而非对象自己查找)。 | 减少硬编码依赖,增强可测试性和可维护性。 | 服务层注入DAO、配置类注入组件 | 通过 @Autowired 、@Resource 或 XML 配置自动/手动注入依赖对象。 |
AOP | Aspect-Oriented Programming(面向切面编程) 将横切关注点(如日志、事务)与核心业务逻辑分离。 | 减少重复代码,降低耦合,集中处理系统级功能。 | 日志记录、事务管理、权限校验 | 通过动态代理(JDK/CGLIB)和切面(@Aspect )实现方法拦截与增强。 |
通俗理解
-
IoC:由“工厂”(Spring)负责生产对象,程序员不再需要
new
。 -
DI:工厂不仅生产对象,还自动组装对象之间的依赖(如给汽车装配发动机)。
-
AOP:在不修改汽车零件(业务代码)的情况下,为所有车辆统一安装GPS(日志/事务)
2、IOC思想的理解
自己的话描述一下。
IOC,即控制反转(Inversion of Control),是一种设计原则,用于指导软件架构的设计。它的核心思想是将对象创建和依赖管理的控制权从程序本身转移到外部容器或框架中。通过这种方式,可以减少组件间的直接依赖,增强系统的灵活性和可维护性。
在传统的编程方式中,对象的创建和依赖关系的管理通常是由程序员自己来完成的,这导致了代码之间的紧密耦合。例如,如果一个类A需要使用另一个类B的功能,那么程序员可能会在类A中直接实例化类B的对象。这样做的问题是,类A不仅承担了自己的职责,还负责管理类B的生命周期,使得系统难以修改和测试。
采用IOC原则后,这种直接的依赖关系被打破了。现在,由外部容器(如Spring框架)负责管理对象的生命周期和依赖注入。当一个对象需要其他对象的帮助时,它不需要自己去创建这些对象,而是声明它需要什么样的对象,并期望外部容器能够提供这些依赖。这样一来,对象之间不再直接相互依赖,降低了模块间的耦合度,提高了代码的复用性和测试性。
简单来说,IOC就是一种让系统中的各个组件尽可能少地直接依赖对方的技术。通过将依赖关系交给外部容器进行管理,使系统更加灵活、易于扩展和维护。这种方法鼓励开发者编写更干净、模块化的代码,从而提高整体软件的质量。
3、IOC容器创建的两种方式
- xml配置文件配置方式【使用读取xml中的bean来创建对象】
- 纯注解方式 @Configuration
- BeanFactory接口:这是 IOC 容器的基本实现,是 Spring 内部使用的接口。面向 Spring 本身,不提供给开发人员使用。
- ApplicationContext接口:BeanFactory 的子接口,提供了更多高级特性。面向 Spring 的使用者,几乎所有场合都使用 ApplicationContext 而不是底层的 BeanFactory。
- ClassPathXmlApplicationContext:通过读取类路径下的 XML 格式的配置文件创建 IOC 容器对象
- AnnotationConfigApplicationContext:通注解方式创建 IOC 容器对象。
4、创建对象的注解
- @Component 类上使用。
- @Bean 方法上使用,方法的返回值是对象,将返回的对象交给ioc容器管理。
5、底层如何创建对象
- 构造方法(无参构造|有参构造)
- 工厂方法(静态工厂方法|实例工厂方法)
6、对象何时创建,何时销毁, 能不能延迟创建,初始化方法和销毁方法
- 单例模式
-
创建时机:容器启动时(
ApplicationContext
初始化)立即创建。
默认情况下,在创建ioc容器时,创建对象。 -
销毁时机:容器关闭时(调用
context.close()
)。 -
单例模式的延迟初始化(Lazy) 通过
@Lazy
注解,使得单例 Bean 在第一次使用时才创建。而不是在创建容器时创建对象。 - 创建对象:默认调用无参构造方法创建对象。 无参构造只执行一遍。
- 初始化方法(在对象创建后,自动调用的方法)。 初始化方法@PostConstruct注释的方法只执行一遍。
- 销毁前调用的方法(关闭ioc容器时,自动调用的) 。@PreDestroy注释的方法只执行一次。
- 多例模式
-
创建时机:每次调用
getBean()
或依赖注入时创建新实例。 -
销毁时机:对象 由 jvm虚拟机 垃圾回收器 在 后台进程自动销毁。
-
不用延迟创建:本身就是“延迟创建”,无需额外配置。
- 创建对象:多例模式下的,可以创建很多对象,不是提前创建的对象,是使用时创建对象。每获取一次对象,创建一个对象,执行一次构造方法,执行一次初始化方法。
- 初始化方法和销毁方法
@Component
public class MyBean {
@PostConstruct // 初始化方法
public void init() {
System.out.println("Bean 初始化完成!");
}
@PreDestroy // 销毁方法
public void cleanup() {
System.out.println("Bean 即将销毁!");
}
}
- 单例 vs 多例模式对比
-
特性 单例模式(Singleton) 多例模式(Prototype) 创建时机 容器启动时立即创建 每次 getBean()
或注入时创建内存占用 全局共享一个实例,节省内存 每次请求新实例,内存占用较多 线程安全 需自行保证线程安全 每次新实例,默认线程安全 销毁管理 容器关闭时自动销毁 Spring 不管理销毁,需手动清理 适用场景 无状态服务(如工具类、配置类) 有状态对象(如用户会话、请求上下文)
7、从容器获取对象的三种方式
- 名称(强制类型转换)
- 类型(容易出错,需要一个对象,返回了2个对象)
- 名称+类型(推荐)
// 2.1 通过类型获取 Goods goods1 = context.getBean(Goods.class); // 2.2 通过名称获取 需要强制类型转换 Goods goods2 = (Goods) context.getBean("goods"); // 2.3 通过名称和类型获取 推荐 Goods goods3 = context.getBean("goods",Goods.class);
8、bean的作用域范围
- singleton
- prototype
- request
- session
作用域范围 - spring-web 环境 接收前端请求
- request 一次request请求创建一个对象
- session 一个会话共享一个对象
- global 全局有效
作用域 | 描述 | 创建时机 | 销毁时机 | 线程安全 | 适用场景 |
---|---|---|---|---|---|
Singleton | 单例模式,默认作用域,整个 IoC 容器中只存在一个 Bean 实例。 | 容器启动时创建 | 容器关闭时销毁 | 需自行保证 | 无状态服务(如工具类、配置类) |
Prototype | 多例模式,每次请求(getBean() 或依赖注入)都会创建一个新的 Bean 实例。 | 每次调用时创建 | Spring 不管理销毁,依赖 GC。 jvm虚拟机 垃圾回收器 在 后台进程自动销毁。 | 默认安全(每个请求独立实例) | 有状态对象(如用户会话、线程上下文) |
Request | 每个 HTTP 请求创建一个新的 Bean 实例(仅适用于 Web 应用)。 | 每次 HTTP 请求时创建 | 请求结束时销毁 | 安全 | 请求级数据(如用户表单提交) |
Session | 每个用户会话(Session)创建一个 Bean 实例(仅适用于 Web 应用)。 | 用户首次访问时创建 | 会话超时或失效时销毁 | 安全 | 用户级数据(如购物车、登录状态) |
9、相关的注解有哪些?各自作用?
- @Configuration
- @ComponentScan
- @Component
- @Bean
- @Lazy
- @Scope
- @PostConstruct
- @PreDestroy
- @Data
- @Gette
- @Setter
- @Test
Spring 核心注解
注解 | 作用 | 示例 |
---|---|---|
@Configuration | 标记类为 Spring 配置类,定义 Bean 的创建逻辑。 | java @Configuration public class AppConfig { ... } |
@ComponentScan | 指定 Spring 扫描的包路径,自动注册 @Component 及其派生注解的类。 | java @ComponentScan("com.example") |
@Component | 通用注解,标记类为 Spring 管理的 Bean(泛用组件)。 | java @Component public class UserService { ... } |
@Bean | 在配置类中定义方法返回值为一个 Bean(常用于第三方库集成)。 | java @Bean public DataSource dataSource() { return new HikariDataSource(); } |
@Lazy | 延迟初始化 Bean(单例模式下首次使用时创建)。 | java @Lazy @Component public class HeavyService { ... } |
@Scope | 指定 Bean 的作用域(如 singleton 、prototype 、request 、session )。 | java @Scope("prototype") @Component public class Task { ... } |
@PostConstruct | 标记 Bean 初始化后执行的方法(替代 InitializingBean )。 | java @PostConstruct public void init() { ... } |
@PreDestroy | 标记 Bean 销毁前执行的方法(替代 DisposableBean )。 | java @PreDestroy public void cleanup() { ... } |
Lombok 简化代码注解
注解 | 作用 | 示例 |
---|---|---|
@Data | 自动生成 getter /setter 、toString() 、equals() 、hashCode() 。 | java @Data public class User { private String name; } |
@Getter | 仅生成 getter 方法。 | java @Getter public class User { private String name; } |
@Setter | 仅生成 setter 方法。 | java @Setter public class User { private String name; } |
测试相关注解
注解 | 作用 | 示例 |
---|---|---|
@Test | 标记方法为 JUnit 测试用例(需 junit 依赖)。 | java @Test public void testMethod() { ... } |