我有一个我无法回答自己的问题-至少不是很好。
想象以下代码:
@Service
public class ServiceA {
public void doService() {
System.out.println("Doing ServiceA");
}
}
@Service
public class ServiceB {
@Autowired
ServiceA serviceA;
public void doService() {
serviceA.doService();
}
}
它有效,但是被认为是不好的做法吗?如果要分离这些类或对其进行测试,则无法手动设置依赖项。
此外,Spring到底如何处理它?是否为该属性创建了带有添加的构造函数的代理类?
答案 0 :(得分:2)
这是否是一个不好的习惯取决于您编写此代码的时代。在EJB时代,这是一种最佳实践,该容器为您提供了生命周期的所有功能,即使在Spring中,即使在某些时候,即使在Spring中这是相当严格的模型,它也是一个很好的解决方案,java config或xml是一个更灵活的解决方案。
但是,在20xx时代,尤其是在TDD和敏捷模型中,我可以说这是一个真正的坏习惯。这些bean无法从Spring容器中进行测试,并且即使在编译时,注解也会在Spring上为您带来麻烦。最好的解决方案可能是下面的代码
class ServiceA {
public void doService() {
System.out.println("Doing ServiceA");
}
}
class ServiceB {
private final ServiceA serviceA;
ServiceB(ServiceA serviceA) {
this.serviceA = serviceA;
}
public void doService() {
serviceA.doService();
}
}
@Configuration
class ServiceConfig{
@Bean
public ServiceA serviceA(){
return new ServiceA();
}
@Bean
public ServiceB serviceB(ServiceA serviceA){
return new ServiceB(serviceA);
}
}
这样,ServiceA和ServiceB类是两个完全不受Spring影响的bean,尤其是对于业务逻辑而言,这是一种最佳实践,由于我们的依赖项是显式的,因此该bean是可测试的。
想象提供一个测试ServiceB类以这种方式编写代码的测试,您可以存根或模拟serviceA依赖项,并且可以单独测试ServiceB bean。
对于代理故事,请不要担心,因为我们提供了配置类ServiceA和ServiceB是像带注释的类一样的两个bean,Spring像带注释的bean一样管理java config bean。区别在于,现在我们可以受益于显式的组合,并且可以提供更灵活的配置方案。我们可以再次受益于Spring的神奇aop,因为就像之前说过的那样,在Java config中配置的Spring bean与带注释的bean完全等效。
我建议您像示例一样使用java config。
我希望它能为您提供帮助
更新: 回复: 此外,Spring到底如何处理它?是否为该属性创建了带有添加的构造函数的代理类?
我可以说:使用组件扫描功能,例如@ComponentScan
,spring可以找到所有带有构造型注释(例如@ Component,@ Service,@ Repository等)的bean。之所以有用,是因为它会触发某些功能,例如,如果我们实现JPA存储库并注册一个PersistanceExceptionTraslatorPostProcessor,则它会@@ Repository转换为DataAccessException层次结构的Exception中的SQL本机异常,但是其他注释只是使用注释@Component注册spring bean的一种方式, @Service是示例。
通过相关的Spring创建bean并注入用@Autowired注释的字段,如果直接在反射设置的字段上使用@Autowired,则直接使用该字段,否则使用setter,例如在xml中需要setter或构造函数。
如果有两个构造函数对您来说是透明的,Spring将使用空的构造函数,然后通过反射提供@Autowired属性,您甚至可以执行以下操作:
@Service
class ServiceA {
public void doService() {
System.out.println("Doing ServiceA");
}
}
@Service
class ServiceB {
private ServiceA serviceA;
public ServiceB() {
}
@Autowired
public ServiceB(ServiceA serviceA) {
this.serviceA = serviceA;
}
public void doService() {
serviceA.doService();
}
}
在这种情况下,spring认识到它已使用带@Autowired的带注释的构造函数来创建Bean并提供依赖项。无论如何,最佳实践肯定是我回答中的第一段代码。在依赖关系中是明确的,在业务代码库中是clean和Spring Free
答案 1 :(得分:0)
如果您不喜欢自动接线(我也可以)。您可以使用构造函数依赖注入。
您不应该将depencendy用于接口的类byt,并且spring将服务器正确实现(解耦)
public interface ServiceA {
public void doService();
}
@Service
public class ServiceAImpl implement ServiceA {
public void doService() {
System.out.println("Doing ServiceA");
}
}
@Service
public class ServiceBImpl implements ServiceB {
private final ServiceA serviceA;
public ServiceBImpl(ServiceA serviceA) {
this.serviceA = serviceA;
}
public void doService() {
serviceA.doService();
}
}