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

本文详细介绍了Lombok在Java中的应用,包括如何使用注解简化代码,以及SpringBean的不同作用域(Singleton、Prototype)及其设置方法。此外,还涵盖了Spring执行流程和Bean的生命周期过程。
摘要由CSDN通过智能技术生成

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

一、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)
====================
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 {
    @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:");
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

学Java的冬瓜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值