1. 接口上的@Service注解
@Service
public interface AuthenticationService {
boolean authenticate(String username, String password);
}
通常情况下,这是可以的,但有一个缺点。通过在接口上使用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上下文无法启动。
因此,在接口上放置
@Service
并不足以自动检测Spring组件。
2. 在抽象类上使用@Service注解
在抽象类上使用@Service
注解并不常见。
我们将从头开始定义一个抽象类,并将@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);
}
}
在运行AuthApplication
后,Spring上下文没有启动。最终出现了相同的NoSuchBeanDefinitionException异常。
因此,在抽象类上使用@Service
注释在Spring中没有任何效果。
3. 具体类上的@Service
与我们之前所见的相反,将实现类而不是抽象类或接口注释起来是一种很常见的做法。
这样,我们的目标主要是告诉Spring这个类将成为一个@Component
并用一个特殊的构造型@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。
您可以查看
this页面获取其他解释。