当前位置:首页 > 编程笔记 > 正文
已解决

【Spring】-Bean的作用域和生命周期

来自网友在路上 160860提问 提问时间:2023-09-25 11:06:36阅读次数: 60

最佳答案 问答题库608位专家为你答疑解惑

作者:学Java的冬瓜
博客主页:☀冬瓜的主页🌙
专栏:【Framework】
主要内容:Lombok的使用,Bean作用域的分类和修改。Singleton、Prototype。spring的执行流程,Bean的生命历程。

文章目录

  • 一、Bean的作用域
    • 1、 Lombok的使用(简化代码工具)
      • 1.1、什么是Lombok?为什么使用Lombok?
      • 1.2、使用Lombok的步骤?
      • 3、Lombok注解总结
    • 2、Bean的作用域
      • 2.1、什么是Bean的作用域?
      • 2.2、Bean作用域的分类
      • 2.3、设置Bean的作用域
        • 法一、使用注解
        • 法二、使用Xml方式
  • 二、Bean的生命周期
    • 1、spring执行流程
    • 2、Bean的生命周期
      • 2.1、Bean的生命周期的过程
      • 2.2、代码查看

一、Bean的作用域

1、 Lombok的使用(简化代码工具)

1.1、什么是Lombok?为什么使用Lombok?

Lombok是一个Java库,通过注解来简化Java代码的编写。它提供了一系列注解,可以自动插入代码,减少了Java开发中的样板代码。使用Lombok可以减少getter和setter方法的编写,简化构造函数的创建,自动生成toString、equals、hashCode等方法。

1.2、使用Lombok的步骤?

步骤A:从maven仓库复制 Lombok的依赖到 pom.xml文件中。
在这里插入图片描述
步骤A:在实体类上使用Lombok提供的注解:如 @Setter @Getter @ToString等
在这里插入图片描述
步骤C:在idea里下载Lombok插件,用于识别Java代码中的注解。(如果不下载插件,那么就无法识别注解)
在这里插入图片描述
如果没有安装Lombok,则想要调用user的属性没有下列提示信息,即无法识别注解:
在这里插入图片描述

3、Lombok注解总结

基本注解作用@Getter自动添加getter方法(@Setter同理)@ToString自动添加toString方法@EqualsAndHashCode自动添加equals和hashcode方法@NoArgsConstructor自动添加无参构造方法@AllArgsConstructor自动添加全属性构造方法,顺序按照属性的定义顺序@NonNull属性不能为null@RequiredArgsConstructor自动添加必须属性的构造方法,final+@NonNull 的属性是必需 组合注解作用@Data@Getter + @Setter + @ToString + @EqualsAndHashCode +
@RequiredArgsConstructor + @NoArgsConstructor 日志注解作用(写日志时会用到)@Slf4j添加一个名为log的日志,使用Slf4j

2、Bean的作用域

2.1、什么是Bean的作用域?

在Java中,Bean的作用域指的是控制Bean实例的生命周期 和 可访问性的范围。
比如你有一个"User"类,你可以将它声明为Singleton作用域,这样整个程序就只有一个user对象,所有的代码都可以共享这一个对象。或者你将它声明为Prototype作用域,这样每次需要使用User对象时,都会创建一个新的User对象,每个对象都是独立的。

2.2、Bean作用域的分类

A:Singleton(单例):每个应用程序只有一个实例,所有请求都共享同一个实例(即 通过applicationContext.getBean()等方法 和 依赖注入(@Autowired) 都是同一个Bean对象)。
B:Prototype(原型):每次在该作用域下对Bean的请求都会创建新的Bean对象。(即 通过applicationContext.getBean()等方法 和 依赖注入(@Autowired) 都是新的实例Bean对象)。
C:request(请求): 每次HTTP请求都会创建新的Bean对象。【适用于SpringMVC】
D:Session(会话): 在HTTP的一个session(会话)中,只有一个Bean实例对象。【适用于SpringMVC】
E:application: 在一个HTTP server Context中,只有一个实例Bean对象。比如ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");获取IoC容器时, 在这个上下文context的作用域下,只使用一个Bean对象。【适用于SpringMVC】

2.3、设置Bean的作用域

法一、使用注解

单例作用域变原型作用域的代码演示:

A 理解当不设置作用域时,默认是单例作用域
需要改为原型作用域的情况:如果获取到对象后,需要当前对象作为源对象给临时对象赋值,就会出错,因为这时临时对象tmp和源对象user都指向了同一个对象,这时如果临时对象发生修改,那么源对象也会发生改变,得不偿失。所以要设置作用域范围,如果整个程序只需要使用一个不变的实体类对象,就可以使用单例作用域,否则使用原型作用域
B 设置作用域的方法:在存储Bean对象的时候在获取Bean的方法上使用Scope。有如下图两种方法。同时还可以使用xml的方式。
在这里插入图片描述

C 代码和运行结果如下:

//实体类
package test.entity;import lombok.*;@Setter
@Getter
@ToString
@AllArgsConstructor //包含所有参数的构造方法
@NoArgsConstructor  //无参构造方法
public class User {private int id;private String name;
}
//UserBeans,方法注解存储Bean对象
package test.conponent;import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import test.entity.User;@Component
public class UserBeans {@Bean(name = "User")
//    @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
//    @Scope("prototype")public User getUser(){User user = new User();user.setId(1);user.setName("admin");return user;}
}
//UserController 获取User对象,并给临时对象tmp赋值
package test.controller;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import test.entity.User;@Controller
public class UserController {@Autowiredprivate User user;public void run(){// 单例作用域时,user和tmp都是指向的同一个引用,tmp改变,user自然也改变System.out.println("原user"+user);User tmp = user;tmp.setId(2);tmp.setName("lihua");System.out.println("tmp"+tmp);System.out.println("给tmp赋值后的user:"+user);System.out.println("====================");}
}
//UserController2 获取当前User对象。
package test.controller;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import test.entity.User;@Controller
public class UserController2 {@Autowiredprivate User user;public void run(){System.out.println("UserController2:"+user);}
}
//App类的main方法中,调用获取上下文,并运行controller的方法。
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import test.controller.UserController;
import test.controller.UserController2;//lombok的使用,以及Bean的作用域、Bean的生命周期
public class App {public static void main(String[] args) {ApplicationContext context =new ClassPathXmlApplicationContext("spring-config.xml");UserController userController = context.getBean("userController", UserController.class);userController.run();UserController2 userController2 = context.getBean("userController2", UserController2.class);userController2.run();}
}

运行结果:

userUser(id=1, name=admin)
tmpUser(id=2, name=lihua)
给tmp赋值后的user:User(id=2, name=lihua)
====================
UserController2User(id=2, name=lihua)

从代码运行结果可以看出,user给临时对象tmp赋值后,因为它俩指向的同一个对象,因此修改tmp后,user也被修改。

D:作修改: 在存储Bean时设置作用域Scope为原型作用域后,运行结果如下:

userUser(id=1, name=admin)
tmpUser(id=2, name=lihua)
给tmp赋值后的user:User(id=2, name=lihua)
====================
UserController2User(id=1, name=admin)

可以看到在UserController获取Bean并赋值tmp然后修改tmp后,UserController2获取Bean时,user对象并没有被改变,获取到的对象是源User,说明Bean不是单例了。
但是在UserController中获取Bean并赋值tmp然后修改tmp后,在该方法中User还是改变了,这是因为在下面方法中整个过程都是建立在调用了一次getBean的基础上来的,只有一次获取Bean的请求的前提,所以在该方法中是单例作用域。
在这里插入图片描述

法二、使用Xml方式
<bean id="userBean" class="com.example.User" scope="prototype"/>

二、Bean的生命周期

1、spring执行流程

在这里插入图片描述

2、Bean的生命周期

2.1、Bean的生命周期的过程

A:实例化,为Bean对象分配空间。
B:设置属性(对象装配),如果在当前Bean中需要其他Bean对象作为属性,则进行对象装配,注意设置属性比初始化早,防止在初始化时调用当前对象的属性对象。
C:初始化
1>执行各种通知
2>初始化前置方法
3>初始化方法(法一:注解方法PostConstruct,法二:Xml方式)
4> 初始化后置方法
D:使用
E:销毁

2.2、代码查看

以下代码展示了BeanNameAware接口的抽象方法重写的方法setBeanName(String s),用于展示初始化前的通知,初始化Bean对象方法PostConstruct,销毁Bean对象方法PreDestroy。同时初始化方法还可以使用Xml方式。

package test.controller;import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.annotation.Autowired;
import test.entity.User;import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;public class UserControllerXml implements BeanNameAware {@Autowiredprivate User user;@Overridepublic void setBeanName(String s) {//执行各种通知的重写的方法System.out.println("do aware!(执行各种通知)");}@PostConstruct//初始化方法public void doPostStruct(){System.out.println("do PostStruct(初始化方法 )");}public void run(){//使用Bean方法System.out.println("使用Bean: "+user);}@PreDestroypublic void doPreDestroy(){//销毁Bean的方法System.out.println("销毁Bean:");}
}
查看全文

99%的人还看了

猜你感兴趣

版权申明

本文"【Spring】-Bean的作用域和生命周期":http://eshow365.cn/6-13420-0.html 内容来自互联网,请自行判断内容的正确性。如有侵权请联系我们,立即删除!