1

I have a question that I can't answer myself - at least not well.

Imagine following code:

@Service public class ServiceA { public void doService() { System.out.println("Doing ServiceA"); } } @Service public class ServiceB { @Autowired ServiceA serviceA; public void doService() { serviceA.doService(); } } 

It works, but is it considered bad practice? If you want to decouple these classes or test them, you have no way to ever manually set the dependencies.

Also, how exactly is Spring handling it? Is there created a proxy class with an added constructor for the property?

1
  • Are you looking for how that Autowiring is done? then its done using reflection, you can check the documentation for @Autowired annonation. Commented Jun 24, 2018 at 20:41

2 Answers 2

2

If it is a bad practice or not depends for the era in which you write this code. In the era of EJB it is a best practice, the container provide you all the feature of the lifecycle and even in Spring it is good even if some time even in Spring this is quite rigid model java config or xml is a more flexible solution.

However in the 20xx era especially in a TDD and Agile model, I can say that it is a real BAD PRACTICE. Those beans are not testable out of the Spring container and the annotation couple you at Spring even in compile time. a more best solution may be a code like below

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); } } 

In this way ServiceA and ServiceB classes are two totally Spring free bean and especially for the business logic it is a best practice, the bean are testable because the our dependencies are explicit.

Imagine of provide a test of the ServiceB class writing the code in this way you can stub or mock the serviceA dependency and the ServiceB bean can be tested in isolation.

For the proxy story do not worry about it since that we provide a configuration class ServiceA and ServiceB are two beans like the annotated class, Spring manage a java config bean like an annotated bean. The difference is that now we can benefit of an explicit composition and we can provide a more flexible configuration scenario. we can benefit again of the magic aop of Spring because like said before an Spring bean configured in Java config is totally equivalent respect to an annotated bean.

I suggest you to use java config like the example.

I hope that it can help you

update: to reply to: Also, how exactly is Spring handling it? Is there created a proxy class with an added constructor for the property?

I can say: with the component-scan feature let's say @ComponentScan, spring find all the bean that are annotated with a sterotype annotation like @Component, @Service, @Repository and so on some of this annotation are useful because trigger some feature, for example @Repository if we implement a JPA repository and register a PersistanceExceptionTraslatorPostProcessor that translate the SQL native exception in an Exception of DataAccessException hierarchy, but other annotation are just a way for register a spring bean with annotation @Component, @Service are example.

Spring by relfection create the bean and inject the field annotated with @Autowired, if you use @Autowired on field by reflection set directly the field otherwise use the setter, in xml for instance the setter or the constructor are required.

In case of two constructor for you it is transparent, Spring will use the empty constructor and then will provide the @Autowired property by reflection, you can even do like below:

@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(); } } 

In this case spring recognize that it have use the annotated constructor with @Autowired in order to create the bean and provide the dependency. In any case the best practice is definitely the first snippet of code in my answer. It is explicit in the dependencies, clean and Spring Free in your business code base

Sign up to request clarification or add additional context in comments.

Comments

0

If you dont like autowired (me either). You can used Constructor Dependency Injection.

You should not used depencendy for class byt for interface and spring will server correct implementation (decoupling)

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(); } } 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.