Spring-Bean 作用域

news2025/1/11 9:04:35

作用域

在这里插入图片描述

作用域案例

public class BeanScopeDemo {
    @Autowired
    @Qualifier("singletonPerson")
    Person person;

    @Autowired
    @Qualifier("prototypePerson")
    Person person1;

    @Autowired
    @Qualifier("prototypePerson")
    Person person2;

    @Autowired
    Set<Person> personSet;
    /**
     * 创建bean
     * @return
     */
    public static Person createPerson(){
        Person person = new Person();
        person.setId(System.currentTimeMillis());
        person.setName(System.currentTimeMillis()+"");
        return person;
    }

    /**
     * 查找
     * @param context
     */
    public static void scopeBeanLookUp(AnnotationConfigApplicationContext context){
        for (int i = 0; i < 3; i++) {
            Person prototypePerson = context.getBean("prototypePerson", Person.class);
            System.out.println("prototypePerson" + prototypePerson);
            Person singletonPerson = context.getBean("singletonPerson", Person.class);
            System.out.println("singletonPerson" + singletonPerson);
        }
    }
    private static void scopedBeansByInjection(AnnotationConfigApplicationContext context) {
        BeanScopeDemo bean = context.getBean(BeanScopeDemo.class);
        System.out.println(bean.person);
        System.out.println(bean.person1);
        System.out.println(bean.person2);
        System.out.println(bean.personSet);
    }
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        context.register(BeanScopeDemo.class);
        context.refresh();
        scopeBeanLookUp(context);
        scopedBeansByInjection(context);
        context.close();
    }

    /**
     * 默认scope 就是singleton
     * @return
     */
    @Bean
    public static Person singletonPerson(){
        return createPerson();
    }
    @Bean
    @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    public static Person prototypePerson(){
        return createPerson();
    }
}

运行结果:
在这里插入图片描述
结论:
1 singleton Bean 无论依赖查找还是依赖注入,均为同一个对象
2 prototype Bean 无论依赖查找还是依赖注入,均为新生成的对象
3 如果为集合类型,则单例和原型对象各一个

单例模式和原型模式生命周期的不同

public class Person implements BeanNameAware {
    private Long id;
    private String name;
    /**
     * 不需要序列化
     */
    private transient String beanName;
    @Override
    public String toString() {
        return "Person{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
    @PostConstruct
    public void init() {
        System.out.println(this.beanName + " : init execute");
    }
    @PreDestroy
    public void destroy() {
        System.out.println(this.beanName + " : destroy execute");
    }

    @Override
    public void setBeanName(String name) {
        this.beanName = name;
    }
}

改造Person以后我们继续调用上面的方法:
在这里插入图片描述
我们可以得到下面的结论:
1 原型和单例模式都是会执行postconstruct
2 原型模式的生命周期不能被spring完全管理,不会执行销毁方法

如果我们需要销毁,采用下面这种方式来操作

public class BeanScopeDemo implements DisposableBean {
    @Autowired
    @Qualifier("singletonPerson")
    Person person;

    @Autowired
    @Qualifier("prototypePerson")
    Person person1;

    @Autowired
    @Qualifier("prototypePerson")
    Person person2;

    @Autowired
    Map<String, Person> personMap;
    @Autowired
    ConfigurableListableBeanFactory beanFactory;

    /**
     * 创建bean
     *
     * @return
     */
    public static Person createPerson() {
        Person person = new Person();
        person.setId(System.currentTimeMillis());
        person.setName(System.currentTimeMillis() + "");
        return person;
    }

    /**
     * 查找
     *
     * @param context
     */
    public static void scopeBeanLookUp(AnnotationConfigApplicationContext context) {
        for (int i = 0; i < 3; i++) {
            Person prototypePerson = context.getBean("prototypePerson", Person.class);
            System.out.println("prototypePerson" + prototypePerson);
            Person singletonPerson = context.getBean("singletonPerson", Person.class);
            System.out.println("singletonPerson" + singletonPerson);
        }
    }

    private static void scopedBeansByInjection(AnnotationConfigApplicationContext context) {
        BeanScopeDemo bean = context.getBean(BeanScopeDemo.class);
        System.out.println(bean.person);
        System.out.println(bean.person1);
        System.out.println(bean.person2);
        System.out.println(bean.personMap);
    }

    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        context.register(BeanScopeDemo.class);
        context.refresh();
        scopeBeanLookUp(context);
        scopedBeansByInjection(context);
        context.close();
    }

    /**
     * 默认scope 就是singleton
     *
     * @return
     */
    @Bean
    public static Person singletonPerson() {
        return createPerson();
    }

    @Bean
    @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    public static Person prototypePerson() {
        return createPerson();
    }

    @Autowired
    ConfigurableListableBeanFactory beanFactory;
    @Override
    public void destroy() throws Exception {
        this.person1.destroy();
        this.person2.destroy();
        for (Map.Entry<String, Person> entry : this.personMap.entrySet()) {
            String key = entry.getKey();
            BeanDefinition bd = beanFactory.getBeanDefinition(key);
            if (bd.isPrototype()) {
                entry.getValue().destroy();
            }

        }
    }
}

运行结果:
在这里插入图片描述
可以看到原型模式的对象也被销毁了。

自定义Scope

1 首先自定义Scope

public class ThreadLocalScope implements Scope {
    public static final String SCOPE_NAME = "thread_local";
    private NamedThreadLocal<Map<String, Object>> threadLocal = new NamedThreadLocal<Map<String, Object>>("thread-local-scope") {
       public Map<String, Object> initialValue() {
           return new HashMap<>();
       }
    };
    private Map<String, Object> getContext() {
        return threadLocal.get();
    }
    @Override
    public Object get(String name, ObjectFactory<?> objectFactory) {
        Map<String, Object> context = getContext();
        Object object = context.get(name);
        if (object == null) {
            object = objectFactory.getObject();
            context.put(name, object);
        }
        return object;
    }
    @Override
    public Object remove(String name) {
        return getContext().remove(name);
    }
    @Override
    public void registerDestructionCallback(String name, Runnable callback) {
        remove(name);
    }
    @Override
    public Object resolveContextualObject(String key) {
        return getContext().get(key);
    }
    @Override
    public String getConversationId() {
        return Thread.currentThread().getName();
    }
}

2 查找方式

public class ThreadLocalScopeDemo {
    /**
     * 默认scope 就是singleton
     *
     * @return
     */
    @Bean
    @Scope(ThreadLocalScope.SCOPE_NAME)
    public static Person singletonPerson() {
        return createPerson();
    }
    /**
     * 创建bean
     *
     * @return
     */
    public static Person createPerson() {
        Person person = new Person();
        person.setId(System.currentTimeMillis());
        person.setName(System.currentTimeMillis() + "");
        return person;
    }
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        context.register(ThreadLocalScopeDemo.class);
        // 注册工厂 也就是 ThreadLocalScope.SCOPE_NAME 这个注入会走这里
        context.addBeanFactoryPostProcessor(beanFactory -> {
            beanFactory.registerScope(ThreadLocalScope.SCOPE_NAME, new ThreadLocalScope());
        });
        context.refresh();
        scopeBeansLookUp(context);
        context.close();
    }
    private static void scopeBeansLookUp(ApplicationContext context) {
    	// 这里开启三个现场去查找
        for (int i = 0; i < 3; i ++) {
            Thread thread = new Thread(() -> {
                Person person = context.getBean( Person.class);
                System.out.println(Thread.currentThread().getId()+ " : " + person);
            });
            thread.start();
            try {
                thread.join();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

结果:
在这里插入图片描述
也就几说我们可以减少对象的创建因为我们在Threadlocal里面存储了,所以线程内部是可以复用的,不存在线程安全问题。
比如SimpleDateFormat是非线程安全的,所以可以采用这种方式来实现。

拓展提示:SpingCloud中的@RefreshScope
参考资料:小马哥核心编程思想

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1665062.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

第41天:WEB攻防-ASP应用HTTP.SYS短文件文件解析Access注入数据库泄漏

第四十一天 一、ASP-SQL注入-Access数据库 1.解释 ACCESS数据库无管理帐号密码&#xff0c;顶级架构为表名&#xff0c;列名&#xff08;字段&#xff09;&#xff0c;数据&#xff0c;所以在注入猜解中一般采用字典猜解表和列再获取数据&#xff0c;猜解简单但又可能出现猜解…

有哪些高性价比的开放式耳机推荐?五款超好用的耳机推荐

近年来&#xff0c;开放式耳机受到了越来越多人的关注&#xff0c;特别是对于运动爱好者来说&#xff0c;在运动的过程中&#xff0c;传统的有线耳机不适合户外运动&#xff0c;不仅佩戴不稳&#xff0c;线还容易缠绕&#xff0c;而普通的蓝牙耳机长时间佩戴会感觉耳朵不适。在…

分享5个免费AI写作软件

在数字化时代&#xff0c;人工智能&#xff08;AI&#xff09;正以惊人的速度渗透到我们生活的方方面面&#xff0c;而写作领域也不例外。AI写作工具的出现&#xff0c;不仅改变了传统的写作流程&#xff0c;更在创意表达、文本生成、语言校正等方面展现了其独特的优势。这些工…

构建无服务器数仓(二)Apache DolphinScheduler 集成以及 LOB 粒度资源消费分析

引言 在数据驱动的世界中&#xff0c;企业正在寻求可靠且高性能的解决方案来管理其不断增长的数据需求。本系列博客从一个重视数据安全和合规性的 B2C 金融科技客户的角度来讨论云上云下混合部署的情况下如何利用亚马逊云科技云原生服务、开源社区产品以及第三方工具构建无服务…

12个网上赚钱野路子信息差,人人可做的赚钱小项目!

在这个多元化的时代&#xff0c;副业已经成为许多人增加收入、实现自我价值的重要途径。今天&#xff0c;我们就来聊聊那些既有趣又能赚钱的副业项目&#xff0c;让你的钱包鼓起来&#xff01; 1.文字创作 写作不仅是情感的宣泄&#xff0c;更是财富的积累。无论是自媒体文、软…

ISIS学习二——与OSPF相比的ISIS报文以及路由计算

目录 一.ISIS支持的网络类型 1.OSPF支持 2.ISIS支持 二.ISIS最优路径的选取 &#xff08;1&#xff09;.ISIS开销值设置 1.全局开销 2.接口开销 3.根据带宽设置开销 &#xff08;2&#xff09;.ISIS的次优路径 三.ISIS报文格式 1.ISIS专用报头——TLV 2.ISIS通用头…

传输层之 UDP 协议

UDP协议端格式 教科书上的&#xff1a; 16位UDP长度&#xff0c;表示整个数据报&#xff08;UDP首部UDP数据&#xff09;的最大长度&#xff0c;描述了这个数据报多长&#xff1b; 实际上的&#xff1a; UDP 会把载荷数据&#xff0c;就是通过 UDP Socket&#xff0c;即 sen…

第十二届蓝桥杯省赛真题 Java B 组【原卷】

文章目录 发现宝藏【考生须知】试题 A: ASC试题 B : 卡片试题 C: 直线试题 D: 货物摆放试题 E: 路径试题 F: 时间显示试题 G: 最少砝码试题 H: 杨辉三角形试题 I: 双向排序试题 J: 括号序列 发现宝藏 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;…

Flink DataSink介绍

介绍 Flink DataSink是Apache Flink框架中的一个重要组件&#xff0c;它定义了数据流经过一系列处理后最终的输出位置。以下是关于Flink DataSink的详细介绍&#xff1a; 概念&#xff1a;DataSink主要负责对经过Flink处理后的流进行一系列操作&#xff0c;并将计算后的数据结…

C语言例题36、判断一个数是否是回文数

题目要求&#xff1a;输入一个5位数&#xff0c;判断它是不是回文数。即12321是回文数 #include <stdio.h>int main() {int x;int ge, shi, qian, wan;printf("请输入一个5位数&#xff1a;");scanf("%d", &x);ge x % 10; //个sh…

网络运维故障排错思路!!!!!(稳了!!!)

1 网络排错的必备条件 为什么要先讲必备条件&#xff1f;因为这里所讲的网络排错并不仅仅是停留在某一个小小命令的使用上&#xff0c;而是一套系统的方法&#xff0c;如果没有这些条件&#xff0c;我真的不能保证下面讲的这些你可以听得懂&#xff0c;并且能运用到实际当中&a…

自主实现Telnet流量抓取

自主实现Telnet流量抓取 根据测试需求&#xff0c;需要抓取Telnet流量包&#xff0c;使用wireshark Python&#xff08;socket、telnetlib库&#xff09;实现 实现代码 主要此处有坑&#xff0c; 根据协议规则&#xff0c;wireshark 默认端口为23 的是Telnet协议&#xff0…

ios 开发如何给项目安装第三方库,以websocket库 SocketRocket 为例

1.brew 安装 cococapods $ brew install cocoapods 2、找到xcode项目 的根目录&#xff0c;如图&#xff0c;在根目录下创建Podfile 文件 3、在Podfile文件中写入 platform :ios, 13.0 use_frameworks! target chat_app do pod SocketRocket end project ../chat_app.x…

【Go语言初探】(一)、Linux开发环境建立

一、操作系统选择 选择在Windows 11主机上运行的CentOS 7 Linux 虚拟机&#xff0c;虚拟化平台为VMWare Workstation. 二、安装Go语言环境 访问Go语言官网&#xff0c;选择Linux版本下载&#xff1a; 解压&#xff1a; tar -xvf go1.22.3.linux-amd64.tar.gz检验安装结果&…

初识C语言——第十四天

指针 总结&#xff1a;指针变量是用来干啥的呢&#xff0c;一是用来存放别人的地址的&#xff0c;指针是有类型的&#xff0c;这个类型是如何写的&#xff1b;二是当我有一天通过*(解引用符&#xff09;找到我所要找的对象&#xff0c;来操作所指向的对象。 #define _CRT_SECUR…

2024年4月12日饿了么春招实习试题【第二题:魔法师】-题目+题解+在线评测【二分】

2024年4月12日饿了么春招实习试题【第二题:魔法师】-题目题解在线评测【二分】 题目描述&#xff1a;输入格式输出格式样例输入样例输出评测数据与规模 解题思路一&#xff1a;解题思路二&#xff1a;解题思路三&#xff1a;动态规划 题目描述&#xff1a; 塔子哥是一名魔法师…

搜维尔科技:【案例分享】Xsens用于工业制造艺术创新设计平台

用户名称&#xff1a;北京理工大学 主要产品&#xff1a;Xsens MVN Awinda惯性动作捕捉系统 在设计与艺术学院的某实验室内&#xff0c;通过Xsens惯性动作捕捉&#xff0c;对人体动作进行捕捉&#xff0c;得到人体三维运动数据&#xff0c;将捕到的数据用于后续应用研究。…

二维费用背包分组背包

二维费用背包&分组背包 一定要做的

Stable Diffusion的技术原理

一、Stable Diffusion的技术原理 Stable Diffusion是一种基于Latent Diffusion Models&#xff08;LDMs&#xff09;实现的文本到图像&#xff08;text-to-image&#xff09;生成模型。其工作原理主要基于扩散过程&#xff0c;通过模拟数据的随机演化行为&#xff0c;实现数据…

接收区块链的CCF会议--NDSS 2025 截止7.10 附录用率

会议名称&#xff1a;Network and Distributed System Security Symposium (NDSS) CCF等级&#xff1a;CCF A类学术会议 类别&#xff1a;网络与信息安全 录用率&#xff1a;2024年接收率19.5% Submissions are solicited in, but not limited to, the following areas: Ant…