Spring中的Bean自动装配是如何工作的?

huangapple go评论122阅读模式
英文:

How does bean self-auto-wiring work in Spring?

问题

在Spring中,我最近发现的一个非常酷而且令人费解的特性之一是self auto-wiring a bean

我所指的是这个:

class UserServiceImpl implements UserService {

    @Autowired
    UserService service;

    // 其他服务方法...
}

我的问题如下:

  • 这是如何实现的?

Spring是如何管理这个的?它是否将相同的对象分配给自动连接引用?像这样:

UserServiceImpl serviceImpl = new UserServiceImpl();
serviceImpl.setService(serviceImpl); // 显然这将通过反射而不是一个setter方法来完成。

还是

Spring是否创建了两个独立的对象?像这样:

UserServiceImpl obj1 = new UserServiceImpl();
UserServiceImpl obj2 = new UserServiceImpl();

obj1.setService(obj2);

然后在RestController中请求时只提供了obj1

  • 在Spring应用程序上下文中有多少个对象副本?

与前一个问题相关,实际上有多少个对象副本?

这是一个非常方便的特性,用于跨方法的事务等情况,但我想知道背后到底发生了什么。

英文:

One of the really cool and rather mind boggling features that I have recently discovered in Spring is self auto-wiring a bean.

What I am referring to is this:

class UserServiceImpl implements UserService {

    @Autowired
    UserService service;

    // other service methods...
}

My questions are as follows:

  • How is this implemented ?

How does Spring manage this ? Does it assign the same object to self auto-wire reference ? Like so:

UserServiceImpl serviceImpl = new UserServiceImpl();
serviceImpl.setService(serviceImpl); // Obviously this would be done via Reflection rather than a setter.

or

does Spring make 2 seperate objects? Like so :

UserServiceImpl obj1 = new UserServiceImpl();
UserServiceImpl obj2 = new UserServiceImpl();

obj1.setService(obj2);

And just gives us obj1 when we request it in a RestController ?

  • How many copies of the object are there in the Spring Application Context ?

Related to the previous question, how many actual copies of the object are there ?

Its a very convenient feature for things like transactions across methods, but I want to know what is exactly going on behind the scenes here.

答案1

得分: 1

  • 只有一个副本并使用反射

  • 让我们看看这个示例

@Service
public class SampleService {

    @Autowired
    private SampleService service;

    public SampleService getService() {
        return service;
    }
}
@SpringBootApplication
public class RestServiceApplication {

  public static void main(String[] args) {
    ConfigurableApplicationContext context
            = SpringApplication.run(RestServiceApplication.class, args);
    SampleService sampleService = context.getBean(SampleService.class);
    //这将打印true
    System.out.println(sampleService == sampleService.getService());
  }
}
  • 正如您所看到的,sampleService == sampleService.getService() 是真的。
英文:
  • There is only one copy and uses reflection

  • Lets look at this sample

    @Service
    public class SampleService {
    
        @Autowired
        private SampleService service;
    
        public SampleService getService() {
            return service;
        }
    }
    @SpringBootApplication
    public class RestServiceApplication {

      public static void main(String[] args) {
        ConfigurableApplicationContext context
                = SpringApplication.run(RestServiceApplication.class, args);
        SampleService sampleService = context.getBean(SampleService.class);
        //This will print true
        System.out.println(sampleService == sampleService.getService());
      }
    }
  • As you can see sampleService == sampleService.getService() is true;

答案2

得分: 1

不会在使用诸如 @Transactional、@Cachable 等注解时注入 UserServiceImpl,实际上它会注入代理。

但是它基于相同的实例。

自4.3版本开始,@Autowired 也考虑了自引用的注入(即,引用回当前注入的bean)。请注意,自引用是一种后备方式。对其他组件的常规依赖始终具有优先权。从这个意义上说,自引用不参与常规候选项选择,因此从不是首选项。相反,它们总是以最低优先级结束。在实际应用中,您应该仅将自引用作为最后的选择(例如,通过bean的事务代理调用相同实例上的其他方法)。在这种情况下,考虑将受影响的方法拆分到单独的代理bean中。或者,您可以使用 @Resource,它可以通过其唯一名称获取到当前bean的代理。

英文:

It doesn't inject the UserServiceImpl if you use some annotation like @Transactional,@Cachable etc. It actually injects the proxy.

But as the base it uses the same instance.

> As of 4.3, @Autowired also considers self references for injection (that is, references back to the bean that is currently injected). Note that self injection is a fallback. Regular dependencies on other components always have precedence. In that sense, self references do not participate in regular candidate selection and are therefore in particular never primary. On the contrary, they always end up as lowest precedence. In practice, you should use self references as a last resort only (for example, for calling other methods on the same instance through the bean’s transactional proxy). Consider factoring out the affected methods to a separate delegate bean in such a scenario. Alternatively, you can use @Resource, which may obtain a proxy back to the current bean by its unique name.

huangapple
  • 本文由 发表于 2020年7月29日 21:15:35
  • 转载请务必保留本文链接:https://go.coder-hub.com/63154484.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定