Can I annotate classes without data interactions with @Service?

Viewed 152

I have a Spring Boot application which does ETL processes and not a web application. I know that the use of services is to separate concerns and provide loose coupling but can I use it with classes that do not deal with the data being processed. I have several classes that I put in my service package and annotated it with @Service such as:

S3Service.java

@Service
public class S3Service {

    @Autowired
    private final AmazonS3 s3Client;

    public File downloadFile(String filename) throws Exception {
        ...
    }

    public File uploadFile(String filename) throws Exception {
        ...
    }

}

FileSecurityService.java

@Service
public FileSecurityService {

    public File decryptFile(String filename) throws Exception {
        ...
    }

    public File encryptFile(String filename) throws Exception {
        ...
    }

}

I did it this way because I think it makes my code cleaner but I don't think this is what services are for. I am hesitant to make them Utility classes because they are a huge part of the process. Is it a bad practice to use @Service this way? If yes, where should I put these? Thank you.

3 Answers

The thing with @Service is that now (that you annotated it), you can inject it into different other components/beans/services, via the constructor (and Spring Boot will take care to find them and autowire correctly).

So for example, you can do:

@Service
public class S3Service {

      private final AmazonS3 s3Client;


      public S3Service(AmazonS3 s3Client) {
            this.s3Client = s3Client;
      }

}

Spring will take care to find s3Client bean when it needs to create the S3Service service.

And now in order to test S3Service - you can provide a @Configuration where s3Client is a mock; thus testing this is super convenient. People tent to forget just how easy spring makes this.


And what is a @Service or not is irrelevant - it is up to you and your team to decide that. A bunch of our "utilities" are services, because it is so much easier to deal with them in that manner.

There are different types of services, depending on how you structure your application. In Spring, the annotations @Service and @Repository are inspired by the Domain Driven Design in which exist few types of services: application service, domain service, infrastructure service ... You're free to use @Service annotation on the top of any of these.

You can also get more specific and create custom annotations for each type of service: @InfrastructureService, @ApplicationService, @DomainService. If you choose to meta annotate them with @Service from Spring, Spring will create a bean for each class with this annotation.

For example:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Service
public @interface ApplicationService {
}

I did it this way because I think it makes my code cleaner but I don't think this is what services are for. -> True. It makes the code cleaner but is that a good enough argument? Spring was not just developed to make application codes look cleaner.

I am hesitant to make them Utility classes because they are a huge part of the process. -> Is this a good reason not to make it a utility class? Just because it is a big class or you have too many method in it? I don't think so.

Is it a bad practice to use @Service this way? -> IMO, creating beans just for sake of having a cleaner code is an insufficient argument to create beans and use spring framework in general.

When you code bases are big, have many packages and even more classes, sometimes it becomes difficult for a reader/reviewer to figure out where an instance of a particular class came from in the application context. That is why you see people create java classes and create the beans in the configuration classes. So there are only a few config classes where all the beans are created and injected to the application context.

Coming to your question -> should you create a bean or you should create a utility class with final keyword and static methods. IMO, you should go with the latter approach and in general you should always take into account the ideology around which spring framework was developed.

Related