@Component、@Repository和@Service注释是否可以在Spring中互换使用,或者它们除了充当符号设备之外,是否提供任何特定功能?
换句话说,如果我有一个Service类,并且我将注释从@Service更改为@Component,它的行为是否仍然相同?
或者注释是否也会影响类的行为和功能?
@Component、@Repository和@Service注释是否可以在Spring中互换使用,或者它们除了充当符号设备之外,是否提供任何特定功能?
换句话说,如果我有一个Service类,并且我将注释从@Service更改为@Component,它的行为是否仍然相同?
或者注释是否也会影响类的行为和功能?
当前回答
我们可以根据java标准回答这个问题
参考JSR-330,它现在被spring支持,您只能使用@Named来定义bean(不知何故,@Named=@Component)。因此,根据这个标准,似乎没有必要为类别bean定义原型(如@Repository、@Service、@Controller)。
但是spring用户在这些不同的注释中有不同的特定用途,例如:
帮助开发人员为胜任者定义更好的类别。这种分类在某些情况下可能会有所帮助。(例如,当您使用面向方面的时,这些可能是切入点的好候选)@存储库注释将为bean添加一些功能(为bean持久层添加一些自动异常转换)。如果您使用的是springMVC,则@RequestMapping只能添加到由@Controller注释的类中。
其他回答
这些是Stereotype注释,可用于自动扫描
从技术上讲,@Controller、@Service、@Repository都是相同的。它们都扩展了@Component。
从Spring源代码:
指示带注释的类是“组件”。当使用基于注释的配置和类路径扫描时,此类类被视为自动检测的候选类。
我们可以对每个bean直接使用@Component,但为了更好地理解和维护大型应用程序,我们使用@Controller、@Service、@Repository。
每个注释的目的:
@带有此注释的Controller->类旨在接收来自客户端的请求。第一个请求来自DispatcherServlet,它使用@RequestMapping注释的值将请求传递给特定的控制器。@带有此注释的服务->类旨在处理我们从客户端接收或从数据库获取的数据。所有的数据操作都应该在这个层中完成。@存储库->带有此注释的类用于连接数据库。它也可以被认为是DAO(数据访问对象)层。该层应仅限于CRUD(创建、检索、更新、删除)操作。如果需要任何操作,数据应发送回@Service层。
如果我们交换它们的位置(使用@Repository代替@Controller),我们的应用程序将正常工作。
使用三种不同的@注释的主要目的是为Enterprise应用程序提供更好的模块性。
这里给出的答案在技术上是部分正确的,但即使答案列表很长,这将是底部,我认为在这里也应该给出一个真正正确的答案,以防有人偶然发现并从中学习到有价值的东西。这并不是说其余的答案完全错误,只是它们不正确。而且,为了阻止成群的巨魔,是的,我知道,从技术上讲,这些注释现在实际上是一样的,甚至到第5春,它们都可以互换。现在,对于正确的答案:
这三种注释是完全不同的,不可互换。你可以这么说,因为他们有三个而不是一个。它们并不是可互换的,它们只是出于优雅和方便而实现的。
现代编程是不同比例的发明、艺术、技术和通信。通信位通常非常重要,因为代码的读取频率通常比编写频率高得多。作为一名程序员,你不仅试图解决技术问题,还试图将你的意图传达给阅读你代码的未来程序员。这些程序员可能既不共享您的母语,也不共享您所处的社交环境,而且他们可能在未来50年内阅读您的代码(这并不像您想象的那样不可能)。在未来很难有效地沟通。因此,我们必须使用最清晰、最有效、最正确、最具交际能力的语言。我们谨慎地选择词汇,以产生最大的影响,并尽可能清楚地表达我们的意图。
例如,在编写存储库时使用@Repository而不是@Component是非常重要的。后者对于存储库来说是一个非常糟糕的注释选择,因为它并不表示我们正在查看存储库。我们可以假设存储库也是一个springbean,但不能假设组件是一个存储库。有了@Repository,我们的语言变得清晰而具体。我们明确表示,这是一个存储库。有了@Component,我们就让读者来决定他们阅读的是什么类型的组件,他们必须阅读整个类(以及可能的子类和接口树)来推断含义。在遥远的将来,该类可能会被读者误解为不是一个存储库,我们可能会对这个错误承担部分责任,因为我们深知这是一个存储,但未能在我们的语言中明确表达我们的意图。
我将不讨论其他示例,但将尽可能清楚地说明:这些注释是完全不同的东西,应根据其意图适当使用@存储库用于存储存储库,其他注释都不正确@服务用于服务,其他注释不正确@控制器适用于既不是存储库也不是服务的组件,在其位置使用其中任何一个都是不正确的。它可能会编译,甚至可能运行并通过您的测试,但这是错误的,如果您这样做的话,我会对您(专业)的评价降低。
整个春季都有这样的例子(以及一般的编程)。编写REST API时不能使用@Controller,因为@RestController可用。当@GetMapping是有效的替代方案时,不能使用@RequestMapping。你必须选择最具体、最准确、最正确的语言来向读者传达你的意图,否则,你会给你的系统带来风险,风险是有代价的。
最后,我想提出一个关于面向对象系统的问题。基本规则之一是,实现可以变化,但接口不应该变化。假设这些注释是相同的,这是一个非常棘手的问题,完全违背OO。尽管它们现在可能以可互换的方式实现,但不能保证将来会实现。此外,即使在同一个团队中,工程师也可能会决定使用方面暂停这些注释中的一个或多个,或者平台工程师可能会出于操作原因选择替换其中一个的实现。你只是不知道,也不应该知道——在OO中,你依赖的是接口,而不是实现。
由于许多答案已经说明了这些注释的用途,我们将在这里重点讨论它们之间的一些细微差异。
首先是相似性值得再次强调的第一点是,关于扫描自动检测和BeanDefinition的依赖注入,@Repository、@Controller)是相同的。我们可以就地使用另一个的,仍然可以得到我们的方式。
@Component、@Repository、@Controller和@Service之间的差异
@组件
这是一个通用的原型注释,表明该类是一个弹簧组件。
@Component有什么特别之处<context:componentscan>仅扫描@component,通常不查找@Controller、@Service和@Repository。它们被扫描,因为它们本身带有@Component注释。
只需查看@Controller、@Service和@Repository注释定义即可:
@Component
public @interface Service {
….
}
@Component
public @interface Repository {
….
}
@Component
public @interface Controller {
…
}
因此,@Controller、@Service和@Repository是@Component注释的特殊类型并不是错误的<context:componentscan>拾取它们并将它们的以下类注册为bean,就像它们用@component注释一样。
特殊类型注释也会被扫描,因为它们本身是用@Component注释注释的,这意味着它们也是@Components。如果我们定义自己的自定义注释并使用@Component对其进行注释,那么它也将通过<context:componentscan>进行扫描
@存储库
这表示该类定义了一个数据存储库。
@Repository有什么特别之处?
除了指出这是一个基于注释的配置之外,@Repository的工作是捕获特定于平台的异常,并将其作为Spring的统一未检查异常之一重新抛出。为此,我们提供了PersistenceExceptionTranslationPostProcessor,需要将其添加到Spring的应用程序上下文中,如下所示:
<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>
这个bean后处理器向用@Repository注释的任何bean添加一个advisor,以便捕获任何特定于平台的异常,然后作为Spring未检查的数据访问异常之一重新抛出。
@控制器
@Controller注释表示特定类充当控制器的角色。@Controller注释充当注释类的原型,指示其角色。
@Controller有什么特别之处?
我们无法将此注释与任何其他注释(如@Service或@Repository)切换,即使它们看起来相同。分派器扫描用@Controller注释的类,并检测其中用@RequestMapping注释注释的方法。我们只能在类用@Controller注释的方法上/中使用@RequestMapping,它不能与@Component、@Service、@Repository等一起使用。。。
注意:如果一个类已经通过任何替代方法注册为bean,例如通过@bean或通过@Component、@Service等注释,那么如果该类也使用@RequestMapping注释进行注释,则可以选择@RequestMapping。但情况不同。
@服务
@服务bean在存储库层中保存业务逻辑和调用方法。
@Service有什么特别之处?
除了它用来表示,它持有业务逻辑之外,这个注释中没有其他值得注意的地方;但谁知道呢,Spring可能会在未来增加一些额外的例外。
还有什么?
与上述类似,未来Spring可能会根据其分层约定为@Service、@Controller和@Repository添加特殊功能。因此,尊重惯例并按照层使用它总是一个好主意。
@组件、@Repository、@Service、@Controller:
@Component是由Spring@Repository、@Service和@Controller管理的组件的通用原型,是用于更具体用途的@Component专用化:
@持久性存储库@服务和交易服务@MVC控制器的控制器
为什么在@Component上使用@Repository、@Service、@Controller?我们可以用@component标记我们的组件类,但如果相反,我们使用适应预期功能的替代方法。我们的类更适合每种特定情况下的预期功能。
用@Repository注释的类使用org.springframework.dao.DataAccessException具有更好的翻译和可读错误处理。非常适合实现访问数据的组件(DataAccessObject或dao)。
带有@Controller的注释类在SpringWebMVC应用程序中扮演控制器角色
带有@Service的注释类在业务逻辑服务中发挥作用,例如DAO Manager(Facade)的Facade模式和事务处理
为了简化这一说明,让我们通过用例来考虑技术性,这些注释用于注入,正如我所说的“用于注入”,这意味着,如果你知道如何使用依赖注入“DI”,并且你应该这样做,那么你将一直寻找这些注释,并通过使用这些立体类型来注释类,您正在通知DI容器扫描它们,以准备在其他地方进行注入,这是实际的目标。
现在让我们来看看每一个;first@Service,如果您正在为特定的业务案例构建一些逻辑,则需要在包含您的业务逻辑的地方将其分离,该服务是普通的Class,或者您可以根据需要将其用作接口,其编写方式如下
@Service
public class Doer {
// Your logic
}
要在另一个类中使用它,请假设在Controller中
@Controller
public class XController {
// You have to inject it like this
@Autowired
private Doer doer;
// Your logic
}
当你注入它们时,它们都是相同的方式,@Repository这是一个应用Repository Pattern Repository设计模式实现的接口,通常在处理某些数据存储或数据库时使用,你会发现,它包含多个现成的实现,供你处理数据库操作;它可以是CrudRepository、JpaRepository等。
例如:
public interface DoerRepository implements JpaRepository<Long, XEntity> {
}
最后,@Component,这是Spring中注册bean的通用形式,也就是说,Spring总是在寻找标记有@Component的bean来注册,那么@Service和@Repository都是@Component的特例,然而,组件的常见用例是当您制作一些纯技术性的东西而不是直接的业务案例时!比如格式化日期或处理特殊的请求序列化机制等等。