类注册到Spring容器,类实现的接口可以获取到该类的bean实例?

发布时间:2024年01月09日


例子,BookServiceImpl类实现BookService接口,BookServiceImpl通过@Service注解注册到Spring容器中,BookServiceImpl将被Spring Boot自动扫描并实例化为一个Bean。

@Service
public class BookServiceImpl implements BookService {
...
}

一、获取bean实例

可以通过下面3种方式获取:

  • 属性注入【推荐方式】:通过在类的字段上使用@Autowired注解进行注入。也可以在接口上使用@Autowired注解进行注入,Spring会根据接口的类型自动查找并注入相应的实现类。
@Autowired
private BookService bookService;

@Autowired
private BookServiceImpl bookServiceImpl;
  • 方法注入:通过在类中定义一个方法,并使用@Autowired注解进行注入。
private BookService bookService;

@Autowired
public void injectDependency(BookService bookService) {
    this.bookService = bookService;
}
  • 构造函数注入:通过在类的构造函数上使用@Autowired注解,Spring会自动查找并注入相应的Bean。
private BookService bookService;

@Autowired
public MyClass(BookService bookService) {
    this.bookService = bookService;
}

无论使用哪种方式,Spring Boot都会自动查找并注入实现了BookService接口的Bean,从而可以在代码中使用BookService接口的功能。需要注意的是,如果容器中存在多个实现了BookService接口的Bean,可以使用@Qualifier注解来指定具体要注入的Bean。例如:

@Autowired
@Qualifier("myBookService")
private BookService bookService;

也可以使用@Resource来制定注入的bean名字,例如:

@Resource(name = "myBookService")
private BookService bookService;

这样,可以根据myBookService的名称来注入对应的Bean。

当使用@Autowired或@Resource注解时,Spring会根据指定的名称或类型在ApplicationContext中查找对应的bean实例。底层实现中,Spring会调用ApplicationContext的getBean方法,传入指定的名称或类型作为参数。

二、注册到Spring容器中的名称和类型是什么?

验证代码:

public static void main(String[] args) {
	ConfigurableApplicationContext applicationContext = SpringApplication.run(Application.class, args);
	System.out.println(applicationContext.getBean(BookService.class));
	System.out.println(applicationContext.getBean(BookServiceImpl.class));
	System.out.println(applicationContext.getBean("bookServiceImpl"));
	System.out.println(applicationContext.getBean("bookService"));
}

cn.forlan.service.impl.BookServiceImpl@68ddd415
cn.forlan.service.impl.BookServiceImpl@68ddd415
cn.forlan.service.impl.BookServiceImpl@68ddd415
Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'bookService' available
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:816)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1288)
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:298)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202)
	at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1109)
	at cn.forlan.Application.main(Application.java:36)

可以看到注册到Spring中的名称是bookServiceImpl,也就是名称是将类名的首字母小写作为Bean的名称。类型是BookService.class和BookServiceImpl.class,也就是除了加@Service的类,也会把类实现的接口也注册进入。

三、Spring通过@Autowired注入的是接口,怎么找到对应的实现类的?

在Spring Boot中,当使用@Autowired注解注入接口时,Spring会根据接口的类型查找对应的实现类。Spring使用了依赖注入和反射机制来实现这一功能。

当使用@Autowired注解时,Spring会扫描应用程序上下文中的所有bean,并尝试将其与接口类型进行匹配。如果找到多个匹配的实现类,Spring会抛出异常。如果找不到匹配的实现类,Spring也会抛出异常。

为了确保@Autowired注解能够正确地找到接口的实现类,您需要确保以下几点:

  • 实现类必须以@Component或其他相关注解进行注解,以使其成为Spring的bean。
  • 实现类必须实现接口,并且接口类型必须在@Autowired注解中指定。

源码如下::
在这里插入图片描述
调用方法栈如下:

isTypeMatch:537, AbstractBeanFactory (org.springframework.beans.factory.support)
doGetBeanNamesForType:530, DefaultListableBeanFactory (org.springframework.beans.factory.support)
getBeanNamesForType:503, DefaultListableBeanFactory (org.springframework.beans.factory.support)
getBeanNamesForType:480, DefaultListableBeanFactory (org.springframework.beans.factory.support)
getBeanNamesForType:473, DefaultListableBeanFactory (org.springframework.beans.factory.support)
resolveNamedBean:1159, DefaultListableBeanFactory (org.springframework.beans.factory.support)
resolveBean:420, DefaultListableBeanFactory (org.springframework.beans.factory.support)
getBean:350, DefaultListableBeanFactory (org.springframework.beans.factory.support)
getBean:343, DefaultListableBeanFactory (org.springframework.beans.factory.support)
getBean:1127, AbstractApplicationContext (org.springframework.context.support)

总的来说,就是通过DefaultListableBeanFactory的getBeanNamesForType,最终调用doGetBeanNamesForType去匹配,返回和接口相关的类,比如它的子类,如果有多个,会报错,我们可以指定名称,进行过滤,最终返回一个bean。

文章来源:https://blog.csdn.net/qq_36433289/article/details/135389522
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。