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