Josh Long delivers a masterclass on how Spring Boot 4 finally sheds its legacy weight to become a high-performance, AOT-native powerhouse. This is a vital roadmap for anyone looking to bridge the gap between enterprise stability and modern cloud efficiency.
Deep Dive
Prerequisite Knowledge
- No data available.
Where to go next
- No data available.
Deep Dive
Bootiful Spring Boot 4 by Josh Long @ Spring I/O 2026Added:
[sighs] >> Morning.
Ah, you all got coffee. I didn't get I didn't get a coffee. I'm jealous. Hey, one more time. This time you know, just uh same thing, okay? We're going to take a photo. It's going to be great.
Just pretend like you're happy. Oh, I've got other photos. Oh, hold on. Here we go. Red No, that's not working.
>> [sighs] >> Ding. That is a I like this venue. I like the last one, too, but this is cool as well. All right, look. My name is Josh. We don't have a lot of time, so let's dive right into it. I just wanted to talk about the latest and greatest, you know me. I just I feel like it's really important to kind of see all the stuff. And I think some of you have been here before. How many of you have been here last year?
Okay, so a lot of you are a lot of you are new. Wow, welcome. Um By the way, I'm obligated to tell you that we're giving away we have a cards, okay? I I don't These are Here. These are cards. Take some of these and pass them around. They're silly. I don't know what they are. You can go to the booth and collect more the Tanzu booth, I'm told. I don't know. I don't know what they are, okay? They're just It's a card based on each speaker, and so you can get them all like like Pokémon.
Okay?
Okay. So, anyway, my name is Josh Long.
I work on the Spring team. I'm a Spring developer advocate, a Java champion, a Kotlin Google developer expert alumnus, Microsoft MVP. I don't know how, okay?
Don't ask me. No No idea.
Uh uh I have a YouTube channel. We all make mistakes, okay? We all make mistakes. Mine I am a YouTuber. And I'm Look, I'm not I'm not saying it's glorious or anything, but it does exist. So, you can you can the internet in Europe, okay?
Here we go. This place is a a YouTube channel that I run with my buddy DeShawn Carter and James Ward. And there's me over there, right? So, you know, join the join the adventure, like and subscribe, that kind of thing. It's not going to be the worst mistake that you make today, probably, okay? Um maybe.
Okay, it might.
It might be the worst. I'm online. I I have email. Who's using email? Anybody Anybody here have email? Email. Email.
Email. No, good. Moving on. Um The word The Blue Sky, who's using Blue Sky? Should I even bother? Like 10 of you.
The bird website?
Yeah, one of you. And then And then the code Oh, the code, this is old. Okay, hold on. We're going to change this. It's the 14th, and then beautiful Spring Boot, and I'll just call this uh four, and we'll call this Spring IO.
Okay, I'll put whatever code we create in there. Now, my friends, look, today I wanted to talk about some of the latest and greatest features in the world of Spring. And obviously, to do this, we need to motivate this. And uh you know, I think about I think about this a lot, right? Because I want an example that we can look at.
Obviously, we've all seen the Spring Pet Clinic, right? Pet Clinic here. And this is a sample application from the distant distant past.
Here we go. But this application has been maintained recently. If you look at this, this was There's code that was just contributed to this just a month ago, last month, right? Uh and that's that could have been 15 days ago and still qualify as last month, who knows?
So, I like the Spring Pet Clinic, but there's we don't have a lot of time, and there's too much. In fact, if you look at this, here's the GitHub organization called Spring Pet Clinic, and there's like there's actually a whole bunch of different implementations of the Spring Pet Clinic in different technologies, right? So, we could Who has time? But I do like the animals aspect. I like the I like dogs and and cats and whatever. And I And I think about animals all the time. In fact, if you get those cards, and I have more of those cards, by the way. I have like a lot more. Just Just come to the booth, okay? Um If you look at the card, there's a picture of me and our dog Peanut, who who's no longer sadly he's no longer here, but uh he is is is kind of a spicy dog, you know, very He's a He's a fun dog, but he's also quite problematic. And um he reminds me of another dog that I learned about during the pandemic named Prancer, right?
Prancer the owner of Prancer back in 2021 wrote an article describing Prancer. She says, "Okay, I've tried. I've tried for the last several months to post this dog for adoption and make him sound unpalatable.
The problem is he's just not. There's not a very big market for neurotic, man-hating, animal-hating, children-hating dogs that look like gremlins.
But I have to believe there's someone out there for Prancer because I'm tired, and so is my family. Every day we live in the grips of the demonic Chihuahua hellscape he has created in our home."
And then she continues on. She says she says, "He was quiet and just laid on the couch, didn't bother anyone. I was excited to see him come out of his shell and become a real dog. I'm convinced at this point that he's not a real dog, but more like a vessel for a traumatized Victorian child that now haunts our home." Right? And she continues on. And it's very funny, but at the end she says, "Oh, he's only only 2 years old and will probably live to be 21 through pure spite, so take that into account if you're interested, okay?" And I think about this dog a lot.
First of all, because he's probably seven now, not two. Um but also just because he went viral, right? He's a He went viral. Let's see. Prancer.
Here he is. Here's a like the New York Times covering Prancer the the demonic Chihuahua, right? Here's uh BuzzFeed News caught up with Prancer nightmare Chihuahua, right? Like he went viral. So, he did get adopted, but I want to build a service to help adopt dogs. That's what we're going to do here today, my friends. We're going to build this I'm going to call this adoptions because I'm amazing with names, okay?
I'm great with names. I get that from my father. He was amazing with names. When I was a small boy, we had a small white dog, and my father named him white dog, okay?
Amazing with names. So, I'm going to bring in the web support. I'm going to bring in Postgres. I'm going to bring in the the dev tools support. I'll bring in the GraalVM native image support and the AOT support. I'll bring in the Spring Data JDBC support. No, that's session. I want Data JDBC. Here we are. Okay.
Uh I don't need the session stuff, although that's very nice. I'm going to bring in the actuator. I'll bring in dev tools. Do I have dev tools? I think I just took it off. There we go. I'm going to bring in security. I'm going to bring in web off n, okay? So, I'm going to bring in just a number of different things in here to build a simple application. And you know, you'll notice that we're looking at the Spring Boot 4.x and Spring Framework 7.x releases.
So, there's a lot of interesting things that are happening here. I also want HTTP client support. Notice that this is a separate dependency. It used to be in Spring Boot 3.x we had this thing called auto configuration. Auto configuration is the thing that allows you to start a brand new empty Spring Boot application and you have a web server or you have a connection to a connection pool, even though you've not written one line of Java code, right? Maybe you specified some properties. That auto configuration runs when the program starts up.
Historically, there's been one giant monolithic auto configuration. Well, now in Spring Boot 4, we've decomposed the auto config. Now, the configuration for each starter lives with that starter.
So, if you only have one starter on the class path, then you don't have all the code from all the other starters on the class path, which in turn improves startup time and so on. But the other benefit of this is that we have more granular starters. So, we can actually have like a starter for HTTP clients and a starter for Spring web server, right?
To build an MVC service. These are two separate things. Before, you would have Spring Boot Starter Web, that would bring in the rest client and the web server. But if you're building a Spring Batch application or a Spring Shell CLI application or a Spring Integration or Spring for Apache Kafka or whatever, all these applications, you know, they don't need a web server.
They're headless. They They operate in the back office sort of use case, right?
So, now you can have just an HTTP client even if you don't want the web server bits. And you know what? We're also going to bring in Spring Modeler because why not?
So, let's hit generate. And again, I chose Java 25.
Remember, friends, we have four versions of Java, but only two valid choices, okay? These This is the current long-term release version of Java. This is the current version of Java. And these other two versions we keep mainly to see who makes terrible life decisions, okay? So, you should never ever select these. Remember, Java 25 is technically superior in every way. It's faster, more robust, more syntax rich, more performant, more operation friendly. It's also morally superior, okay? You won't like the look of sadness and shame in your children's eyes when they see that you're using Java 8 in production. Don't do this. And remember, Java 25 is also mathematically superior, okay? It's at least three times greater than Java 8, okay? Simple math. Simple math. It's just a fact. Hard to argue.
Okay, hit generate.
Open this up. Here we are.
And we're going to connect to a database, so let's go ahead and do that here. Application at properties, waiting for the IDE to load. I I did a presentation a few weeks ago with my friends James Ward, who's here, by the way, the legendary James Ward, my hero friend and mentor. He's here. And Dr. Venkat Subramaniam, the legendary Dr. Venkat Subramaniam. And Dr. Venkat Subramaniam, he he said something when we when we presented a few weeks ago, he he said, "There are two types of developers.
Those who have idea and those who have no idea."
And I think that's a really really brilliant thing to say.
Okay. So, let's see here, huh?
Um So, we say Spring Data Source.
Uh password is uh secret, right? And the username is my user.
And the URL is JDBC BC colon Postgres QL localhost my database, okay?
Here we are. Good. So, there's our application. We're going to connect to a database, and we're going to build an application that talks to the database, okay? Oh, did I choose Groovy? I like Groovy, but I'm not very good at it. So, let's undo everything we've just done.
How did I choose Groovy by accident? Oh.
That's scary. Okay.
Don't worry, it's going to be fine.
We've only typed a few lines of code anyway.
All right.
No wonder IntelliJ was like taking its time, you know.
Okay, here we go.
Good. Spring data source.
It's still taking its time.
Here we are.
Maven.
Oh, is it because of the Java code? How much you want to bet it's because of the JDK thing? Yeah, SDK.
Java 25.
Please.
Maven sync.
Okay.
Okay. When in doubt delete.
Uh for the in spring io. Yes.
Okay.
You have to do invalidate caches. It's okay.
Oh, look at that. Much better. Spring data source.
Uh pa- username is my user.
And the password is secret. And the URL is JDBC. That's close enough. My database. And voila. Okay. Very good.
So, now we're co- we're connected. I'm still going to call it adoption. I don't care what IDEA says, okay? Here we are. And what we're going to do is we're going to talk to the talk to the database. So, I've got a a database running. I'm going to describe my entities using Spring Data JDBC. I love JDBC. All right, I'm going to do that. String description. Okay.
Description.
Okay. And I'll say at int ID. And look at this. I'm using Java records. I love love love Java records. Huge fan, right?
Huge fan. Okay. Going to create a dog repository extend a list of crud repository who manages entities of type dog whose primary key is of type integer. Very good. And you know, I'm going to I'm going to create a simple controller to return information about the dog. So, we'll say at controller at response body class dogs controller.
Okay. And what I'm going to do is I'm going to inject the repository there.
I'll say dogs controller.
Uh like that. And I'll actually you know what? I'll do it the old fashioned way.
Final dog repository. And voila. Add that to the constructor. Create an endpoint dogs, not digs.
Dogs. Collection of map of string of object dogs. Okay.
Look at that. dot find all dot stream dot map. And I'm going to take each dog and I'm just going to return a view of the data showing the full name. So, I'll just do Java lang object downcast so that it's a lowest common denominator type dot name. And then the ID and dog dot ID, okay? And then to list. And then I'll say return There we are. Okay. This dot repository etc. Okay. Very good. So, I've got my simple controller. Let's go ahead and spin this up. Oh, wait. We got one more problem, friends. I'm going to do something terrible, something you should never ever do. And if you leave right now for whatever reason, and the last thing that you saw me do was to comment out security, just know I'm going to bring it back, okay? The lesson here is not to comment out security. Okay. Here we are.
Good. Command shift I.
Reload this.
All right.
So, now local host 8080 dogs. Voila. Okay, it worked. Of course it worked. It was a demo.
It was it was always going to work. So, so there's that. I This is fine, but you know, product management will come by and they'll change the requirements. And maybe we have a new endpoint, okay? We have a new version of this endpoint. So, we go here dogs and we say collection of dog dogs return this dot repository dot find all. And then and that's fine, but now I've got a new version 1.1 version of the API. So, what I'm going to do is I'm going to take advantage of version versioning API versioning in Spring Framework 7.0. I'll make this the 1.0 version. And then the new one will be 1.1. And I'll specify that the default is 1.1. And I'll specify that if somebody wants to override that, they can use a header or a media type parameter or a path segment or a query parameter. I think I'll use a header, okay? The header will be called X dogs version, okay? So, now if I reload, I go back here, the default gives me the full details, right? But if I want the actual details from the old one, I can get that as well. Minus H X dogs version 1.0.
Paste that and I get that as well.
There's the full name, right? So, that's the old version. And if I get rid of this here's the new version, okay? So, I have API versioning built into Spring Framework as a low-level thing. That's really convenient. Okay, so we've got this.
We've got this low-level thing. I've got API versioning.
You know, it can't all be about dogs, of course, right?
Maybe maybe we want to have an endpoint for cats, okay? So, here's what I'm going to do. I'm going to do controller at response body cats controller.
And in order to do this, I'm going to call a third-party service to get information about cats, okay? I'm going to build a client here. I'm going to inject the rest client here like so.
Rest client. HTTP. Add this to the constructor. And I'll just build it just like you saw a million times before, okay? And this is going to be a regular Spring Bean, no big deal. And we'll have the client. And then I'll have an endpoint here that returns we you know, cat facts. And it'll return a collection of cat facts array. So, a collection of facts about cats, okay?
There we are. There we are. And now I'll say cat facts facts return this dot HTTP dot get dot URI HTTP localhost. It's actually HTTPS.
Okay.
www.catfacts.net/api.retrieve.body cat facts class, okay? So, there's my very simple client. And I'm going to build a controller with that. I'm just going to basically just proxy the data, if you will. I'll inject that into the controller here. And we'll say at ca- cats cat facts.
Okay.
Here we are. Very good. Let's reload this.
Oh, actually I didn't need to reload. It was already there.
Cats.
And now it's going to take its time and there we go. Cats have fact in their diet. And according to a myth, they might have if they have their paws underneath, they'll have cold weather.
Okay, great. So, the website worked. We built a client. But that was a lot of code, wasn't it? I had to write all this code here to get that that client right.
And really all I care about is this.
And I want to map the JSON to this shape. Well, in Spring Framework 6 a few years ago, we introduced declarative HTTP service clients, okay?
Um and so, we're going to take advantage of that. You know, cat. We'll just call this There you go. Exactly. Right? And all I need to do is to make this work is I need to do get exchange. And then I put in the URL.
Okay.
Very good.
Paste. And now I I can remove this. Now, in Spring Framework 6, unfortunately, this required a fair bit of configuration to make this work. It wasn't much, but it was just boilerplate. Well, now in 7, you can say at import HTTP services. So, cat facts client.
Okay.
Uh that one. Good.
And now if I reload the same endpoint returns with the same data. Right? Isn't that convenient? Very very convenient. So, we have this nice built-in. And I can delete code, which is my favorite pastime. Okay. Good. So, now we have a client. Now, look. This website this service has been working every single time I use it. It has never failed. Oh, yeah.
All right. It has never failed. That said, things are going to fail all the time, right? Last year, we had not one, but two amazing examples of this, right?
Last year US East 1 in AWS went down.
And with it, the in- half the internet went down, right? Look, I'm not blaming them.
This is probably the best run data center on the planet. And if it can go down everything can go down. And so, we need to build accordingly. We need to build our software to be robust and immune to that kind of turbulence, okay? And so, you saw Jurgen in the keynote. He talked about how we have pushed some very nice primitives for resilience into Spring Framework. And so, we have at enable resilient methods.
And then I can I'm going to go to my code. And I'm going to do something terrible. Normally, I would never do this, okay? I'm about to purposefully add errors to my code. Sometimes this is called PHP. Now, I I would never do this otherwise, right? But I'll do it now to demonstrate what would happen if we throw an artificial an exception, okay?
So, I'll say private final atomic integer.
Okay. Very good. Starting at zero just to be sure. And here, I'm going to say if this dot counter is less than five, okay? Throw new exception.
And I'll say new illegal state exception.
No sangria, okay?
Um I would have print line oops. And then Yay, okay? There we go. So, we're going to we want to make sure that even if there's an exception, if something should go wrong when we make the network call, that we retry this request. So, I'll do retryable max retries is five include this illegal state exception, okay?
Let's restart this. And so, now if I reload that endpoint, you go to the console here.
This one.
Oops.
Reload. Oops. Oops. Oops. Oops. Yay, okay? So, it actually retried the same request and we eventually got the response even if the service is down.
And you can schedule you can do things like you know, exponential back off and all that kind of stuff to make it more robust. The point is things will sometimes go down. They might be in the in the middle of reloading. They might be in the process of upgrading, whatever. You want to be able to retry.
Uh this is in the case that the downstream service is faltering for whatever. But sometimes you want to avoid being the cause of that faltering, right? That's a problem that you might have. And so one thing you can do is also to use concurrency limits so that you don't saturate the downstream service, right? Here we're going to have a semaphore that basically limits how many threads can enter this method to 10, right? That's very convenient as well. Okay, so we've got uh we've got our robust uh declarative interface client. We've got our cats controller.
We've got our dogs controller. I think we're doing pretty good. We've got API versioning. Um and so far I've been creating objects and I've been annotating them with @Controller and @Component and uh @Service. You may know this, but it's worth restating that @Controller is actually a meta-annotation. In Spring, all all annotations that declare components are annotated with @Component, okay? All Spring beans. This is an implicit implicit i m p l i implicit way of declaring and configuring your objects.
Spring decides based on the shape of your object, the constructors, the parameters, how to wire that object up for you. But you have to let Spring know how these objects get wired together, right? This is implicit. And anything can be a component, right? You can create your own meta-annotation. I don't know if you know this, right? So I could say um Let me see. Uh Okay.
Accept all.
Okay. Bean.
And then we're going to take it to Spanish. Frijole. Okay, there you go. So we're going to create a uh this I'm going to take this code.
Okay.
And bop bop uh whoop There you go. Whoop. There you go. So now we have our own custom annotation, a meta-annotation uh that is itself a component. So if I annotate, let's say Where is a Let's create an object here, just a simple my runner implements application runner, right? And if I implement that, I would have print line.
Hola. Okay. If I say @Frijole that's a Spring bean, right? If I reload this, you'll see this gets run in the application. So we created a meta-annotation. Hey, hello. We created a meta-annotation by using that that meta that component annotation. And everything is a a component. So a controller is a component. A service is a component, right? It's a stereotype stereotype annotation, but it's a component. A repository is a component. And a rest controller is No, it's a controller. You You are all so silly. It's a controller.
And that controller is a component, yes, right? So it's a meta You can have a cascade, okay? So this is implicit configuration. Explicit is when you use Java configuration, right? I say uh over here class my configuration and I create a bean my runner runner and I create this Spring bean as a part of the configuration class. And by the way, the configuration class is also a component, right? If you look at the annotation, everything is a component. So there's the annotation So far I'm going to comment that out.
Actually, if I leave that in, uh we might see the same bean twice, right?
There you go. Same bean got registered two different ways, right? So that's fine. Uh maybe if I comment this out go back over here reload Okay, there you go, just once. So you can register beans different ways, but the point is Spring eventually needs to know about how these objects are wired together. There are some limitations, however. If you use implicit, we pick the constructor. You have ways to to help us decide by using qualifier and @Autowired and things like that, but we generally it's up to us to pick the constructor and construct the object and we create a singleton unless you tell us otherwise and so on. With this, you have full control, but it's a lot more code.
It's it it's four lines of code just to create the object when really the one annotation could do the same job in this case.
But you know, the choice is yours. If you have access to the source code, maybe you don't do this. Maybe you use @Component. If you don't have access to the source code, you do something like this. But how do you create more than one of these, you know, dynamically based on some config file, right? And what if you wanted to do it programmatically? What if you wanted to look at something in the environment and then decide to register something? There are ways to kind of achieve this, but there's a new way that I like a lot called a bean registrar.
Okay. Bean registrar.
Implements bean registrar. Okay.
Add that. And this this is a a a configuration class that you can register just like you would any other config class, right? @Import like this, okay? And the registrar, by the way, you you heard this in the keynote as well. You might have noticed it here. Um notice that the arguments here is great It's a beige, right? Same thing for the bean registry here. That's because this class is in the package org.springframework.beans.factory.
If you look at that package in the package-info right? Where is package-info?
Whoop, there it is. It's right in front of me. It's annotated with @NonNull Marked.
This says that everything in the package is not null by default. And then if somebody wants to make something null, they have to opt into the nullability, right? So in in very specific cases, we have nullability. So basically the IDE is saying, "Hey, we're not expecting a null reference and yet you have written the code in such way that it might accept a null reference. If you want that to go away, you have to say, 'Hey, I understand no nulls, okay? No nulls for me.'" Good. So I've got this bean registrar and I'm going to register a bean of type my runner, okay?
There's This is the simplest example.
This is a implicit almost kind of approach, right? So let's comment out this one and then reload.
Go back here and there is the hola again, right? Okay. So what if I do now a multiple, right? I could do a for loop. For var i i zero, i is less than five, i plus plus.
Okay.
Reload. Command five. There you go.
There's four of them, okay? So look look at look at that. We're actually programmatically registering things with the system as we want. Now I can also control all the construction of the object. Maybe my object has a constructor that I want to call, okay?
So I create a constructor here and I'll say um you know, string message, okay? And I'll private final string message and I'll just do this.
And this.message equals message, okay?
And then the other one will be this.
this.
Hola. Okay. And and now I have two different versions and you know, I'm going to print out the message either way.
So this.message. Very good.
So now what if I want to control the the construction? Here I'm using the default constructor, but if I want to control it, I can do that as well. I can say uh whoop whoop whoop. Okay. Var m equals uh hello number i and I'll say spec spec.supplier uh new function of and then return a new my runner, okay? Passing in uh m.
Okay, now this is a little bit long in the tooth here. Let's lambda-ify it. So much better. Love that. Look at that.
Much better, okay? So there's this and now I can rerun this again.
Go down here.
And you can see it's printing out it's now using our custom constructor as well. So we get the best of both worlds.
You have configuration explicit and implicit. Okay, so now we've got an application. We've got auto configuration. We've got custom dynamic bean registrars. We've got API versioning, dynamic clients, all sorts of good stuff. I think it's time to think about making this thing a little bit more production worthy. And one of the things I want to do is to make it more secure. So I'm going to go back to my old build here, start.spring.io. I'm going to bring back in some security here, okay?
Um here we are. Get rid of all this and that and that. We're going to be using some of the latest and greatest in Spring Security 7.0, which also comes with Spring Boot 4. And um what I'm going to do is I'm going to lock down every endpoint, okay? So @Controller @ResponseBody class um uh no, I don't need that. I need a Actually, no, I do I want that. class uh me controller @GetMapping /map uh I said get I said get mapping as I typed get exchange, okay? No problems there, though. Me principal and then map.of name, principal.getName.
And voila. Okay, so I'm going to log When somebody logs in they're going to we're going to see who's logged in there. Now I want to I want to set up some users. I've got users in a database. And in Spring Security, if you want it to manage users for you, you have to define a bean of type user details manager or user details service. So let's say security configuration.
Okay. I'll create a bean that points to our SQL database here.
Return new JDBC user details.
Okay. There's this. And when I go to the config, you know, I can click on this, command. There we go. Hit test connection. Hit a okay. Hit apply. Go over here and you can see I've got some users in the system, right? If I go here, users, there we are. Oh, let me uh let me reset this, my friends. Hold on.
Drop.
Goodbye.
Force refactoring. Goodbye. Okay. So now I go over here. Desktop misc talk DB init DB. Reload. Okay. What that's going to do is it's going to recreate the database table with bad data, right? Not good data. So, let's refresh. Here we are, tables. There's the users and there you go. You can see we've got three users in there, but two of them haven't logged into the service in a long time and they're using SHA-256. I don't know if you know this, but you should never ever use SHA-256. It's considered insecure. It's basically cracked, okay?
So, I would not use that. BCrypt is pretty good. Argon is pretty good. So, that those are okay, but this old these old users, we want to convert their password. It's it's cracked, but it's not computationally efficient to try and crack it and then reverse engineer it and then migrate it. We want to migrate it to a new password encoding whenever possible. So, what we're going to do is we're going to set up a uh password migration, okay?
So, when the user logs in, when they have the plain text password in memory, we're going to update their password if the password matches the one that's in the database, okay? So, let's reload this.
And I go to localhost:8080/ okay? Now, it's going to ask me to log in. Josh, pw. Great. So, that's logged in. Anything change? I don't think so because Josh was using BCrypt. That's the default. What about Rob and James?
Let's go out here.
Okay.
Incognito. James, pw.
Okay. And now, refresh. There you go. James and Josh are both using BCrypt now. It migrated the password on login. That way we're always moving forward to the latest and greatest. Secure passwords are good, but passwords are bad.
Passwords are not a good way to do security, believe it or not. In fact, in certain governmental contexts, they're illegal.
They're not they're not considered secure. Why? Because so many bad practices exist. Things that we all take for granted as being like the the one true way to solve the problem aren't actually that. One of the things we're often told is you need to migrate your password every 3 months or every week or whatever, right? How many of you get that Do you get that email saying migrate your password? You know what most people do? I'm sure you do the right thing, but most people don't. What Most people don't use password managers.
And so, what most people do is they get the old password, add one, save, done.
Right?
Completely insecure. And so, people are are discouraged from using passwords because they're not a good proof that you are who you say you are.
So, what I want to What I want to do is I want to move away from passwords. One way I can do that is by configuring an alternative login form called one-time token one-time yeah, one-time token. And uh what I want to configure the default configuration for Spring Security.
Normally, in Spring Security 6 and earlier, you'd have to create a bean of type security filter chain and you'd inject the HTTP security and all that.
And as soon as you create this bean, Spring Boot backs off. The defaults that lock down everything and set up HTTP basic and form login and lock up lock down all endpoints disappear. So, now you're unprotected completely. Which, if you know what you're doing, it's fine, but it's not a great security posture, right? So, in Spring Security 7, we have this thing called a customizer.
And you can additively It's additive.
You can add things to it. So, I'm going to add a one-time token a one-time token login.
Okay.
And I'm going to say when somebody logs in, attempts to log in, let them let them log in with this token. Now, this is You've seen this before like with Slack.
If you've ever used Slack, you know what I'm talking about. You You enter your email, it sends you an email, and you click on the link, you're in because they verified that that email is you.
And if you have access to that email, you must be you, right? You must be who you would say you are.
But, this is not a password that you as in your code have to maintain. It's somebody else's password. It's Google or Outlook or whatever, right? Somebody somebody else is maintaining the integrity of that password. So, you still have a password, but at least it's somewhere else somebody else's problem, not yours, okay? So, I don't have time to set up an email server for you today to demonstrate this or to set up Twilio or SendGrid or something to send text messages or something like that, but we're going to pretend I have email or I have something like that on my console.
Okay? So, when the user logs in, I'm going to say right out print line um uh print, I guess.
You've got console mail, okay? And I'll say response.setContentType media type.text.plain.
And I'm going to print out uh please go to HTTP localhost:80 8080/login/ott token equals this. One-time token.get token value.
Get token value, okay?
There's this.
So, let's clean the code up a little bit and reload.
And if I go to here to this incognito window, now I have two ways to log in.
Username password and one-time token.
So, I'll say send a token, please.
You've got console mail. Thank you very much. I know I do. And I've got this URL here.
Okay, take that right there.
Okay, paste. There we are. Sign in. I'm authenticated. Great, okay? So, this is a different way to log in, but it's still a password. It's just not my password. One of the nice things that we have in recent versions of Spring Security is a different more interesting way to do this. How many of you have heard of WebAuthn?
WebAuthn or passkeys. You might have heard of passkeys, right? So, passkeys Where is my uh Well, actually, we can do FIDO Alliance.
Passkeys are Every website in the internet is asking you to set up passkeys right now. And this is a technology that's the product name for a thing that was created by a group of people. Where's the alliance here? A number A number of small mom-and-pop shops that are trying to make the internet a better place. Companies like Amazon, American Express, Apple, Chase, uh Google, Intuit, Lenovo, Meta, Microsoft, PayPal, uh etc. So, what I'm about to show you works everywhere already. This is not like a hypothetical. It's already here, okay?
It works on all the browsers in in Linux. Works on all the browsers on Mac.
It It even works on Windows.
Windows.
Can you believe it? I don't know if you've heard about Windows recently, but things some small things are have been broken in the recent months. Small Good news, they're small things I I'm told. It'll be fine. Small things like the start menu and the login and the file system and the explorer. Those things are broken in recent months. So, the This works there, okay?
Even on Windows. I can't believe it. So, we're going to set that up here quickly.
What I'm going to do is I'm going to say uh WebAuthn a allowed origins HTTP localhost:80 okay?
And I'll say RPID is localhost.
And I'll say RP name uh Spring IO, okay? And that's it, done.
So, let's reload. And what I'm going to do now is I'm going to go here, log in, okay? And it's going to say, "Hey, you want to log in with a passkey?" The problem is passkey Well, not the problem. The The thing is passkeys are managed in my case by the operating system. So, I have to delete this passkey and I need to now re-register another passkey. So, I'll I'll log in some other way. I'll just do this. Josh, pw, okay? And now I'm going to go here to Web up Come on. 80 80 WebAuthn register uh Spring IO register.
Oh, did I do localhost? I did localhost, yeah.
Here we go. Sorry about that. Josh, pw.
And now I go here and I'm going to register. MBP, sure. Register. And now it's asking me to use my fingerprint.
Touch ID on the Mac. This is public key cryptography. It's managed on the Mac on the iOS Apple ecosystem by iCloud. It's federated. So, I'm going to set up a Touch ID on my laptop, but when I go to my face, I can use face my phone, I can use Face ID, right? Or I can double-click on the watch. It doesn't matter. It's the same key across all the devices, okay? So, I'm going to set up the key here.
All right, registered. And now if you go back to here, you can see it's right there as well.
And now I'm going to log out.
All right.
Paste that in. And now I'm going to log in with my fingerprint.
Ta-da! Okay. So, now I have I have a secure application. I'm using one factor to log in. Obviously, there are more, right? There are more more things you can show.
You You might want more factors. You might want more than one factor at a time. One of the nice things in Spring Security 7 is we have enable glo No, multi-factor. There you go. That one. And I'm going to say authorities equals factor granted authority.
Factor granted authority.dot. I want to do let's say a password and a one-time token, right?
OTT. There you go. So, I'm going to require both factors to be present before I trust that the user is who they say they are. So, here we go. I'm going to log in with the username and password.
Okay. Now, I'm going to log in with the one-time token.
And I go here.
Copy and paste this.
And voilà. Log in with that and I'm authenticated. Nice.
So, now I have a much better secure system. I have observability. I have uh the declarative clients have been configuration. I have all that good stuff. I think I now need to get this thing in a shape where I can get it into production. And friends, here we're going to take advantage of uh the AOT subsystem in Spring uh Spring Framework 6 and later. And we're going to turn this application into an application that runs well on Project Leyden, right? You've heard of this.
Leyden is a mechanism from the JDK. And in order for this to work though, I need to specify a dialect. So And the reason I need to specify this is because I'm going to do compile time code generation and I need to know what dialect to use for my you know, the compiler needs to know what dialect to use when it turns my Spring Data Repository into a concrete implementation because that's going to be reified at compile time. So if I go here for example, collection dog find by name string name, okay?
Hello. Hello. Okay, good. So let's try this out.
I have a script, okay?
It's a script and what it's going to do if if you look at this, it's going to it's going to turn it's going to run the up compile the application and then run the Spring Boot application jar in jar mode extracting the the AOT stuff. It's going to then run the application up until the point where it's about to start and then capture information about the objects that are created, the classes that are created, etc. And then finally I'll run the application with that with that profile that we've captured, that photograph that we've captured, okay? Oops, let me stop it here.
That might have ruined it, okay? So it's it's running the application. This is a repeatable thing. You can do this on every single Java application and the the application now starts up well, in this case well, what did I do wrong here? Oh, it must have been because I had that thing.
Let's try that one more time, okay?
We'll see. Maybe I just got this one wrong.
Okay, running the profile.
Yeah, well, there you go. There's the application. Uh in this case it didn't seem to make much of a difference.
That's a bit of a shame. Okay, my friends, we have built an application that starts up reasonably quickly. It doesn't it does it's that's basically the same speed as always. We've built an application that uses compile time code generation here. So if you look at the output of the target directory forgot to show you this. This is one of my favorite features in Spring Spring Data the one included in Spring Boot 4. So sources com look at this. This is my repository.
This is the code generated repository. This is you can run this on the JVM in AOT mode and notice that that query that I wrote has been code generated. That's what actually got generated at compile time. You can run this directly. You can put a breakpoint in that code and debug it. You can see how Spring Data translates your query into calls to the underlying persistent subsystem, right? It's an amazing result. So my friends, with that, this has been a very brief abbreviated look at some of my favorite features in Spring Framework 7 and Spring Boot 4.
Who learned something new?
Very good. Who had fun?
Me, too. Thank you so much everybody.
Thank you, thank you, thank you. Come by the booth, say hi. Come get a card if you want.
Related Videos
Agentforce NOW AMA: Build with React and Salesforce Multi-Framework
SalesforceDevs
490 views•2026-05-28
How agent o11y differs from traditional o11y — Phil Hetzel, Braintrust
aiDotEngineer
450 views•2026-05-28
WEB TECHNOLOGIES UNIT-2 | Degree 4th sem BCOM Computers web technologies unit-2 full explanation💯✅
LearnwithSahera
1K views•2026-05-29
More tests are always better? How to use AI to identify tests that bring little value
Alliance4Qualification
335 views•2026-05-29
Search Algorithms Explained in 60 Seconds! 🤖💨
samarthtuliofficial
218 views•2026-06-01
People of Game of Thrones using JavaScript DOM
AltCampus
296 views•2026-05-30
Introduction to Problem Solving Part - 1 | Lecture 1 | Intermediate DSA
ascensionix
107 views•2026-05-29
🚀 BCS613C Compiler Design | Module 1 to 5 Schema Evaluation 🔥 | VTU 6th Sem 💯 #VTU #bcs613c #exam
Pranavaa-y4y
104 views•2026-06-02











