作者
:学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 {
@Autowired
private 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 {
@Autowired
private 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)
====================
UserController2:User(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)
====================
UserController2:User(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 {
@Autowired
private User user;
@Override
public 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);
}
@PreDestroy
public void doPreDestroy(){//销毁Bean的方法
System.out.println("销毁Bean:");
}
}