前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >不一样的视角来学习Spring源码之容器与Bean---下

不一样的视角来学习Spring源码之容器与Bean---下

作者头像
大忽悠爱学习
发布2022-05-10 16:11:42
2260
发布2022-05-10 16:11:42
举报
文章被收录于专栏:c++与qt学习
  • 可以将通过 server.servlet.session.timeout=30s 观察 session bean 的销毁
  • ServletContextScope 销毁机制疑似实现有误,,待定

分析 - singleton 注入其它 scope 失效

以单例注入多例为例

代码语言:javascript
复制
@Scope("prototype")
@Component
public class F1 {
}
代码语言:javascript
复制
@Scope(value = "prototype", proxyMode = ScopedProxyMode.TARGET_CLASS)
@Component
public class F2 {
}
代码语言:javascript
复制
@Scope("prototype")
@Component
public class F3 {
}
代码语言:javascript
复制
@Scope("prototype")
@Component
public class F4 {
}

有一个单例对象 E

代码语言:javascript
复制
@Component
public class E {
    private static final Logger log = LoggerFactory.getLogger(E.class);

    private F f;

    public E() {
        log.info("E()");
    }

    @Autowired
    public void setF(F f) {
        this.f = f;
        log.info("setF(F f) {}", f.getClass());
    }

    public F getF() {
        return f;
    }
}

测试

代码语言:javascript
复制
E e = context.getBean(E.class);
F f1 = e.getF();
F f2 = e.getF();
System.out.println(f1);
System.out.println(f2);

输出

代码语言:javascript
复制
com.dhy.demo.cycle.F@6622fc65
com.dhy.demo.cycle.F@6622fc65

发现它们是同一个对象,而不是期望的多例对象

对于单例对象来讲,依赖注入仅发生了一次,后续再没有用到多例的 F,因此 E 用的始终是第一次依赖注入的 F


解决

  • 仍然使用 @Lazy 生成代理
  • 代理对象虽然还是同一个,但当每次使用代理对象的任意方法时,由代理创建新的 f 对象
代码语言:javascript
复制
@Component
public class E {
    @Autowired
    @Lazy
    public void setF(F f) {
        this.f = f;
        log.info("setF(F f) {}", f.getClass());
    }
    // ...
}

注意

  • @Lazy 加在也可以加在成员变量上,但加在 set 方法上的目的是可以观察输出,加在成员变量上就不行了
  • @Autowired 加在 set 方法的目的类似

输出

代码语言:javascript
复制
E: setF(F f) class com.itheima.demo.cycle.F$$EnhancerBySpringCGLIB$$8b54f2bc
F: F()
com.dhy.demo.cycle.F@3a6f2de3
F: F()
com.dhy.demo.cycle.F@56303b57

从输出日志可以看到调用 setF 方法时,f 对象的类型是代理类型


4种解决方法

如果 jdk > 8, 运行时请添加 --add-opens java.base/java.lang=ALL-UNNAMED,否则spring可能会反射调用jdk内部方法,造成访问权限异常被拒

代码语言:javascript
复制
@Component
public class E {

    @Lazy
    @Autowired
    private F1 f1;

    @Autowired
    private F2 f2;

    @Autowired
    private ObjectFactory<F3> f3;

    @Autowired
    private ApplicationContext context;

    public F1 getF1() {
        return f1;
    }

    public F2 getF2() {
        return f2;
    }

    public F3 getF3() {
        return f3.getObject();
    }

    public F4 getF4() {
        return context.getBean(F4.class);
    }
}

对于f2的设置如下:

代码语言:javascript
复制
@Scope(value = "prototype", proxyMode = ScopedProxyMode.TARGET_CLASS)
@Component
public class F2 {
}

本质也是生成一个代理对象,每次使用代理对象的任意方法时,由代理创建新的 F2 对象

剩余两种方法,都是从IOC容器中获取bean对象


小结

出现上面scope失效的原因在于在依赖注入阶段就去获取了对应scope的值,然后后续所有使用到该scope类型的对象都是直接返回一开始注入好的值,而不是每次都向容器去获取一下。

因此想要解决这个办法,就必须要推迟socpe bean的获取,方法有上面说的四种

更多细节可以参考本文

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-03-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 不一样的视角来学习Spring源码之容器与Bean---下
  • BeanFactory 后处理器
    • BeanFactory 后处理器的作用
      • ConfigurationClassPostProcessor负责解析@ComponentScan @Bean @Import @ImportResource
        • MapperScannerConfigurer负责扫描mapperScan注解
          • 收获💡
        • 模拟解析 @ComponentScan
          • 收获💡
        • 模拟解析 @Bean
          • 收获💡
        • 模拟解析 Mapper 接口
          • 收获💡
      • 6) Aware 接口
        • Aware 接口及 InitializingBean 接口
          • 疑问?
          • @Autowired失效了?
          • 小结
      • 7) 初始化与销毁
        • 初始化销毁顺序
          • 收获💡
          • 收获💡
          • 分析 - singleton 注入其它 scope 失效
          • 解决
          • 小结
      • 8) Scope
      相关产品与服务
      容器服务
      腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档