Java Spring@Autowire与getBean(className)的性能

Java Spring@Autowire与getBean(className)的性能,java,spring,performance,autowired,Java,Spring,Performance,Autowired,代码有两种变体: public class MyClass { public void myMethod() { AnotherClass object = SpringContexHolder.getContext().getBean(AnotherClass.class); object.doSomething(); } } @Component public class MyClass { @Autowired AnotherClass object; publi

代码有两种变体:

public class MyClass {
 public void myMethod() {
  AnotherClass object = SpringContexHolder.getContext().getBean(AnotherClass.class);
  object.doSomething();
 }
}

@Component
public class MyClass {
@Autowired
AnotherClass object;     

public void myMethod() {
 object.doSomething();
}
}
在第一个变体中会有性能损失吗(顺便说一句,它不是Springbean,只是简单的类)? 自动连线与getBean的功能相同吗

我想我应该把我的问题扩大一点。情况是,我加入的团队仅通过getBean(className)在项目中使用Spring注入。我猜原因是,大多数已经编写的项目类不是SpringBean,在一个类中使用自动连接意味着通常也会生成依赖类bean,以此类推,直到大多数类成为bean

好的,我想我理解这种方法的可测试性惩罚和总体上缺乏代码风格。但这不是一种表现惩罚吗?准备就绪的Spring singleton在启动时构建,所有字段都自动连接,从非Spring非singleton类(特别是在关键位置)调用getBean(classname)(afaik比纯hashmap.get(object))的速度慢几倍,这两者的性能是否有区别

另外,我创建了类似smth的迷你基准测试(我知道由于GC、JIT等的工作,很难获得真实的信息,但无论如何…)。 我的结果是(数字越大-越差):
自动连线时间-193,GetBean时间-2161,同一类中的方法-173,另一类中的静态方法-206,IMO,您不应该使用这些。正如一些用户在评论中已经提到的,你不应该在意性能。但对于可测试性,请使用基于构造函数的注入(并且@Autowired是隐式的):


每次需要访问bean时,在Spring上下文(通常是复合的)中查找bean是低效的。实际上,您要在多个哈希表中多次查找一个项,破坏CPU缓存,浪费时间,并且由于执行路径更复杂,可能会阻止其他优化,如内联

一定要使用自动布线(基于注释或基于构造函数)。这样,在应用程序启动时查找一次,然后通过直接引用访问该类


即使使用
@Autowired
注释,可测试性也非常好。您只需自动关联模拟而不是实际对象。此外,还可以查看和注释以注入mock,并以其他方式增强Spring上下文以进行测试。

始终使用第二种方法进行可读性和测试。而且,第一种方法只有在没有找到bean的情况下调用
myMethod
时才会失败,而第二种方法甚至不会让应用程序正确启动,因此您不应该真正关心spring的性能,因为它本身已经有相当大的开销,并且可能不会在性能关键型应用程序imo中使用,您不应该真正关心应用程序在启动时的性能。您使用自动连线是因为它更方便;如果您关心启动时间,那么您可以完全避免使用Spring,但缺点是您需要手动执行所有操作。我不认为“使用Spring”与“您不应该真正关心性能”相对应。这个问题基于使用spring,
getBean
@autowired
之间的性能。我认为有两个概念“依赖查找”和“依赖注入”。getBean是依赖项查找@自动连线是依赖注入。这个问题是好的。Spring-Test实际上是用于集成测试的,用它进行单元测试真的很痛苦。使用构造函数注入对象允许您通过注入mock(例如来自mockito)来进行单元测试,而无需使用所有spring样板。当禁用类路径扫描并为所有依赖项提供mock时,我通常不会遇到spring mock的问题。但是Mockito肯定也很有用。
@Component
public class MyClass {

  private final AnotherClass object;     

  public MyClass(AnotherClass object) {
    this.object = object;
  }
}