我正在使用Spring开发一个应用程序.我需要使用@Service注释.我ServiceI和ServiceImpl这样ServiceImpl implements ServiceI.我在这里很困惑,我应该在哪里保留@Service注释.
我应该注释接口或实现@Service吗?这两种方法有什么不同?
Ral*_*lph 117
我从不把@Component(或@Service......)放在界面上,因为这会使界面变得无用.让我解释一下原因.
声明1:如果您有一个接口,那么您希望将该接口用于注入点类型.
权利要求2:接口的目的是定义一个可以由多个实现实现的契约.另一方面,你有注射点(@Autowired).只有一个接口,只有一个实现它的类,(恕我直言)没用,并且违反了YAGNI.
事实:当你把:
@Component(或@Service......)在界面上,然后你会得到NoUniqueBeanDefinitionException
(或者你有一个非常特殊的配置设置,环境,配置文件或限定符......)
结论:如果您在界面上使用@Component(或@Service......),则必须至少违反两个clains中的一个.因此,我认为@Component在接口级别放置是没有用的(除了一些罕见的场景).
Spring-Data-JPA Repository接口完全不同
Pau*_*nis 31
基本上注解像@服务,@Repository,@Component等,它们都达到同样的目的:
使用基于注释的配置和类路径扫描时自动检测.
根据我的经验,我总是@Service在接口或抽象类和注释上使用注释,@Component以及@Repository它们的实现.@Component我在那些用于基本目的的类上使用的注释,简单的Spring bean,仅此而已.@Repository我在DAO图层中使用的注释,例如,如果我必须与数据库通信,有一些交易等.
因此,我建议@Service根据功能使用其他层注释您的界面.
Mur*_*dız 19
1. 接口上的@Service
@Service
public interface AuthenticationService {
boolean authenticate(String username, String password);
}
Run Code Online (Sandbox Code Playgroud)
通常来说,这没问题,但有一个缺点。通过将 Spring 放在@Service接口上,我们创建了额外的依赖项并将我们的接口与外部库耦合。
接下来,为了测试新服务 bean 的自动检测,让我们创建一个实现AuthenticationService:
public class InMemoryAuthenticationService implements AuthenticationService {
@Override
public boolean authenticate(String username, String password) {
//...
}
}
Run Code Online (Sandbox Code Playgroud)
我们应该注意,我们的新实现,InMemoryAuthenticationService,没有注释@Service。我们@Service只留下界面,AuthenticationService。
因此,让我们在基本 Spring Boot 设置的帮助下运行 Spring 上下文:
@SpringBootApplication
public class AuthApplication {
@Autowired
private AuthenticationService authService;
public static void main(String[] args) {
SpringApplication.run(AuthApplication.class, args);
}
}
Run Code Online (Sandbox Code Playgroud)
当我们运行我们的应用程序时,我们可能会遇到臭名昭著的NoSuchBeanDefinitionException,并且 Spring 上下文无法启动。
因此,放置
@Service在接口上不足以自动检测 Spring 组件。
2.抽象类上的@Service
在抽象类上使用@Service注释并不常见。
我们将从头开始定义一个抽象类并@Service在其上添加注释:
@Service
public abstract class AbstractAuthenticationService {
public boolean authenticate(String username, String password) {
return false;
}
}
Run Code Online (Sandbox Code Playgroud)
接下来,我们扩展AbstractAuthenticationService以创建一个不带注释的具体实现:
public class LdapAuthenticationService extends AbstractAuthenticationService {
@Override
public boolean authenticate(String username, String password) {
//...
}
}
Run Code Online (Sandbox Code Playgroud)
因此,我们还更新了AuthApplication, 以注入新的服务类:
@SpringBootApplication
public class AuthApplication {
@Autowired
private AbstractAuthenticationService authService;
public static void main(String[] args) {
SpringApplication.run(AuthApplication.class, args);
}
}
Run Code Online (Sandbox Code Playgroud)
运行后AuthApplication,Spring 上下文不会启动。它最终再次出现相同的NoSuchBeanDefinitionException异常。
所以,
@Service在抽象类上使用注解在 Spring 中没有任何效果。
3.具体类上的@Service
与我们上面看到的相反,注释实现类而不是抽象类或接口是一种很常见的做法。
通过这种方式,我们的目标主要是告诉 Spring 这个类将是 a@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) {
//...
}
}
Run Code Online (Sandbox Code Playgroud)
我们应该注意这里我们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);
}
}
Run Code Online (Sandbox Code Playgroud)
我们的最终测试给了我们一个成功的结果,并且 Spring 上下文启动,没有任何异常。这两个服务都会自动注册为 Bean。
您可以查看此页面以获取其他说明。
yal*_*ris 13
我只在实现类上使用@ Component,@ Service,@ Controller和@Repository注释,而不是在接口上.但@Autowired注释与接口仍然适用于我.
小智 7
在@Service上添加注释的优点是它提示它是一个服务.我不知道默认情况下是否会有任何实现类继承此annoation.
Con方面是您通过使用特定于弹簧的注释将您的界面与特定框架(即Spring)耦合.由于接口应该与实现分离,我不建议使用任何特定于框架的Annotations或对象的接口部分.
小智 5
我会穿上@Service你的课,但把接口的名称作为注释的参数,例如
interface ServiceOne {}
@Service("ServiceOne")
class ServiceOneImpl implements ServiceOne{}
Run Code Online (Sandbox Code Playgroud)
通过这样做,您可以获得所有好处,并且仍然可以注入接口但获得类
@Autowired
private ServiceOne serviceOne;
Run Code Online (Sandbox Code Playgroud)
因此,您的界面与 spring 框架无关,您可以随时更改类,而不必更新所有注入点。
因此,如果我想更改实现类,我可以注释新类并从第一个类中删除,但这就是需要更改的全部内容。如果您注入该类,那么当您想要更改 impl 类时,您可能需要做很多工作。
| 归档时间: |
|
| 查看次数: |
57769 次 |
| 最近记录: |