hectorg87
hectorg87

Reputation: 753

Complex Spring Framework Service Layer

EDITED SHORT VERSION OF THE POST:

Haven't had enough views, so I'm summarizing the question:

My architecture is completely stateless and async, the front-end makes a petition to a REST API and then long-polls for the response. This Rest API queues petitions into a messaging queue, and each petition is dequeued and processed by the Back-end.

I want this Back-end to follow the "traditional" Spring @Service interface and ServiceImpl approach, however is kind of hard because of how I'm doing it.

One Thread dequeues the petition (Producer), spawns a new Thread (Consumer), and then it processes all the petition within that thread, which later sends back to a "responses pool" where it gets polled. That petition might need to use several @Service's and merge the responses from each, maybe even the same @Service twice.

How would you do it? For more information, check the description below!

ORIGINAL LONG POST:

I have a large application with 3 layers like this:

  1. Front-end (Spring-MVC): Views and Controllers, "Model" are async requests to REST API in Middleware to queue the petition first and then long-polling for an answer
  2. Middleware (Spring-MVC): The rest API. Two main functions: receives a petition from front-end and queues it, receives an answer from Backend and stores it on responses cache until retrieved by front-end
  3. Back-End (Spring Standalone App): Producer/Consumer pattern, ONE Producer dequeues petition and creates a Prototype Consumer for each petition. The consumer implements InitializingBean, so it goes something like this: It is initialized, many Autowired fields are initialized and then afterPropertiesSet is executed and many fields which depends on the petition are set.

I also have a Repository Layer of HibernateDaos, which does all the querying to the database.

I'm missing a properly built Service Layer and that's what this question is all about.

Let me put a little bit more of context. What I have right now is like one only HUGE service with 221 functions (The Consumer's file is very long), and one petition may need to invoke several of this functions, and the result of each is merged into a List of DTOs, which is later received by the front-end.

I want to split this one and only service into several, in a logical match to "it's" corresponding Repository, however I've faced the following problems:

Keep this in mind:

With a good Service Layer I want to acomplish:

I was thinking of having a prototype ServicesFactory per Consumer which is initialized with all the parameters afterPropetiesSet in the Consumer, inside this ServicesFactory all possible Services are declared as Class fields, and when a specific service is requested, if it's field is null it is initialized and all fields are set, if not null, the same instance is returned. The problem with this approach, I that I'm losing Dependency Injection on all the Services. I've been reading about ServiceFactoryBean thinking maybe this is the way to go, however I really can't get a hold to it. The fact that it needs all the parameters of the Consumer, and that it needs to be an unique ServiceFactoryBean per Consumer is really confusing.

Any thoughts?

Thanks

Upvotes: 2

Views: 1438

Answers (2)

Angular University
Angular University

Reputation: 43127

Based on the description I don't think this is a good case for using the protoype scope, in this case the ideal scope seems to be thread scope.

As a solution, the simplest would be to make all services singleton. Then the consumer reads the petition from the inbound queue and starts processing.

One of the services that is also singleton and gets injected in all services needed, let's call it PetitionScopedService.

This service internally uses a ThreadLocal, which is a thread scoped holder for a variable of type PetitionContext. PetitionContext on it's turn contain all information that is global to that petition.

All the consumer needs to do is to set the initial values of the petition context, and any caller of PetitionScopedService on the same thread will be able to read those values in a transparent way. Here is some sample code:

public class PetitionContext {
    ... just a POJO, getters and setters etc. 
}

@Service
public class PetitionScopedService {

    private ThreadLocal<PetitionContext> = new ThreadLocal<PetitionContext>();


    public doSomethingPetitionSpecific() {
        ... uses the petition context ...
    }
}

@Service
public class SomeOtherService {

    @Autowired
    private PetitionScopedService petitionService;

    ... use petition service that is a singleton with thread scoped internal state, effectivelly thread scoped ...
} 

Upvotes: 1

Bassem Reda Zohdy
Bassem Reda Zohdy

Reputation: 12942

Points 2 and 3 need more reorganizing, prefer to check "Spring Integration" for both "Middleware" and "(Spring Standalone App): Producer/Consumer pattern" actually spring integration made to solve these 2 points, and using publish/subscribe if you are doing 2 or more actions at same time, the other point why you are using REST in "Middleware" are these "Middleware" services exposed by another app rather than your front end, in this case you can integrate this part in your Spring-MVC front end app using "content negotiation", otherwise if you are going to use "Spring Integration" you will find multiple ways for communication.

Upvotes: 0

Related Questions