拨开荷叶行,寻梦已然成。仙女莲花里,翩翩白鹭情。
IMG-LOGO
主页 文章列表 Spring @Service注解应放置在哪里?

Spring @Service注解应放置在哪里?

白鹭 - 2021-11-24 657 0 0

1.简介

作为软件开发人员,我们一直在寻找使用给定技术或库的最佳实践。自然,有时会有辩论。

这样的争论之一就是关于Spring的@Service注释的放置。由于Spring提供了定义bean的替代方法,因此值得注意构造型注释的位置。

在本教程中,我们将研究@Service批注,并检查将其放在接口,抽像类或具体类上是否最有效

2.接口上的@Service

一些开发人员可能决定将@Service放在接口上,因为他们想要:

  • 明确表明接口只能用于服务级别的目的
  • 定义新的服务实现,并在启动过程中将它们自动检测为Spring Bean

让我们看一下我们对接口进行注解的样子:

@Service

 public interface AuthenticationService {



 boolean authenticate(String username, String password);

 }

我们注意到, AuthenticationService现在变得更具自我描述性。 @Service标记建议开发人员仅将其用于业务层服务,而不用于数据访问层或任何其他层。

通常,这很好,但是有一个缺点。通过将Spring的@Service放在接口上,我们创建了一个额外的依赖项,并将我们的接口与外部库耦合。

接下来,为了测试新服务bean的自动检测,让我们创建AuthenticationService的实现:

public class InMemoryAuthenticationService implements AuthenticationService {



 @Override

 public boolean authenticate(String username, String password) {

 //...

 }

 }

我们应该注意,我们的新实现InMemoryAuthenticationService上没有@Service批注。我们仅在AuthenticationService接口上保留@Service

因此,让我们在基本的Spring Boot设置的帮助下运行Spring上下文:

@SpringBootApplication

 public class AuthApplication {



 @Autowired

 private AuthenticationService authService;



 public static void main(String[] args) {

 SpringApplication.run(AuthApplication.class, args);

 }

 }

当运行我们的应用程序时,**我们得到臭名昭著的NoSuchBeanDefinitionException,**并且Spring上下文无法启动:

org.springframework.beans.factory.NoSuchBeanDefinitionException:

 No qualifying bean of type 'com.baeldung.annotations.service.interfaces.AuthenticationService' available:

 expected at least 1 bean which qualifies as autowire candidate. Dependency annotations:

 ...

因此,在接口上放置@Service不足以自动检测Spring组件

3. @Service类上的@Service

在抽像类上使用@Service注解并不常见。

让我们对其进行测试,看看它是否达到了使Spring自动检测实现类的目的。

我们将从头定义一个抽像类开始,并在其上添加@Service批注:

@Service

 public abstract class AbstractAuthenticationService {



 public boolean authenticate(String username, String password) {

 return false;

 }

 }

接下来,我们扩展AbstractAuthenticationService创建一个不带注释的具体实现

public class LdapAuthenticationService extends AbstractAuthenticationService {



 @Override

 public boolean authenticate(String username, String password) {

 //...

 }

 }

因此,我们还更新了AuthApplication ,以注入新的服务类

@SpringBootApplication

 public class AuthApplication {



 @Autowired

 private AbstractAuthenticationService authService;



 public static void main(String[] args) {

 SpringApplication.run(AuthApplication.class, args);

 }

 }

我们应该注意,我们不尝试在此处直接注入抽像类,这是不可能的。相反,我们打算仅根据抽像类型获取具体类LdapAuthenticationService的实例。正如Liskov替代原则所建议的那样,这是一个好习惯。

因此,我们再次运行AuthApplication

org.springframework.beans.factory.NoSuchBeanDefinitionException:

 No qualifying bean of type 'com.baeldung.annotations.service.abstracts.AbstractAuthenticationService' available:

 expected at least 1 bean which qualifies as autowire candidate. Dependency annotations:

 ...

如我们所见,Spring上下文没有启动。它**以相同的NoSuchBeanDefinitionException**异常结束。

当然,在抽像类上使用@Service注释在Spring中没有任何作用

4. @Service具体类的服务

与上面看到的相反,注释实现类而不是抽像类或接口是一种很常见的做法。

这样,我们的目标主要是告诉Spring该类将是@Component并用特殊的@Service型对其进行标记,在本例中为@Service

因此,Spring将自动从类路径中检测这些类,并将它们自动定义为托管Bean。

因此,这次让我们将@Service放在我们的具体服务类上。我们将有一个实现接口的类,还有一个扩展了我们先前定义的抽像类的类:

@Service

 public class InMemoryAuthenticationService implements AuthenticationService {



 @Override

 public boolean authenticate(String username, String password) {

 //...

 }

 }



 @Service

 public class LdapAuthenticationService extends AbstractAuthenticationService {



 @Override

 public boolean authenticate(String username, String password) {

 //...

 }

 }

我们应该在这里注意,我们的AbstractAuthenticationService在这里没有实现AuthenticationService 。因此,我们可以独立测试它们。

最后,我们将两个服务类都添加到AuthApplication ,然后尝试一下:

@SpringBootApplication

 public class AuthApplication {



 @Autowired

 private AuthenticationService inMemoryAuthService;



 @Autowired

 private AbstractAuthenticationService ldapAuthService;



 public static void main(String[] args) {

 SpringApplication.run(AuthApplication.class, args);

 }

 }

我们的最终测试为我们提供了成功的结果,并且Spring上下文毫无例外地启动。这两个服务都自动注册为bean。

5.结果

最终,我们看到了唯一的工作方式是将@Service放入实现类中,以使其能够自动检测。除非单独注解这些类,否则Spring的组件扫描不会选择这些类,即使它们是从另一个@Service注释的接口或抽像类派生的也是如此。

另外, Spring的文档还指出,在实现类上使用@Service可以使组件扫描自动检测到它们。

六,结论

在本文中,我们研究了使用Spring的@Service批注的不同位置,并了解了保留@Service以定义服务级别的Spring Bean,以便在组件扫描期间自动检测到它们。

具体来说,我们看到将@Service批注放置在接口或抽像类上没有任何效果,并且当使用@Service批注时,组件扫描将仅提取具体的类。

标签:

0 评论

发表评论

您的电子邮件地址不会被公开。 必填的字段已做标记 *