History of Spring Framework and Spring Boot
quickprogrammingtips.com
quickprogrammingtips.com
This caught my eye. I have never used a Java framework, but use Rails daily. Does Spring Boot do Rails things such as migrations? Is there a healthy plugin ecosystems? (whatever the Gem equivalent in Java is).
After 3 years of building and maintaining a mission-critical Java backend, I would never do it again... We were using a similar framework, called dropwizard, great product, super lean and reliable.
If you think Rails is magic, then you haven't seen the Java world, all the magic with annotations, dependency injection, glueing libraries together by placing some files in a folder.
If you think Rails 2.3 to 3.0 upgrade was dramatic, then what we went through with a minor update from dropwizard (i think 0.7 to 0.8) was a nightmareish 1-2 months of rewriting half of the code and dependency injection handling.
Java is still super verbose, not just the language itself, but also all the libraries that are often over-engineered.
Hibernate is quiet easy to get started and you don't understand what all the fuss is about. But once you go start adding features it quickly becomes unmaintainable and any change to the models comes with FUD whether that'll make the queries explode in an unpredictable manner.
There's a lot of libraries, but on UI/UX level you don't have anything close to what Rails offers out of the box. Things you take for granted don't exist, like devise.
The good parts were: Rails deployments are from the stone-age compared to dropwizards simple approach of installing java and copying the self-running jar (fat binary) to server and start. Very good instrumentation/metrics out of the box with joda-metrics.
After 3 years, a pivot required us to rewrite large parts of the logic. We took that as a chance to rewrite/migrate all our services to Elixir/Phoenix. And never looked back.
So far Elixir/Phoenix/Ecto to me is the perfect middle ground between a solid Java environment and the speed of development of Rails.
> all the magic with annotations
... which are basically just decorators
> dependency injection
... which is quite useful for loose-coupling and injecting different implementations (and you don't have to use it)
> glueing libraries together by placing some files in a folder
.... what? Never done that ;-)
> Java is still super verbose, not just the language itself
I don't see that. It's actually quite nice for my taste. I guess you don't like generics, but then you have to live without them, which also sucks.
> There's a lot of libraries, but on UI/UX level you don't have anything close to what Rails offers out of the box.
What do you mean exactly? There are things like thymeleaf if you want SSR, otherwise you can put whatever SPA in front of it.
> things you take for granted don't exist, like devise.
.. it's not hard to use Spring Security though
>Elixir/Phoenix/Ecto" - is there some devise like auth by now? I also like Elixir/Phoenix quite a lot, but it's nowhere near Rails/Springs level.
Coherence https://github.com/smpallen99/coherence
Kinda curious why there was such a big migration conisdering dw is mostly just a combination of packages.
All the things you are complaining about have been abstracted away by many recent java and groovy libraries.
You are literally comparing some random company using a random java framework 4 years ago to modern ruby on rails. The comparison just doesn't work.
You can make java as simple as you want or as complex as you want. Modern tools like spring boot and groovy make it VERY easy to make java simple.
Most popular languages today have such a thing - cpan gor perl, pip for python, etc. In java there‘s at least maven for that with it’s huge library repositories.
There might be more nowadays, i‘ve not been using Java since a good while.
Regarding ecosystem, the Java one is the biggest and has much more to offer than any other technology. Spring Boot can work with all libraries and there exist Spring Boot plugins for the configuration of the most popular solutions (data storages, clouds, templates, MQs etc).
The package management in Java is mature and one of the best and is now replicated/reused on other platforms. E.g. Java-based Nexus repository can be used for hosting libraries for JS and Docker and tools like Apache Maven can build and manage not only Java projects (I think it's even possible to wrap Rails project in Maven).
Unless you're working alone or unless everybody knows exactly how the whole system works, being explicit will save you a lot of time.
If you're still insisting, I suggest you to clone random mid-size spring project from github and do some non-trivial change (like implement automatic tracking of all changes or soft-deletes)
You may be interested in programmatic / functional bean registration[0], which was introduced in Spring Framework 5. It has a particular focus on Kotlin support[1][2].
[0] https://springoneplatform.io/sessions/programmatic-bean-regi...
[1] https://spring.io/blog/2017/08/01/spring-framework-5-kotlin-...
BWAHAHAHAHAHA! Good one.
Seriously, though, I'm really, really glad to see this come up this morning.
I've done a lot of .NET lately, but Rails has been my main tool for 10 years. However, because it's (apparently) a strange, new, unproven-and-potentially-exceedingly-insecure framework, and because I'm the ONLY PERSON in a company of SIXTY THOUSAND employees who could possibly write a program with it, I've been forced to stop using it. I took FOUR MONTHS of arguing about it with the powers-that-be to conclude that I should use Java instead. I have 3 web applications to write, right now, with some flavor of Java EE.
For a couple of weeks, I've been trying to bootstrap an environment to read an existing database I had already created with Rails, and filled with production data. I thought it would have been straightforward. I'm trying to use current versions:
* Netbeans 8.2 * Java 1.8 * Gradle 4.6 * SpringMVC 5.0.4 * Hibernate 5.2.15
I can't find a single, working example that demonstrates this stack. Not a single one, on the entirety of the internet! Every example I can find switches out some part of that stack, and makes the flow different. Netbeans and Eclipse do things differently, and both have about 3 different ways to generate a Java web application.
Then there's the whole Maven thing. I guess most of the world hasn't really switched to Gradle, despite their site's glowing description of the advantages?
And what is "Spring Framework?" There's really several different pieces of that puzzle, and that's fine, but, at the end of the day, show me the code, AND TELL ME WHERE TO PUT IT IN THE FILE STRUCTURE TO MAKE IT WORK.
Most of the examples I can find about how to write a Java web application never even get to the point of pulling data from a database, and so finding an example that uses either Hibernate OR JPA is almost non-existent. This just makes me shake my head.
My current direction, which I was all set to get serious with today, was to use Groovy on Grails, under IntelliJ IDEA. After a couple of weeks of experimentation, it's the only stack I've been able to bootstrap, and actually get a listing of objects from the database. I feel it probably takes too many liberties to simplify the workflow, and will quickly lead to a bottleneck I don't know how to get out of, but, dammit, it's the only thing I can find some reasonable examples for.
(But even IDEA wants to generate a stack based on the non-current Spring 4.3.14, and Hibernate 5.1.5. Spring 5 is released. Why doesn't IDEA "support" it yet? What little examples I can find show that a lot of things are changing from Spring 4 to 5.)
Through this learning process, I've realized just how much tribal knowledge I've absorbed about Rails. I "grew up" with Rails. I was playing with it in the 0.x days, got serious with it in the early 2.x era, and have stayed with it ever since. I understood that learning how to use another web stack would be a challenge. While the actual language is hardly a concern to me, I had no idea that the chaos of choices and versions would complicate the process of just trying to get started. At the very least, when you say "Rails X.0", you've described all the major pieces of the stack, and the IDE is immaterial. That is simply not the case in the Java world.
So I've said all of this to set the context in order to ask you this: What is the "right" framework stack to use to create a Java web application TODAY? And by "right," I mean "most popular," in order to make finding answers as easy as possible. For the sake of argument, the 3 apps I need to write are essentially simple CRUD applications, so there are no esoteric requirements to consider. What's the most straightforward and maintainable approach, and where's the definitive documentation on how to configure it? I'm ready to go all-in on SOMETHING, but I'm overwhelmed with choices and a lack of examples.
The GP seemed to be indicating they were trying to put together a standard set of tools for others in their company to use. Having one official 'blessed' IDE and a 'standard' way to do things - even as a demonstration process - isn't out of the ordinary. And... given how much any complex Java program relies on the author having an IDE handle things for them (the assumption is that an IDE will help find the correct imports when developing, for example), it's pretty common for people to assume you're using one of the few common ones out there. I guess the author was looking for 'free' up front, but I'm curious why they didn't mention IntelliJ - it's the only thing I'd bother with for 'real' Java development in 2018 (although I'm keeping an eye on the vscode landscape).
> should read up on the documentation of the basics of java, gradle and spring first
There's no 'basics' to those - they are sprawling ecosystems, and any non-trivial task requires a pretty deep understanding of how those pieces fit together.
> maybe rails developers expect everything to be spoon fed to them in pieces of 5 minute screencasts or something?
Perhaps other tech stacks are able to deliver useful/functioning tutorials of information in 5 minute screencasts, without requiring someone to be an expert or have years of the 'tribal knowledge' the GP spoke of in another post?
Yup. This is forging a new trail at the company, which is, itself, a painful process.
I was a grails advocate for a long time. I put up with some of the initial pain (from 0.6 days) because it provided more benefit than not. And, had I not picked up intellij, I may have left the fold a long time ago. :)
As time has gone on, the coupling with Spring has become more obvious - I may have just been blissfully unaware earlier on. The migration to a 'spring boot' based approach has sort of soured me more than I expected. If I wanted to use Spring boot, I'd use it. I preferred some of the Grails conventions, but many have been thrown out or reduced to accommodate the Boot way. Some of the stuff I'd hoped to have to dig in to (and, in some cases, had not needed to be an expert in) have now become requirements to dig in to, and I spend more time configuring and digging through framework problems than the actual application.
No doubt much of this is me, but I'd hoped Grails would improve, but for me, it's just changed. My work with Java/Spring/etc definitely has helped me think about problems differently, and improved my thinking and coding overall, but much of what I was looking for has improved in other ecosystems over the last several years to make continuing in the Java world a harder decision. (context: I'm primarily a solo developer, not working with large teams or large budgets). One minor example: being able to make a code change in a test, run that one test, make another change, and rerun the test, all in a few seconds doesn't seem to be something that's possible in the Spring world, and perhaps not in the Java world in general (no doubt there will be people who tell me "you're doing it wrong" and "we run 4000 spring tests every 7 seconds with 0% CPU!" but it's not been my experience).
This was my experience when I began.
What I learned was: unit tests don't need Spring. It seems silly in retrospect, but that's the basic rule. If you need Spring in your unit tests, you probably made a mistake somewhere.
Having worked in a few languages and frameworks, having seen codebases at various levels of maturity and whatnot, I quite like Spring Boot & co. Especially when Kotlin is in the picture.
Really? You dismiss my clearly-not-ignorant comments by belittling me? OK. I should have known.
Part of the frustration here is this: given a clean sheet of paper, and a desire to write a Java-based web application, where do I start? What files do I download? I don't know! How do I start developing with Spring? The site says "add this line to your build file." WTF does that even mean, to a Java noob? What's the file I'm supposed to be putting that configuration into? Unless you have a file structure bootstrapped, and know that they're talking about pom.xml, in the case of Maven, or build.gradle, in the case of Gradle, it doesn't mean anything!
How did I figure that out? By using an IDE and generating example file structures for a "web application" based on those 2 options in the stack. So getting started with Spring requires an existing bootstrapped structure that I STILL don't know how to generate by hand. (Feel free to enlighten me. How do YOU start a new Spring project?) Hence, my frustration with the various IDE's, and their multiple ways of generating what should be a pretty standard stack of files to get started.
As I tried to indicate, I "get it" that I have a lot of this stuff internalized with respect to Rails, and that's what I'm trying to get across. I don't think that the Spring folks understand what they need to do to "onboard" someone to their system. At least Grails seems to do a better job with this.
When Spring started, there was already a myriad ways of doing stuff, and multiple IDEs, and multiple use cases for Java itself, and Spring was trying to answer a lot more up front.
If you're doing 'web' in Java (something I still think much of the java world still doesn't really 'get'), there are dozens of choices/options/etc. If, in 2006, you were planning to do 'web' and wanted to use Ruby... the primary choice was Rails. If you were doing 'web' and wanted to use Python... you similarly have often only had one or two major choices (I'd argue 'Zope' early on, then Django as a default go-to for the last 10 years or so). In the Java world... way too many choices up front, all answering similar problems, but slightly differently.
While Ruby was out before Rails, their popularity generally rose in tandem, and much of the tooling for the ecosystem seemed to develop in tandem during the progression of Rails itself.
Had Spring started in 1997, we might have seen a somewhat different trajectory re: choice/tooling/community/etc.
I'd suggest not to search for various "stacks". They might be written poorly and incomplete. Learn each part and learn how to combine them.
I guess Rails is a complete solution, with Java there are many libraries which you should choose and glue together. Every non-trivial application probably will use somewhat unique combination of libraries.
And how exactly did you search for examples, considering that there are pretty good guides and lots of examples right on the Github? Here's the one from Spring: https://spring.io/guides/gs/accessing-data-jpa/
That example is for JPA. I thought the "better" answer for a Java ORM was still Hibernate, and I can't find a Spring-based example for that. If you tell me that Hibernate has been usurped by JPA in Java developer mindshare, or if you tell me that JPA just works better with Spring, I can change course. I have no experience with either to make the call.
Here you can generate a project and you can select what options you want in your starter.
Of course the IDE is immaterial. I understand that developing in a stack that you are familiar with is much simpler for anyone but people could make similar claims in support of Java+Spring.
That being said, if you are forced into this by your company, I think that stepping back from this would help you a lot.
The IDE is absolutely irrelevant to java stack (of course, there are some little nuances when you do something like develop an eclipse plugin, but in your case where you list several general technologies, there should be zero dependency on an editor) - whether you use netbeans, eclipse, vim, vscode or intellij should change exactly nothing about your project setup, maybe except for extra .gitignore line or two for the editor specific files.
I suspect that majority of the problems you're describing stems from this misconception.
On another note: Just don't use Spring 5 or every other framework for a small simple thing which got just released.
There is no harm at all in using Spring 4 and all tools and everything is just working.
And, to be fair, I've also since discovered https://start.spring.io.
It's worth pointing out that both of these sites exist specifically to address my frustration in just getting started with a Java web stack, but it's taken me a couple of weeks to discover them.
Anyways, I would highly recommend using IntelliJ and Dropwizard, both of which “just work”. Don’t worry about anything else, just use the DW docs.
Is that version 2 or 3 of Grails? Virtually no-one has updated their Grails 2 websites to version 3, or is starting new projects in Grails 3. Choosing version 3 means first adopter risk.
I upgraded a couple v2 to v3, mostly because of concern about security (moderately sensitive data, most of the 2-era plugins aren't updated, etc). The allure of v3 was supposed to be "it's all spring boot!" but... I'm not capable enough of just installing random spring stuff and configuring it for boot - there's still 'stuff' grails does its own way (or... it's just my competency level?) But if I need to become much more proficient in spring boot to get benefit from grails 3... i'll just move to spring boot in the long haul. This seemed an inevitable move for grails, but not one I was excited about.
I understand that motivation, but given that someone else (company) has made some of this decision for you, based on - it seems - ability of other people in the company to take over the apps, is there not some internal standard or existing apps you can learn from?
I realize telling you how this is a stupid decision your company has made doesn't really help, but given the decision, I'd think that would mean there's someone else with existing Java web app knowledge/experience for you to learn from?
Having the app done in Java - even if it means it's 6 months late - seems to be more important than having the app(s) available now, which - that alone must be frustrating. :/
Frustrating doesn't even scratch the surface of what this is. And, to be fair, my attitude about how this has gone hasn't exactly helped me find the answers I need. ;-)
Correct me if I'm wrong: for several WEEKS you're struggling with implementing a database read?
Really? Does it do a lot of code generation across the db / server / front end?
That plus convention over configuration makes most of my rails development pretty fast.
Yes, Spring offers a lot of flexibility in terms of IoC and testability. I generally avoid Spring for B2C apps. (For B2C apps, I tend to favor Jersey + MyBatis) But for B2B apps and in-house enterprise apps, Spring is a very good candidate.
It all depends on what your init logic is I guess.
I guess the biggest issue is restarting services in production, but that is mostly alleviated by not having singular copies of crucial services.
The load time of Spring apps is dominated by the number of classes loaded from disk, which is a function of the libraries pulled in. This is because the JVM loads classes out of JARs more or less linearly.
Think about it for a second: which is faster, in-memory operations (reflection) or I/O (loading classes from disk)?
Dave Syer has done more actual empirical investigation[0] of Spring's launchtime behaviour than anyone. If you can produce better evidence of actual behaviour, I'll be very surprised.
[0] https://github.com/dsyer/spring-boot-startup-bench
Disclosure: I work for Pivotal, we sponsor Spring development. I do not work on Spring.
All of Joist's Rails-ish code generation (creating the boilerplate lazy-loaded getters/setters/collections/etc.) is done at build-time so your test-/server boot time is very quick.
[1]: http://www.joist.ws/
Spring is a team of fairly smart individuals who tinker with experimental stuff all the time, so I would not at all be surprised if Dropwizard didn't figure amongst the inspirations. And they do keep up with what other folks are doing, so good ideas tend to be adopted into Spring pretty frequently.
Disclosure: I work for Pivotal, but not on Spring.
The article quotes:
"I think that Spring's web application architecture can be significantly simplified if it were to provided tools and a reference architecture that leveraged the Spring component and configuration model from top to bottom. Embedding and unifying the configuration of those common web container services within a Spring Container bootstrapped from a simple main() method."
The very next lines are:
"Though there are many frameworks and platforms today that no longer require a container I think inspiration can be drawn most from DropWizard (http://dropwizard.codahale.com/).
Another project I've seen inspired by DropWizard but leveraging Spring is HalfPipe (https://github.com/32degrees/halfpipe). Though I don't think HalfPipe goes far enough. I think to truly provide simplification the entire architecture, wherever reasonable, must be embedded within the Spring container rather than without. Though it does have several other interesting ideas."
However, you have to be prepared for a serious learning curve when needing customizing (e.g. attribute based authorization with Spring Security and AOP). It's a jump in the cold water after the pain- and effortless start using Spring Boot.
I haven't mastered Spring yet (in depth understanding of DI, AOP and the configuration), but I feel that when mastered, Spring is the ultimate framework to build concise and clean applications.
Can be said about everything in this world, right?
Frameworks that are large often have lots to learn in them, necessarily, but how that learning has to be done can differ. Good frameworks will be simple enough that you can almost ignore the ocean of complexity until you need to dive in, and when you dive in all of the pieces that you now must need to learn and know are almost obviously necessary.
For example, compare/contrast a system like express (nodejs) with a system spring in java. The func(req, res, next) paradigm gets you VERY far, but doesn't expose you to too much before you need to. Implementing middleware is much more delightful in nodejs (and other frameworks that adopted the func(req, resp, next) abstraction) than it is in Sprint.
doFilter(req, resp, chain)
You could use that if it Is more suited to your style?Last I touched java, Jersey was really exciting to me (https://jersey.github.io/) -- netty + good annotations/flask-like syntax + access to the beast that is the JVM is everywhere I want to be. Jersey doens't necessary force you into the servlet pattern IIRC?
@Component
public class MyMiddleware extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
// your code
filterChain.doFilter(request, response);
}
}1. Set up your spring boot project properly
2. Set up all the XML that supports your beans properly
3. Know how and when to use @Component
4. Know that OncePerRequestFilter exists, and/or to extend it, which method to override
5. Know to call filterChain properly
Most of these are trivial with some IDE support and maybe a templating school, and probably not even an issue after your second week with Spring boot (or spring in general), and it's an improvement over what life used to be like but compare this with the general jist of how to do it in JS:
1. set up expressjs properly (usually a two-liner). It won't have things like @Cachable that spring boot provides to you out of the gate, but it generally has enough to get you up and serving requests.
2. Know what req/res are (the fact that calling res.send(...) sends stuff and .ends as well is arguably nontrivial) and how to use next
3. Know what a function is.
the code snippet I'm thinking of is:
app.use(function(req, res, next) {
// your code
next();
})
It is "pretty much" the same, but how much work it is really depends on who you ask -- you can get up to speed with a simply built expressjs app in tens of minutes (many express apps follow a very simple setup pattern), but I've never seen that happen in a spring boot app for an absolutely fresh developer, even worse if the codebase is transitioning from spring to spring boot or has some other hacks in it.Spring Boot is marvelously simple one of it's best parts (it almost makes me want to use Java for a greenfield project), but there's so much noise in that code -- it should just be a function -- IMO all started with the decision in 1.1 (??) to choose Runnable over lambdas. Most of the complexity I'm ribbing Java over is just due to how you write the langage -- java on it's simplest day just can't be as simple as some of the stuff that came after it, since they had the benefit of hindsight.
2. It's 2018, we don't use XML anymore, a Main class annotated with @SpringBootApplication is all the configuration you need (and autogenerated by step 1)
3. All you need to know about @Component before you get started is if you annotate a class with it, it will get instantiated with all its dependencies and made available for use in the container
4./5. Yes, to know about Filter, the filterChain and how to use it might take some minutes looking into the documentation or stack overflow, but that is what you are going to have to do anyway if you are going to use a framework.
I put knowing how to use @Component and figuring out what you need from the docs on the same level as knowing about the (req, res, next) pattern and knowing about async/callbacks/promises.
I agree that Java is verbose and has much ceremony but modern IDE's take away a lot of that pain. For my filter example the only things I typed are:
* the class name
* extends OPRF<tab>
* <alt><enter> <enter> to generate the 1 method to implement
* the `// your code` comment and filterChain.doFilter()
I'm not sure what you mean about choosing Runnable over lambdas. Runnable `is` a functional interface so anywhere you can use a Runnable, you can pass a lambda (or method reference)
Meanwhile I can get to a running Spring Boot app in quite literally seconds.
The difference is that I know something about Spring Boot and much less about Node. That says nothing about either of them.
It's about optimizing for the easiest case vs the harder cases in design. This is the design space that answers the question as to how serious the curve is. Serious curves require a leap in complexity, whereas other approaches can have more incremental increases.
Authentication was a fine example. The canonical example in my mind though is Visual Basic vs Delphi. VB (version 3 era, for Windows 3.11) required that you write your components in C++. You could use the framework in Basic but to customize it you needed a leap up a cliff in complexity. Whereas Delphi's VCL was written in Pascal just like your own code, the source shipped with the product, you could step through it, and you could even make a copy of the source and modify it as a step on the way towards writing your own component.
On the other end of the spectrum, looking at the Windows compile instructions for popular C++ products makes me reach for a bottle, of Advil or Absinthe.
Yes, I can customize any component assuming I have the source (and modification rights), but for some components, the customization comes naturally, with others, just getting a runnable binary is a whole-week ordeal.
Annotations feel very action-at-a-distance-esque because the code that scans for them and processes them is completely separated from the annotation itself. There's no really universally applicable way of just going "show me all the code that processes annotation X" to your IDE... and that's often scary and can also lead to incredibly hard-to-debug problems which would be near-instantly solvable if you could just see the code which processes an annotation immediately.
I feel decorators/higher-order functions are generally to be preferred since it's actually about applying concrete transformations. (Of course they may not always have equal power, but a lot of the time annotations are basically just a HOF in disguise.). Unfortunately, without good type inference the syntax of HOF can get incredibly clunky.
Isn't "Find References" literally that? All code that makes use of an annotation at runtime (which is the case for all Spring annotations) needs to refer to the annotation's type at some point.
Do you know of any good intro materials?
Not a problem with the framework per se, but it does add an extra layer of frustration when trying to search for an answer to your specific problem
I guess point here is unless code is smothered with multiple layers of frameworks companies will not like it.
Granted, both extremes are bad, and finding a happy medium is hard.
Hopefully the architecture group's "recommended"/mandated stack also includes great out-of-the-box, company-wide tooling like metrics, error logging, etc., etc.
If their solution doesn't provide these perks, well, yes, that's not as useful.
Mostly they jump on hype train. Few months back it was netflix stack now it seems they are moving to something else. My main work is on a large(ish) application which is in production long before merger. So for now I am not forced on to jump on their architectural astronautery. I just play around with other technologies etc.
I've done this with Jetty, and sure the first few handlers/servlets are dead simple. But when it starts to grow, manually coding these things becomes unruly quickly. As the other commentor says, converting this to Spring Boot should be easy, and a good learning exercise.
Well... how closely are they looking? Not even joking here, although it's kind of funny in a sad way. I've had clueless "enterprise architecture" groups demand that I use some pointless framework or other - some EAI or ESB or ORM or something else that 100% gets in the way and 0% enhances productivity. So what I do is, I declare a dependency on the framework, use just enough of it so they can't say I'm _not_ using it, and then go ahead and write the damned code so that it works and avoids the pointless "framework" they're cramming down my throat.
But if I'm doing a new greenfield project, I would rather prefer serverless architectures with light weight libraries and no frameworks (and perhaps golang). Yes, the serverless still lacks proper tooling and has few gotchas like no resource/connection pooling, cold starts, etc.. but the pros far out-weigh the cons. I'm still highly productive with springboot, but I am willing to discard my favorite tool and as I clearly see serverless stack as the next evolutionary step for application development.
1. CDI has no testing story, this is the biggest point, everything else pales to this. Arquilian is a joke compared to Spring TestContext Framework and strictly speaking not part of CDI.
2. CDI is in general lacking what Spring calls "enterprise integration", convenience layers over a lot of the a bit annoying to use Java EE layers like JDBC.
3. CDI is in general hampered by the Java EE / JCP release model. Spring can in general and does roll out new features quickly. For example we got new functionality into 5.0.4 within a few weeks without having to wait three years for a specification to be perfect and another three years for a supported application server to ship.
4. CDI/Java EE has still no caching story, even in 2018.
5. CDI has no MVC story.
- The API violates many of Josh Bloch's guidances [1], including items in Effective Java.
- Many of its features are incompatible with itself. For example, the AOP support cannot be used with loaders, writers, or listeners.
- The AOP support does not support atomic memoization (dog piling [2]) and can crash if initializing the same cache concurrently.
- The JavaDoc dictates implementation details that matched the lead's product, rather than being open ended to allow alternative algorithmic choices.
- The JSR defines an configuration API that is not suitable for production use and promotes the silent usage of unbounded anonymous caches.
- The interfaces do not attempt to feel natural alongside the Java's Collection Framework nor the direction that the language has been heading. It redefines terms, like "access", in an incompatible way.
- Despite numerous delays in being accepted, the JSR was not modified to take advantage of significant changes in the language (java.time, lambdas, CompletableFuture, etc).
- The TCK is not robust, does not check concurrency, and bugs in it languished.
- Most importantly, writing code using JCache is not enjoyable and it is often not flexible enough to solve most needs.
There are likely many more, but that is a short list that comes to mind in a few minutes.
- Cache.iterator() may return a null entry, despite null key or value is disallowed. This occurs when the cursor points to an entry that no longer exists - hasNext() was true, but the entry disappeared due to removal/eviction/expiration. This is a performance optimization to avoid underlying I/O that leaks to users and violates their assumptions.
- Cache.putAll(map) first invokes CacheWriter.writeAll(list<entry>) prior to storing them. The writer uses an in/out parameter so that if an exception is thrown, the user must remove the successfully written entries first. Then cache must store those successfully written entries before propagating the exception to the caller.
- An amusing bug was that their custom future could not be consumed by multiple threads. It used notify(), not notifyAll(), so only one waiter would wake up. The concerning part was that this existed for a few years due to lack interest in releasing a new version.
Past a threshold of codebase size and complexity, I see the value of course, but IoC frameworks get pitched too often as a thing that everyone should be using IMHO. Even for testing we already have mocking tools that handle replacing component objects with mocked versions just fine, and we don't need IoC tools for that.
Well, that place needs those objects to do its job.
> When / why is that ever a thing that someone needs to do so often that it becomes a concern?
In web applications, at least, you find yourself with a few controllers, which all need a few services which all need a few repositories to access the database... I guess you can see where this is going. Declaring in your class' constructor that instances need an object of `Type` is the less repetitive way of saying that an instance of a class needs something. Writing the code that builds objects and passes them to your constructors would be quite repetitive.
Maybe something like the mediator pattern? There's definitely use cases for it, but I think a lot of the time the cure isn't any better than the disease.
I can deal with both, but just a preference.
In general, dynamic integrations like IoC, etc make things harder to troubleshoot/debug as well.
Inversion of Control is really good and there are no reasons not to use it. When you have something that can be done in multiple ways, make a small interface and several implementations for it.
The trick now is how to decide what to use. The simplest way is just to parse your configuration file or application flags/arguments in main and instantiate the concrete implementation of your classes there, then pass them down all the way until you need them. This is explicit, simple and clean.
Spring makes you (at least) do two things wrong:
1. Configure the concrete implementations the wrong way. You don't want your users to decide which class implements a certain interface. You want them to decide something higher level, like for example "get crash data via e-mail" or "get crash data in logs". The rest is implementation details.
2. Annotations for autowiring: my feeling is that those are just to go around Java verboseness. Instead of typing "VeryLongName veryLongName = new VeryLongName()", "@autowire" it easier to type. I have always seen it misused (used for stuff that is not Inverted/Configurable) and it makes code more magic. Even worse, you are back at having classes pick their dependencies, even if they are interface implementations. If your classes take their dependencies as constructor parameters, everything is much more explicit.
This is the guidance that Spring team members give, to the point that Spring now defaults to injecting constructors without annotations.
I agree that field/setter autowiring is Satan's handicraft.
Not all of this is Spring's fault. Java has the JavaBeans standard, which created a universe in which setter injection is common. JPA, for example, requires no-arg constructors. It makes me sad.
This is especially useful when implementing tests because it is easy to inject mock implementations of dependencies.
Personally I'm deeply suspicious of mocking as an approach to testing code. I much prefer a functional approach with explicit data flow between parts of the system, rather than indirecting control flow through vtables using complex ad-hoc protocols that become part of your specification by getting baked into mocks in tests. IoC and mocking promotes dataless Verber, Doer and Handler classes that have no real place in an OO model of a system.
We shouldn't forget that decoupling isn't good for its own sake. Things that change together are already coupled; decoupling them at the implementation level is usually an obstacle in every way, whether to understanding, effort, performance, whatever. Abstraction use vs programmer experience generally follows a hump shaped curve; beginners know nothing, intermediates abstract everything, while experts use fewer more powerful, more composable abstractions and code more directly elsewhere. Mocking IMO optimizes for the middle case of too many non-reusable abstractions.
Also, you don't need to swap everything, your application (in fact) has hard dependencies. And mocking everything is not always the best way to test system (sometimes it's totally okay to mock the whole db)
The problem with the cult of DI fanatics is that they can sometimes take it too far. Sometimes code is tightly coupled to the implementation by necessity, and it doesn't add any value to have additional layers of misdirection. Although I'll admit that this is a bit of a strawman, since IoC can be summed up as "give things what they need", which is generally a sensible approach.
At test-runtime, one will pass mock objects to the SUT's constructor using the new keyword. These mock objects are used to rig up specific preconditions that drive the scenario to be tested. Mocks can also be used to assert that the SUT called the dependency as expected with parameters.
At runtime, the IoC container handles instantiation of the module and injects the dependencies as appropriate constructor params.
I assume you asked this because Spring Framework is the poster child of dependency injection and IoC in the Java world. With all the Aspect-Oriented Programming and proxification and scope twizzling that occasionally blooms in the Spring ecosystem that is all wired-up using Spring DI, I think Spring sometimes gets a bad rep. Only abusers of those features get bad reps with me. Spring as a whole is a trove of nicely built systems with lots of classy 3rd party integrations. I personally prefer using Google Guice for DI because it is a standalone system, it eschews doing classpath scanning to identify injectable classes which I think makes it faster especially at startup, and it has decent integrations with 3rd party libraries.
[0] http://olivergierke.de/2013/11/why-field-injection-is-evil/
[1] https://github.com/spring-projects/spring-framework/wiki/Wha...
Note that DI is just a form of IoC and both are separate from Spring. You can "manually" do DI by passing objects to constructors yourself. Some people have a complex web of dependencies and Spring can help make this manageable. Other people don't but have a hatred for passing arguments to constructors.
Also, Java is statically-typed language and DIC are a way to do more dynamic stuff (@Transactional proxies) - such things are possible without DI in some other languages.