0
donuts
3y

In Spring/Boot if you annotate a class as a Service is it started on a different thread? I used @PostConstruct to start listening to a connection.

The class with main () seems to just load Beans defined in the AppConfig?

I need it to start a thread that listens to a Mongo Changestream and trigger some action on each.

I noticed a log line under the watch() is never reached so seems it's blocking...

Comments
  • 1
    What I like about Kotlin/springboot is that you never really know what happens exactly.
  • 0
    @bagfox I prefer knowing how things work so they don't blow up in production.

    But yes most people dont, and probably because they're not the ones that have to clean their shit up.

    Guess who usually does?
  • 1
    No it does not. If you want your service to be async - DIY. I.e. spawn a thread in the service's constructor and relay service calls to your worker. What will your service calls return if you're running jobs async? Either a Future or a void (or a dehydrated POJO that gets filled in as the thread does its work, which might not be a good idea). If you need the actual value returned - there's no point in spinning a separate thread for that service, because you will have to synchronize anyway and block until you get the value.
  • 0
    @netikras I don't need it to returns. It's sorta like a kafka consumer. I just want it running in the background so doesn't block any other services initialization/work.

    Like if I were to create an app that listens to change streams for multiple collections/ sources. They have to all be started but running on their own thread so they don't block the main app from starting the others.

    I just don't know how to do that the Spring Boot way with all the @Services, contexts classes.

    Spring is like start a web server, then ComponentScan ask the other classes and services. Somehow it all works even when the main function is just like public static void main() { MainClass.run(); }.... And I'm like wtf is going on...
  • 1
    @Service and @Controller all are but a fancy @Component. You could also annotate your services with @Coponent - it should still work.

    1. you start your main class with autoscan enabled
    2. Spring autoscan is triggered and it scans the classpath looking for classes with Spring's annotations (reflection)
    3. For each of those classes it filters out constructors, analyzes their parameters. If any needed - pulls them from the bean bag. Then calls the Class.getConstructors()[i].newInstance(<beans from the bean bag>)
    4. the constructed class is added to the bean bag (for injection to other constructors, to @Autowired fields)

    That's all, that's the magic. Spring's context is nothing else but a fancy classloader.
  • 1
    @donuts
    As for your async case -- I suggest smth like this

    public interface MyService {
    void doStuff(Task task);
    void doOtherStuff(Task2 t2);
    }

    public class MyServiceAsyncImpl implements MyService {
    private final ExecutorService es;

    public MyServiceAsyncImpl(ExecutorService es) {
    this.es = es;
    }

    private void async(Runnable r) {
    this.es.submit(r);
    }

    public doStuff(Task task) {
    async(() -> task.run());
    }

    public doOtherStuff(Task2 t2) {
    async(() -> t2.run());
    }

    }

    This way you will maintain testability of your code and you won't couple it to the async approach.

    Ofc you'll need the ExecutorService provided as a @Bean (in your main class, unless you have @Configuration classes).
  • 2
    @donuts sounds like you might benefit from the @Scheduled annotation.

    You'd need to add @EnableScheduling over you application class first and then you can annotate any method with it.

    Or if you really need a background thread just handle it with a ThreadPoolTaskExecutor in some configuration or service class

    Or even better it sounds like you do actually need a messaging system. I'd deploy rabbitMQ or similar if you need to handle a lot of events like this. If you only need a few, something like a scheduler going through a "queue" or a database table every couple of seconds/minutes would be enough

    In relation to your question:
    Services aren't automatically ran in new threads. They are created and destroyed based on your scope setting. By default only one service is created and shared among all requests but the individual requests are handled on individual threads (I think the default pool is 20)
  • 0
    @netikras so once is all loaded, how do I get your program to do something with everything it loaded?
Add Comment