0
donuts
3y

Sorta just had a realization but wanted to confirm if that's how it works.

@Bean adds the object to global objects collection?

And @AutoWired in a object returned in like @Bean ClassA classA() { return new ClassA(); }

Gets the instance from these global collections?

In which case Spring is just a way to use global variables/singletons... Isn't that like bad?

Comments
  • 0
    On a side note, I was having a sheets nervous breakdown for an HR thinking about all the tasks I am supposed to finish and not having enough time.

    On the other hand, when I think about stuff like this, technical/conceptual, I find it interesting and sorta calming.
  • 2
    First off, there are 2 types of singletons: Spring-managed beans and your own managed singletons.

    Secondly, Spring does not only operate in Singletons. Spring's dependency injection also supports PROTOTYPE (see the @Bean() params).

    Thirdly, yes, that's how it works. However, there are a few things you should consider:

    - Field injection (@Autowired private MyService service;) has become an antipattern. Use constructor/setter injections.
    - The "global collection" is usually referred to as Spring's context in general.
    - It is not bad is used correctly. It saves you from lots of boilerplate code, it enables you to easily plug in new services/controllers/etc to your application; other Spring modules as well.
    - It might be bad if abused (e.g. field injections hide bad arch problems)
    - you are marrying Spring, because @Autowired is only supported by Spring. JSR330 would be a solution but it is only partially supported by Spring.
  • 1
    @donuts Oh, and Spring can only inject dependencies into Spring-managed beans. It means you must register your controllers, services, repos and other components into the Spring context if you want Spring to do the injection for you. And these dependencies must also be in the context as well.

    What Spring does nicely, it works out the sequence of the beans' initialization really well. I.e. it figures out which bean depend on which ones and initializes dependencies first.
  • 1
    @netikras what about in the case of multithreading, like SpringBoot.

    Multiple requests come at once but if a Bean can only be used by one at a time?

    Also I guess this goes into a issue I had with an existing app someone else wrote. For one of the classes it creates a new one per request by returning: new AppContext(...).getBean("helper");

    Problem is after the request finishes, the object is not disposed and eventually causes memory and socket leaks but to a network connection created in the bean/context. And finally hangs the machine.

    Is there some sort of kill-switch basically "get rid of everything it created immediately".
  • 1
    @donuts one doesn't normally create a separate context for each thread/request. Normally a single app uses a single context to cover it all.

    Also, querying the context manually is not the preferred way to get/register a bean. If possible, use the Spring's annotations. Yes, it sounds weird, but it actually is a better approach. I like to see Spring like a proprietary product that hopefully knows what it's doing.

    No, getting rid of all the beans is not possible. Spring is using its own beans in the same context, so nuking them is as good as System.exit(). Unless you go ahead and juggle multiple contexts all the time, which is a performance killer and a good way to create random ans hard to solve bugs.

    I don't think there are concurrency issues in the context, since a singletone is only 1 instance and other beans are querying it, not writing. Anyways, if you encounter any - they should be easy to work around with custom synchronizers using some Factory pattern as a bean.
  • 1
    @netikras well whoever wrote this code thought it was a good idea... shortcut.

    And sort back to the issue with global collections. The structure is Spring class -> many spring classes -> many spring classes.

    And of course all have parameter less constructors and a ton of AutoWired...

    So I guess a team of monkeys that never learned how to use spring the right way...

    Then junior devs copy the code and just make it worse...

    One of those inner classes causes the leak due to some lib that can't close itself...

    So guess only way is system.exit();

    The work I did was create a pool for the first class.

    The problem and reason why the original code needed to create new contexts is because the super class it creates has a initialize(requestSpicificArgs) method... So can't have 2 requests using the same one at once....
  • 0
    @donuts I know there is a lot more to it than what you've just said and the devs probably had a good reason to do what they did.

    But I can't help but think: WTF? All the webapps have request-speciffic methods and practically none of them need a separate Spring context created for each request. Sounds like either singletons done wrong (stateful) or someone misread (if read at all) Spring docs.
  • 0
    @donuts Can't you hook up a reference to those closeable beans (i.e. decorate them) and, one the request is complete (i.e. back in your @Controller method) release the resources using that reference? System.exit doesn't feel like a sound solution.
  • 0
    @netikras tried that but this lib can't close... Calling close() just hangs the thread or does it in background but doesn't really close.

    Our team there's sr devs and jr devs. Senior devs do things because that's how they always did it.

    Jr devs do things bc that's how the existing code does it.

    And then there's me. When something fcks up that no one can fix, it goes to me and well the root cause everytime is "some incompetent monkey fcked up"... And it will keep on happening until I stop saving their asses...

    Maybe next time something like this happens... I'll just reject helping them
  • 0
    @donuts That makes no sense.. Is there any way to programmatically release those resources? If there was no Spring in the picture - how would you release those resources then?
  • 1
    @netikras u close the app. The root cause it's that lib resource should've been a Singleton except it's so nestsd in the code but it can't be fix easily.

    And the inner classes is used by other "apps" or Spring contexts.

    Anyway root cause it's bad design and the Sr devs are part of the problem and I think next time will let them few am with their own mess....
  • 1
    Main reason why I really want to change teams... I don't like being the global error handler...

    But no team to change to. Tried last year the team I was joining got restructured away somehow...

    Can't do external for health reasons and well COVID
  • 0
    @donuts I think even a reflection-based workaround (with some fields/methods caching if possible) would be a poor way to sovle the problem, but it would solve it for now. Unless, ofc, the code you are using is native (i.e. the methods have 'native' modifier).

    Fire up your idea and use that built-in java decompiler to track down the mechanics of that lib and find a way to release your resources. Then summon some reflection for the job to clean all the mess. It'll be slow-ish, but it'd save you from restarts.

    Or log a week-long Story to fix the architectural mess they've created. Hopefully, you do have unittests to have your back!
  • 1
    @netikras unit tests nope. Anyway now but my problem. Gave them the pool solution and put in a "temp" fix to just restart the app every day.

    My work is done. Next time will just give them a bunch of excuses that amounts to "clean up ur own mess"
Add Comment