Bean的作用域和生命周期(Bean是线程安全的吗?Spring如何在并发情况下获取不完整的Bean...)

@Bean 注解是 Spring 框架中的一个注解,用于告诉 Spring 容器需要将被注解修饰的方法的返回值注册为一个 Bean。通常情况下,Spring 容器会自动扫描并创建带有 @Component 或其他类似注解的类,并将这些类的实例注册为 Bean。但对于某些特殊情况,我们可能需要手动配置某个对象的实例,或者需要调用一些特定的初始化逻辑来创建对象。这时就可以使用 @Bean 注解。总结一下,@Bean 注解用于告诉 Spring 容器需要注册一个 Bean,并提供了一个方法来创建该 Bean 的实例。通过 @Configuration 注解的配置类中使用 @Bean 注解,可以手动配置和创建特定的 Bean 实例,并在其他地方使用依赖注入的方式获取和使用这些 Bean。

Spring 是⽤来读取和存储 Bean,因此在 Spring 中 Bean 是最核⼼的操作资源,Bean是线程不安全的。

0.Lombok

0.1 了解Lombok 

Lombok是一个Java库,它可以通过注解减少Java类中的样板代码。使用Lombok可以简化代码编写,提高开发效率。

以下是Lombok库的一些常用注解及其功能:

1. `@Getter` / `@Setter`: 自动生成字段的Getter和Setter方法。

2. `@ToString`: 自动生成toString方法。

3. `@EqualsAndHashCode`: 自动生成equals和hashCode方法。

4. `@NoArgsConstructor`: 自动生成无参构造方法。

5. `@AllArgsConstructor`: 自动生成全参构造方法。

6. `@Data`: 包含了`@Getter`、`@Setter`、`@ToString`、`@EqualsAndHashCode`和`@AllArgsConstructor`的组合注解,用于快速生成Getter、Setter、toString、equals、hashCode方法和全参构造方法。

除了上述注解外,Lombok还提供了很多其他常用的注解,如 `@NonNull`(标记字段不能为空)、`@Builder`(生成Builder模式的构造器)、`@Slf4j`(自动生成Logger对象)等。

使用Lombok时,需要在项目中添加Lombok的依赖,并在IDE中安装Lombok插件,以便支持注解的自动生成。

下面是一个使用Lombok的例子:


import lombok.Data;

@Data
public class User {
    private int id;
    private String name;
}

在上述代码中,使用了`@Data`注解,它包含了`@Getter`、`@Setter`、`@ToString`、`@EqualsAndHashCode`和`@AllArgsConstructor`注解的功能。因此,不需要手动编写Getter、Setter、toString、equals、hashCode方法和全参构造方法,Lombok会自动帮我们生成这些代码。

0.2 将Lombok配置到idea

 从maven中央仓库中搜索lombok,点击引用量最高的,找到1.18.24版本,复制到pom.xml

  <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.24</version>
            <scope>provided</scope>
 </dependency>

在idea中的File的setttings中下载lombok

1. 代码感受Bean的作用域

1.1 被修改的代码

1.1.1 设计思路

公共类UserBean的作者张三,类中设置name="zhangsan",id=1;

UserController1作者李四,通过使用setname修改,使得name="lisi";

UserController2作者王五,打印user,结果发现打印出来的name="lisi",而不是我们正常逻辑上的zhangsan.由此引出我们思考.......

1.1.2 代码

//Lombok注解,先从maven仓库中引入依赖,然后在settings中下载lombok插件
//@Data注解中就包含了他的哈希,tiString,get和set方法
@Data
public class User {
    int id;
    String name;
    String password;

}
//作者:张三
@Component
public class UserBeans {
    @Bean
    public User user(){
        User user=new User();
        user.setId(1);
        user.setName("zhangsan");
        user.setPassword("1234");
        return user;
    }
}
//作者:李四
@Controller
public class UserController1 {
    @Resource
    private User user1;
    public void getUser(){
        System.out.println("张三:"+user1);
        User user2=user1;
        user2.setName("lisi");
        System.out.println("李四:"+user2);
    }
}
//作者:王五
@Controller
public class UserController2 {
    @Resource
    private User user1;
    public void getUser(){
        System.out.println("王五:"+user1);
    }
}
public class MainApp {
    public static void main(String[] args) {
        // 加载Spring配置文件即创建Spring上下文;
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

        UserController1 u1=context.getBean("userController1", UserController1.class);
        u1.getUser();
        UserController2 u2=context.getBean("userController2", UserController2.class);
        u2.getUser();



    }
}

1.1.3 观察现象

1.2 分析原因

 操作以上问题的原因是因为 Bean 默认情况下是单例状态(singleton),所有⼈的使⽤的都是同⼀个对象(使⽤单例可以很⼤程度上提⾼性能,所以在 Spring 中 Bean 的作⽤域默认是 singleton 单例模式

所以在上述作者为王五时就没有打印出zhangsan,而是被修改后的name ->"lisi"!

2. Bean的六种作用域

2.1 普通Spring项目中的作用域

singleton(Spring默认的作⽤域)——单例模式

该作⽤域下的Bean在IoC容器中只存在⼀个实例:获取Bean(即通过
applicationContext.getBean等⽅法获取)及装配Bean(即通过@Autowired注⼊)都是同⼀
个对象。 通常⽆状态的Bean使⽤该作⽤域(⽆状态:Bean对象的属性状态不需要更新)

prototype——多例模式

proto中文含义:原生的;

每次对该作用域下的Bean的请求都会创建新的实例,获取Bean和装配Bean都是新的实例对象

该作用域适用于有状态的Bean(每次请求都会创建一个新的Bean实例。每次调用getBean()方法时,都会返回一个新的实例)

 2.2 

请求作用域:request

每次http请求都会创建新的Bean实例,类似于原型模式

限定在MVC/Web中使用,适用于一次http请求和响应的共享Bean

会话作用域(session)

再一次http session 中定义一个Bean实例

用户共享Bean,比如记录用户的登录信息,限定在MVC中使用

全局作用域(application)

在一个http servlet Context中定义一个Bean实例

使用场景:Web应用的上下文信息,比如记录一个应用的共享信息,限定在MVC中使用

作用于servlet容器

websocket

网络长连接,在一个HTTPWebSocket的生命周期中,定义一个Bean实例

使用场景,在WebSocket的每次会话中,保存了一个Map结构的头信息,用来包裹客户端头信息,第一次初始化后,知道WebSocket结束,都是同一个Bean,限定在Spring WebSocket中使用
 

2.3单例作⽤域(singleton)和全局作⽤域(application)区别💀

singleton 作⽤于 IoC 的容器,⽽ application 作⽤于 Servlet 容器。

singleton 是 Spring Core 的作⽤域;application 是 Spring Web 中的作⽤域; 

3.设置作用域(Spring如何在并发情况下获取不完整的Bean)

以改为多例模式的prototype为例

写法一:@Scope("prototype")

写法二:@Scope(

ConfigurableBeanFactory.SCOPE_PROTOTYPE

)

打印结果

  • 6
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

sqyaa.

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

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

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

打赏作者

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

抵扣说明:

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

余额充值