Spring 其它注解和杂项

news/2024/7/24 11:19:49 标签: spring, java, 后端

Spring 其它注解和杂项

1. @Lazy 注解

使用 @Lazy 注解的典型场景就是解决循环依赖问题。特别是构造注入,@Lazy 是弥补构造注入的『缺点』的关键。

当你对注入的 JavaBean 使用 @Lazy 注解时,Spring 注入的并非是这个单例对象,而是它的一个代理。当你(在未来)第一次使用这个 Bean 时,这个代理对象才会去 IoC 容器中找这个真正的 Bean 。

2. Spring 的 @Import 注解

在使用 maven 多模块的概念去构建项目时,我们的各个 @Bean 会分散在各个子模块中。

当然,我们可以仍在入口模块(web)中通过配置去配置各个模块必须创建的单例 Bean ,不过更好的方式是:将各个模块的配置也分散在各个模块中,由各个模块自己负责,最后让入口模块引入各个模块的配置即可。这样的话,责任更加分明。

  • 一个独立的配置类:ConfigA.java
java">@ComponentScan("com.example.commandpattern.config.a")
public class ConfigA {

  @Bean
  public String demo() {
    return "hello world";
  }
}
  • 另一个独立的配置类:ConfigB.java
java">@ComponentScan("com.example.commandpattern.config.b")
public class ConfigB {

  @Bean
  public LocalDate localDate() {
    return LocalDate.now();
  }
}
  • 主配置类:MainConfig.java
java">// 主配置类引入各个独立配置类
@Import({ConfigA.class, ConfigB.class})
public class MainConfig {
}
  • 引入,使用:
java">// 只需要将主配之类交给 Spring IoC 容器即可。
public static void main(String[] args) {
  ApplicationContext context = new AnnotationConfigApplicationContext(MainConfig.class);
  System.out.println(context.getBean(String.class));
  System.out.println(context.getBean(LocalDate.class));
  System.out.println(context.getBean(StudentDao.class));
  System.out.println(context.getBean(StudentService.class));
}

3. 特殊情况下的 Bean 注入

非托管对象中获取托管对象

有时你需要在非托管对象中获取 Spring 的 ApplicationContext

方案一:通用方案
java">@Slf4j
@Component
public class ApplicationContextHolder {

    private static ApplicationContext APPLICATION_CONTEXT;

    public ApplicationContextHolder(ApplicationContext applicationContext) {
        APPLICATION_CONTEXT = applicationContext;
    }

    public static ApplicationContext getApplicationContext() {
        return APPLICATION_CONTEXT;
    }
}

使用时调用:

java">ApplicationContextRegister.getApplicationContext().getBean(Xxx.class);
方案二:Spring 可用,Spring Boot 不可用

在 Spring 项目中可用,在 Spring Boot 项目中不可用。

还有一种方案可以实现同样效果,直接调用 Spring 提供的工具类:

java">ContextLoader.getCurrentWebApplicationContext().getBean(Xxx.class);

经测试发现,在 Spring Boot 项目中该方案无效。有人跟踪源码分析,因为 Spring Boot 的内嵌 Tomcat 和真实 Tomcat 还是有一定的区别,从而导致 Spring Boot 中该方案无法起到一起效果。

单例 Bean 中注入多例 Bean

保证每次获取都是新的多例 Bean 。

在 Spring 中 如果需要一个对象为多例,需要使用 @Scope 注解,指明作用于为 SCOPE_PROTOTYPE 即可。

当我们在一个单例的 Bean A 中注入多例 Bean B 时,由于 Spring 在初始化过程中加载 A 的时候已经将 B 注入到 A 中,所以直接当做成员变量时,只会获取一个实例。

我们可以通过以下两种优雅的方法解决:

  • 使用 Spring 的 ObjectFactory

  • 使用 @Looup 注解

方案一:Spring 的 ObjectFactory

为你的单例对象注入一个 Spring 提供的 ObjectFactory ,毫无疑问,ObjectFacotry 也是一个单例对象。

java">@Component
public class SingleBean {

    @Autowired
    ObjectFactory<PrototypeBean> factory;

    public void print(String name) {
        System.out.println("single service is " + this);
        factory.getObject().test(name);
    }
}

但是,在单例对象中,你只要通过 ObjectFactory(的封装)ObjectFactory.getObject() 方法去获得多例对象,每次它返回给你的都是一个『新』的对象。

方案二:@Lookup 注解

我们可以使用 Spring 的 @Lookup 注解。该注解主要为单例 Bean 实现一个 cglib 代理类,并通过 BeanFacoty.getBean() 来获取对象。

@Lookup 注解是一个作用在方法上的注解,被其标注的方法会被 Spring 通过 cglib 实现的代理类重写,然后根据其返回值的类型,容器调用 BeanFactory 的 getBean() 方法来返回一个 bean 。

java">@Component
public class SingleBean {

  public void printClass() {
    System.out.println("This is SingleBean: " + this);
    getPrototypeBean().xxx();
  }
 
  /**
   * 方法的存在,以及方法的返回值是关键。
   * 该方法会被 Spring 重写:Spring 会来保证在『别处』你调用这个方法时,每次都返回一个新的 PrototypeBean 对象给你。
   */
  @Lookup
  public PrototypeBean getPrototypeBean() {
    return null;
  }
}

http://www.niftyadmin.cn/n/5427674.html

相关文章

零知识玩转AVH(5)—— 怎么玩(4)

接前一篇文章&#xff1a;零知识玩转AVH&#xff08;4&#xff09;—— 怎么玩&#xff08;3&#xff09; 上一回经过了一个艰苦的探索过程&#xff0c;最终完成了“arm-avh-best-practice-project-product-subscription-guide-cn.pdf”即“Arm虚拟硬件实践专题一&#xff1a;产…

应用开发技术巩固指南

前言 起初毕业前夕&#xff0c;个人已经开始自学Android开发&#xff0c;由于没有指导&#xff0c;所以起步很难&#xff0c;写的代码也规范&#xff0c;逻辑不清&#xff0c;技术止步于皮毛&#xff0c;很多东西都不理解。 后来步入工作&#xff0c;逐渐熟悉了这个方向&…

海豚调度系列之:任务类型——Flink节点

海豚调度系列之&#xff1a;任务类型——Flink节点 一、Flink节点二、创建任务三、任务参数四、任务样例1.在 DolphinScheduler 中配置 flink 环境2.任务流程 五、注意事项 一、Flink节点 Flink 任务类型&#xff0c;用于执行 Flink 程序。对于 Flink 节点&#xff1a; 当程序…

idea安装了某个插件之后启动报错打不开怎么办

刚才安装了个这个插件 然后重启的时候就报错了 如下 不用慌&#xff0c;看一下报错日志&#xff0c;找到插件的位置给他删了就行了&#xff0c;往下拉一点 找到这个文件给他删了&#xff0c;再启动就好了。记得删之前先把上面这个报错弹框关了&#xff0c;不然会提示文件占用不…

基于YOLOv8深度学习的木薯病害智能诊断与防治系统【python源码+Pyqt5界面+数据集+训练代码】深度学习实战

《博主简介》 小伙伴们好&#xff0c;我是阿旭。专注于人工智能、AIGC、python、计算机视觉相关分享研究。 ✌更多学习资源&#xff0c;可关注公-仲-hao:【阿旭算法与机器学习】&#xff0c;共同学习交流~ &#x1f44d;感谢小伙伴们点赞、关注&#xff01; 《------往期经典推…

快速在Linux系统安装MySQL

虚拟机使用docker安装MySQL 使用docker拉去镜像 查看mysql的镜像 docker search mysql拉去mysql镜像 docker pull mysql查看下载的镜像 docker images启动容器 docker start mysql进入MySQL容器 docker exec -it mysql /bin/bash登录mysql mysql -u root -p检查是否进入…

5.58 BCC工具之mysqld_qslower.py解读

一,工具简介 mysqld_qslower工具用于追踪 MySQL 服务器提供的查询,并打印出那些超过延迟(查询时间)阈值的查询。默认情况下,使用的阈值为 1 毫秒。 二,代码示例 #!/usr/bin/env pythonfrom __future__ import print_function from bcc import BPF, USDT import sys# a…

【Leetcode每日一题】 递归 - 面试题 08.06. 汉诺塔问题(难度⭐)(33)

1. 题目解析 题目链接&#xff1a;面试题 08.06. 汉诺塔问题 这个问题的理解其实相当简单&#xff0c;只需看一下示例&#xff0c;基本就能明白其含义了。 2.算法原理 这是一道关于递归算法的经典问题——汉诺塔。我们可以通过分析不同规模的情况来深入理解其解决思路&#…