It's a Kind of Magic: Under the Covers of Spring Boot - Brian Clozel, Stéphane Nicoll

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hello everyone welcome to this presentation so we often hear people saying that spring good does all kinds of magic and you don't know what's going on and I mean that you'd better figure that one this one is magic really this one so we wanted to have a a talk so you could go from how does that magic work to this is working like this and by the end of that talk you should be able to reuse that infrastructure and be like yeah this is not magic at all it's just stuff that I use everyday now so we hope that will explain everything and that will there's won't be any magic by the end of that talk so remember this is a deep dive session three slots so the way we intended to do this is 45 minutes then 20 minutes break so that you can rest your brain a bit probably be necessary and then 45 minutes again so we'll cover all kinds of topics will do gently at the beginning like we did basics then going to the hardest stuff of we're not too hard to explain and then we'll gently land again with a few additional concept and misconceptions about people ah spring in general yeah so let's get started or what yeah oh do we have a couple of questions maybe oh yeah so first one who's using spring boots keep your hand up if you're using an introduction alright so go down who is not using spring boo that would probably be easier okay maybe 20 interesting perfect but perfect so we'll use in the course of this talk we'll use a very basic spring boot application as you'll see with a service that very complex not complex at all news so the purpose is not to focus on the on the function and key but on the infrastructure because that's really what's been good is all about configuring things by default for providing opinions and how you can all you can actually customize those opinions or maybe provide your own implementation so let's have a look to our domain today very complex so we have this interface that says it'll be the name told you a very complex and there is an implementation that takes a prefix and a suffix so here ello and exclamation mark and basically I'll put something in the console what that implementation is put something in the console so our world basically and we have an app this app has a dependency for now on that service and the most simple Springwood starter you could find and this app is empty for them at the moment okay there's nothing so should we implement something now should we yeah let's go okay now so let's implement something that we will use so I look I'm on language oh hello so what I want to do is I want to use this I want to use this arrow service to do something so for that I can use the commode annular from spring boot it's a callback interface where I can run something once the application has started and I want to use the yellow service and let's start this app oh yeah I need to make that a component and let's study stop as you wish as you may expect that app will fail we don't have any implementation or we can inject anything we don't know about it or service no doesn't work so you can see here we get a very nice error message you'll find out how to create your own later in this talk and okay just to get started let's create a bean so let's create a version of the other service and say something like OD and have a bad character here there we go so I'm creating a beam definition photo the thing that does not exist and nothing happens why because I guess I didn't call it right probably call it so instead of printing hello or whatnot you could think about this about like how do you configure a tomcat embedded tomcat server or anything related to a database etc so we're going to use that sample but that's this can can be applied to any other thing we are Auto configuring in spring good so yeah here's what here's what we've got so our simple application is annotated with preamble application it's got a main method and we're running the application running that main method so if we move here we know that that spring good application it's actually Madonna dated it's several applicants everal annotations in one so if you look at the source of that annotation you can see that it's made of several the first one is spring good configuration which is more less like at configuration with a little twist we've got companies scan which is about scanning for beans and components in your application so if you don't provide anything by default it'll scan from the current package of that class and under and we've got the last one with which does all the magic and we'll see it's not magic at all so enable our configuration it's triggering all the auto configuration for spring boots so looking at signs and opinions that you've got in your application and configuring things for you so it can be very simple or you can express opinions in more complex ways or subtle ways with with properties with customizer and whatnot and we will adapt to that and give you the best experience possible so whether what that means also is that me component scanning all the auto-configuration infrastructure is in mandatory concept in spring but-- so you could completely disable them you could not use components get at all if you want to or you could also use spring boot without the other configuration if you choose to you lose a lot of features but there is nothing that prevents you to do that so this is we wanted to show you that just to show you that a spring google application is just reusing several parts of infrastructure and if you selectively enable them you get the expected result is it's not one hard-coded and code pad that says i'm doing everything it's really come not driven it's really organized just like our code base so you can see what's going on okay so we already talked a bit about competent scan so common scan will scan for beans and components so within a particular package so if you provide one in the annotation or the current package where you declared it and so that's how it goes so if you declare it on in the on a class in package come example hello it'll scan into alpha and Bravo and obviously they come example Charlie won't be won't be scan at all and it can be you can look like obvious in that case but it happens a lot so for example if you if you don't create your application we'd start the spring the i/o the starter spring that I don't not only provides a builder grade or upon that XML file with all the right dependencies and all it's providing you with the right structure and by accident if you just I create a class in the in the wrong in the wrong place you can end up with something in common example Charlie and it won't be scanned at all and you don't know why it's it's really it can happen really easily if you if you don't pay attention so to fix that obviously you need to move that package and it will be scanned so that's why we try to have that spring good application annotation which should be at the root of your application you should like design your package structure so that in its organized like this so this is really the recommendation right so you have a dedicated package for your app your app is in that package and then your structure your code underneath if you do that you'll get as Brian just explained sensible behavior by default but it will also expand to two things that we don't have the time to cover today like slicing so slice test where you only focus on the part of your application for instance data GPA test allows you to test on your data your Web MD test allows you to only test a controller so we are doing something to start the application with a narrow view of your components basically and this is also using that as a default if you disagree with that and you want to structure your code differently it will be alright but then you have you have to configure that yourself okay so component is one annotation but we've got many more configuration with mastery controller etc many of those are specialized types of components some of them like service are just components in these guys that they're just doing the same thing is just a declarative way to say this is a service so it's just your unit dedicated stereotype yeah and others are doing more they have more attributes and they tell more about your component and they are treated differently let's go and do that on application yeah or I guess I guess yeah what something I could I could quickly quickly mention here is we we can play a bit with our app and for instance we can demonstrate remove spring with application so it's basically removing all features and then you notice you notice that the message does not print out so basically if you remove that configuration is disabled so this is not really taken into account components can is disabled so this class is not scared anymore and this application is starting without the other configuration support right now in this case we're not using any of it so that's why you don't see a difference but you could also write this if you want it to the company scan and configuration which are two of them two of the annotations that you have in Spring good application the only thing we don't get here is the other configuration so you're basically starting it's pretty good app without do to configure so there is nothing really specific about to bring boot application it's just an opinion about the fact that your spring boot up is a configuration class that you want to scan from the package where the spring good application is defined and you want to use the other configuration infrastructure so if I move this class as Brian explained if I remove discussed for instance in your sub package than the this one won't be found any more etcetera etcetera right so to summarize so this is what we've got we've got our application a component so those components in means when your application starts what happens it's being picked up by spring amongst other component types of components and those are turned into beams one for application to be useful right and but those beans are in a separate phase are what we call the user configuration phase so this is specific to to boot we are separating in two phases one is all the confidence in your application code all of those are gathered and turn into bin definitions at a certain stage and there's a separate phase which is the auto configuration one and that's where we look at all the possible and candidate beans into the other configuration that boots provides and and that's where we we can create the beans that the boot configuration will will provide depending on your opinions so that's really key right so the components can the components can hear a term is just an example you could have used import or XML resources if you want to do that for whatever reason so it's not really only about components candies it's really about everything you have defined and the reason why it works in two phases as you'll see in the examples today is that we need to know what are your opinions before applying ours so we need to know if eventually you've provided two data source if you've provide the data source and user configuration we don't have to configure one because you have an opinion about this so we need to detect that the user configuration on your left is actually actually contains that means and we don't have to create one so we can try and use that in a basic auto-configuration so we can take our application the one we have already and we'd like to create another configuration for our hello service so we'd like to just like boot have a way to provide a hello service if there's none or flexibly provide a recognize your opinions when you when you have some and do something flexible with with that with with that library so so don't worry too much about the code will share the repository with you at the end of the talk each demo is in one commit and each commit as a message explaining what what that's supposed to do so you can go back later and review it so I did I was lazy so I did check out the commit just to get a new module in our project which is called a new starter and basically what we are going to do now is create a custom starter from yellow service so if we look at the yellow configuration class you can see it's like nothing for now and we have a test which does not much and what we want to do is we want to say okay we want to start spring good with a certain oh-oh and I on the right branch are you okay sorry about that I'm not in the right branch why okay let's fix this one thing that you can think about that specific starter project here will mix both the auto configuration and the actual dependencies what happens in in real life when you pull the starter spring good starter you only get the dependencies and the other configuration is already built in spring boot itself but if you want to have your own store in your company you can definitely do that you can create a project have the auto configuration and it provides some dependencies and right exactly we're about right so you can express how certain library should be used in your company and the default opinions it should have on the properties configuration properties you should provide so that so that users can change that default opinion in some ways so just like all the things we you have already with boot by the end of that talk you'll know how to build the same thing for your own library and so you can use that in several projects so actually we have two branches on this project we have one which is the original talk based on 1:5 and we have a new branch now which is what you see based on spring boot to was supposed to be two O's two om 7 and yesterday when we had a look to the examples who obviously found the back always happens so we had to switch to snapshot by the way you need to remember that need to make sure that we on the snapshot change it so the main difference if you had a chance to look at the test you could have seen some infrastructure bits bits and pieces into oh there is a new utility class called application context Runner and it's really a great way to test your auto configuration so you can bootstrap the runner by basically saying these are the auto configurations that I want to enable for this test so what we want to do is we want to say if I start a spring boot up with nothing no customization nothing basically the a loader configuration will kick in what I want what I want to do in this case is I want to assert that there is one bin of a certain type which is in this case just a single bin serine also this which were not resolved because I haven't really changed my palm yet so let's do that okay so my starter what should I know what do I need to do for my starter it doesn't really rely on anything so let's use the the basic one and I need a dependency on my service it would be the library your you'd like to create another configure four and the boot starter dependency provides the basic infrastructure you'll need to write your own auto configuration and everything so there's really two way to think of it when if you want to build a starter and we'll choose the easy one but the most them I wouldn't call it the common one but once you have more code it's a good idea to separate the code from the starter so you have one module with the other configuration so that you can use that independently and you have the starter that brings the auto configuration of course and the dependencies that you think are the right ones for that use case in this particular scenario we are shipping the code and the library in one module so if you if you had that in two modules this would definitely be optional so that you don't have a transitive dependency if you if you rely on the code so you could have the auto configuration code but not the library and adding the library is actually the thing that enables your configuration okay so as you can see the contact here is Anna Sergey assert so I have those nice utility method I can invoke so now what I can do is I can actually get yellow service from the context and say oh and now I can assert this output capture is something that captures the output so this is very useful if you want to test something in your this isn't spring good test right yes that output capture so if you want to test something in your code that should write to system out and you want to see if it did a quick capture is a pretty handy rule to do that so you can test if something was printed in the console or not so again start with a test and in this case it fails as it should because there's no such a low service being right we haven't provided it so let's now work on our auto configuration so the goal of our other configuration is to provide that beam so we did we have that library and we want to configure things for for developers so they don't have to do that thing manually so for now a another configuration is just a classic configuration and the more flexibility and opinions and and and things you want to add the the more we'll see it'll be different but for now it's just a simple configuration where you declare beam and that's another configuration so the the the main difference so there is only one difference critical difference between configuration and auto configuration is the life cycle of it so remember you've seen those user configuration on the left and you know configuration on the right so we need to make sure that this auto configuration actually is being processed on on the right face so the face of the other config and we don't want to use any kind of component scanning for that right so what we want to do is that you'll be able to drop a Java file somewhere it doesn't matter what the components can how the component scan is configured if it's configured at all so if the user has decided to disable components can you should still be able to process the other configuration so the way it works is you need to register your auto configuration in file called spring factories in the meta in the directory so I'm doing this now and to make sure you remember to which key you need to register it you just use the fully qualified name of unable to configuration for that so basically what I'm saying is this this this jar file defines a set of photo configuration and right now we only have one so let's let's register it like this okay so this is this is what it takes you write regular configuration you register it in the spring factories file and you get another configuration so let's let's run our test again there you go good so we have our bean we have it wasn't really hard to configure right but this is sample but we we provided something for the user and it's just a configuring configuration class that other developers don't have to don't have to write anymore but we probably need something something more clever in that sense because I in spring boot when you have an opinion we don't like send you throw you throw beans at you and you you have a chance to change things and for now it's just not the case so it's very basic for now but we will we will improve it so let's replace the yellow service by the starter that's what you that's what you do when you use spring good right you use spring good start or something and then you get sensible default and that's let's run the app alright so if you've noticed our system prefix has disappeared we're back with the default behavior of hello world remember that we expressed an opinion here that the prefix would be howdy so something is wrong and we got what we are going to see how we can fix that so with that to summarize that so with our basic configuration our configuration what you need to have for an auto configuration is just a configuration class that won't be scan shouldn't be scanned instead we are declaring it in a spring that factories file and this is how it will be discovered by by spring boots and this is how the configuration will be processed and again this behavior has nothing to do with spring blue the spring that factories and facility it's something that exists in Spring Framework for plenty of other use cases so we are just reusing something that already exists so if you take that part and you look at the actual operation for now that auto configuration is very simple it's just a configuration class that you could have written your it's really super simple we're just declaring a beam and this is will be this will be provided in the other configuration phase that second part so this is why when we are overriding your opinion because in the user phase you are providing your own and then in the other configuration phase we are overriding that and we are providing that one so this is not what we want but this is how it works for now we better and improve that right so let's fix it let's first create a test what we want to do is to simulate that the user has provided its own version of it so let's create a user configuration in our test so we want to simulate what a user would do using your infrastructure basically so let's just so you know the application context runner that we have previously in spring good one for we were testing things in a more manual way I'd say so this is more involved we would set up the context ourselves and we would register the configurations in right order and this is something you came up with I think too because it was easy to mix things up in our own code base and to test things the wrong way at least this way we can see this is the configuration classes that are dedicated for the other configuration those are the ones that should be provided by developers and we are testing the several scenarios so it's just an easier way to testings but behind that is just regular context setup with Spring Framework not nothing nothing fancy so what we want to do is we want to say I want to start a spring boot app or mini mini supreme good app with the auto configuration and I want to apply that user config so I want to simulate that the user has defined that in its configuration so to do that we we have explicit support in the contacts further we could say with user configuration with the class and that's going to do the right thing so if we start this test you notice that so in that case we have the other configuration the configuration provided by the user and we want to make sure that the opinion provided by the developer is still there and for now it's not because we're providing our own component no matter what right so the outcome of the test now is oh I have two bins I have my arrow service which is this one and I have other service which is this one so what we want to do now is we want to express in our auto configuration that is a bin of that type already exists we shouldn't do anything and that's where the conditions comes into play so I could say conditional on missing being on this type and it will default to the return type of the method so I could say also conditional on missing being console hello service if I want to narrow it down for whatever reason right but that's not what I want to do so that's one and two we will also want to say if the LOC service library is not here there is no reason for us to kick in so don't even don't even try to do anything if a low service is not there so for that we can add a conditional class on one one one class that's supposed to be in that library so what what that will do concretely is it will check if whether or not that class is on the class path and if it's not it will simply discount the OL content of the config and conditions are not we're not written by by spring boot the basic conditions report is written in Spring Framework has a spring firm ik four and the actual profile when you activate a profile in your spring application this is being supported by that same mechanism so looking if that profile is enabled then I'm in abling that configuration or not in enabling that one and in spring boot were shaping a few more conditions that are quite local to spring boot because there are more opinions and more assumptions in spring that we can have so we provide richer conditions that you can reuse in your in your Auto configurations right so let's start the app with this change where we finally respect what the user has decided and we are back in business right but we start with still not using the the auto configuration in our app which is a shame because it's so complex to configure the console service I would like not to do that myself right I want you to configuration to do that for me so let's remove this and of course then we are back with the default so our custom prefix is gone okay so this is the next step this is the the the next time that let's say that we want to show you is once you have an auto configuration that's being defined how do you provide users with customization choices or can you give give them options so that they can tell you oh yeah I'm happy with the auto configuration the way you do things but I don't want the Tomcat on port 8080 I want Tomcat on pot 7017 and because you have this opinion it's no reason that you have to configure them cut yourself you should only be able to say 70 70 please instead of 80 80 and the way to do that as you know as a spring good user is to define a property so now we are going to show you how you can define properties and now you can use that within your own auto configuration can we show the auto configuration report maybe or later maybe we can do that because it can be sometimes super confusing you don't know why this Auto configuration was processed or not and the auto configuration report you can you can trigger that using many ways - - debug on the command line or an environment variable in many ways and when you start your application you get a nice report with all the other configuration that were processed why they were activated or not which condition matched or didn't match this is really super useful if you thought something would happen or happen this is what you should look at and the some you know the most obvious one if if you're part of the Eurasian doesn't show up here it's probably because you forgot the spring that factory-style or something like this so it this is a very good step to if you didn't write tests it's a very good test test to see what happens so if sts also has a dedicated factor that I don't know about NetBeans but if you use an IDE that doesn't have explicit support for it the deal is to start your app with something like debugging so if you if you pass a system property debug or if you pass it like this then that will enable the debug mode and the debug mode will print out the auto configuration report at the end so if I put back if I put back my my customization so I put back the my bean definition and I restart the app you will see that the auto configuration will back off because there is already a bean so we can see that it matches because the library is present so we are going to go to consider this Auto configuration but this this one and you see the the name of the method there this one didn't match because there is a bin of that type already so you can actually analyze what what happened you can also see that from the web if you if you are building a web application there is an actuator endpoint that you can invoke just recede or something but it's more convenient when you when you work in the idea to use this so to summarize our Auto configuration is processed after the user configuration and it can provide more or even overwrite things but the goal is to be more lenient and to let either your opinions to in your application and not overwrite things when you didn't want to but the next step is for now it's just an all-or-nothing kind of deal and you probably want to just tweak the one thing like Stefan said instead of writing everything yourself so let's let's update our first test let's assume that now the prefix and the suffix is configurable we can provide a we can configure that via application properties if you wanted to and you want to simulate the fact that the user somewhere doesn't matter where but somewhere has defined one key so let's say again there's dedicated support for that in in the contacts runner so I could say something like I don't know test and if I do that this change right this is whatever I want to do and that's obviously going to fail since we haven't implemented anything so our world does not contain this word so let's implement that so we want to expose to properties hello prefix loc fix and we want to use that within our auto configuration and those properties they can be provided by the developers but in the application of properties file as an environment variable all the different ways to provide configuration properties but here in the testing environment we have a single way of defining them so to to define that they're the best option you have with spring boot is to define a type and that type defines the properties that you want to expose and you need to give it a perfect so you need to tell pls bind from a certain area of the configuration to do that you add configuration properties on the object and this will basically expose to properties hello dot prefix and hello that suffix so configure the properties is just about saying this is a properties class and this is the namespace but that's it it doesn't it doesn't declare the properties class anywhere it doesn't it's not picked up for now so this is still a simple photo but what we can do is we can enable the processing of that class conditionally so if that auto configuration can taken so if the hello service library is present if the condition defined here are matches basically then please create a bin for me with the arrow properties class and once I have that while it's a beam so I can inject it as usual and I can I can find you in my Auto configuration so I can say rather than going with with hard-coded value please use those those customizations so we're doing that as well in Springwood so you know that we're not binding all the possible configuration properties that we support if you don't have RabbitMQ for example we won't do the work for all the rabbitmq properties right so this is something that saves time and this is always something it is also something that's saved from complexity you know that it just belongs there and it shouldn't be used anywhere right so this is our auto configuration now there is a bit more to it so we basically careful not to kick in if the library is present we careful not to create the service if you already provided one and we look in the environment automatically in case you've customized it so the next step is to basically use that within our app and simply to use here a lot of prefix howdy and run the app and we're back with back in business now with what we had initially except that the only customization that we've made is this okay the other configuration takes care of the rest there's still one problem though as the ID is complaining that this property does not exist right so if I type hello ello here I don't have any auto completion you've used to that if you do that with server for example you need to do that with server you know server dot pause for instance then you can see all the options you have to configure the embedded container so it would be nice for your own auto configuration if you could benefit from that so we can show you how to do this quickly [Music] you've noticed also maybe you know a banner here that complains the Springwood configurational tration processor wasn't found and the reason why it's complaining is because that component is responsible for generating a metadata file about your configuration properties and that metadata file is used by third party clients so let me add the dependency here and we don't need we only need that locally so there is no reason to just for compilation it's not useful at one time and let's go back here and it's not yellow anymore and I can see the suffix as well and a default value I could go further as we do if you've looked at the springboard code base you've probably know you've probably noticed that on those classes we had we had Java duckenfield that's because that that documentation is used for documenting the keys anything like that very clever and just recompiling will create a metadata file inside the jar and that'll be picked up by by the IDS so it's supported in STS NetBeans IntelliJ right many others so in the end that processor is basically creating this file nothing fancy so it's basically detecting the properties and just storing that metadata and IDs read that simply to give you automatic intentions about what you type so what that means also is if you don't if you don't want to use that component you want to write at yourself or whatever reason for kids that you manage yourself that's perfectly fine just write that and the ID will pick that up okay so to summarize with our configuration class we went from a regular configuration class that always does the same thing it's just a copy and paste of what you you'd have written in your own application but then we added a few twists the first one was the condition to only be triggered when the library is actually there and the other one is to back off when the developer provides an opinion so those conditions are super useful and that's where all the flexibility comes from in spring boots so you we saw conditional missing being so process this dismiss current class or this method when the there's no being of that type conditional in class do this only if there's that class on the class path but there are many others so conditional on being one missing class so just the opposites conditional in property so if you've got a property present defined by the developer with a certain value other more complex conditions so is it a web application of which type we've got a servlet and reactive now is it not a web application on resource so do you have a resource present on the class path sorry for that you can imagine that you have like some conventions in your company right you have a fire at a specific location and when that fire in that location is present you want to do something because that's some company's default in your development environment well you could write an another configuration that detects that and does something about it there is own single candidate so if you provide just one bin of one type and not several conditional Java were not using that a lot and yeah well Java changes so much no condition what junior conditional Java 3240 so we have that right now plus jndi in case you want to check things out in JJ I and Express expression which is about Alex expressions don't do that usually when we see developers using that one 99% of the time you can do that in a simpler way with conditional property often and very often as well if it's more complex than that either you have a crazy crazy long expression or it deserves its own condition something you can definitely implement yourself and we will show you how to do that exactly so please don't do that and so the the whole deal behind enable our configuration is that when you have that annotation in your application it's it's asking for those spring factories file to be processed when we look at those we see all the other configurations that are present and when we have those other configuration we look at each so if it's just a configuration class then we process it we do everything in it if there is a conditional on something on that class for Bravo for example and if that condition does not match we don't do anything we don't we don't read we don't process that our configuration if everything checks out just like Charlie then we process that class or a computer in class and in case of Delta the first condition that doesn't match we don't even care about the others we won't we won't process the other conditions so we we are as fast as we can for about conditions and certain of those conditions actually apply without even loading the class itself so you've seen for instance conditional on class hello service dot class and you may wonder ok if I'm writing ello service dot class in the code and ello service is not on the class pass on autos it work and the reason why it works is because that certain conditions are actually processed by reading the by code so we use ASM to write the bytecode of the class we extract those tokens from the from the bytecode and we apply the condition and if the condition doesn't doesn't match we don't even know the class itself was one for yes in today we're doing even something even better so without even reading the file so before we were reading the class loading the class and but we were reading the first bytecode instructions and now we're at come at computation time we are writing some kind of index where we express that condition in an index and so this is even even faster so we just look at this and we see all those conditional in classes and conditional class conditions and we are just executing those at that point so it's even faster so we have two configurations so yeah two of those of the four matched if you look at Chari for example let's say inside that class you also have another other methods and conditions and just like the top-level annotations we look at the conditions execute those see the match or not if they match then we execute the beam method and we have a new beam in our context if not then we don't do anything so we told you that we were executing one condition after the other and we told you that and you can see that some are quite easy conditional in class it's just looking do I have that class in my class path but others like conditional mean it's much more complex because you have to look at if is there a beam like this in my context but since we since it depends on when you do that so if you do that at a certain point in time maybe someone later will create that beam and you'll get a condition negative but actually it was positive for some other reasons so order is everything here and if you look at those single candidate being and missing beam we are executing those at a separate phase so all the others there are executed quite early and on the other three we are executing a bit later when the others had a chance to to contribute things to the context and that's why it's very important that you have user configuration on one side and not a configuration on the others right because if we check oh did the user providing provided a bin of type a we need to make sure that everything on the user side has been processed and we actually know what you've got what you've defined before actually running those conditions and as you'll see either you could also have and we have that in Springwood you can also have such conditions between other configurations or two configurations competing with each other so it's for that case it's very important that they are ordered properly and we will show you how to do that yeah definitely and so that's a the two-phase thing but as well if you look at those conditions some of them are really cheap and some others are more complex they require more work and if you've got several of them on a single class for example it'll be a bit silly to check for the very expensive ones first if the very simple one doesn't doesn't match right so that's what we do there's a specific order that we use to to process the the conditions and this is how you can speed up the processing of your other configurations and actually that's why in some cases and very often adding more conditions does not equal being slower because if you add the cheap ones then chances are you'll be just faster yeah so advanced tips if you write your own condition try to find a sensitive sensitive order so if your condition is a bit expensive try to put it below the chain so give it a high order on the contrary if the condition is very fast to check just put it a lower order okay so let's say we want to write our own condition not nothing none of those match is what we would like to do so let's write our own condition so we can have something more flexible in our application for the first unit already yeah about the break yeah sure sugar on your brain whatever if you're still alive and we see you in 20 minutes minutes thank you awesome so we had plenty of questions that's amazing thank you very much I hope we have more at the end the good news also is that we had the some I don't know you because we haven't adjusted actually but on my side I had like a couple of questions so even more than that that we are actually going to address hopefully now so that's the good news so we were at conditions and I was telling you about what I'm telling you about some important things to know about conditions so let's build our own conditions right so that you see it very easy it's not something that you have to do every time it's it's more of an advanced use case but we want to show you what what that means in in in practice right so we want to do something a bit silly if I remember the name of the thing a real template yes what's the name of that template for that again I think what we'd like is to add a specific condition on our configuration to restrict the usage of our library to generally accept certain critic seas or certain rules on our prefix and suffix values and we'd like to enforce that as a condition level to to have a better experience right so it's a bit silly because not really representative of what what you would do but at least you you can relate to that for your own use case so there is two things one I'm going to do is if the ellow the traffic's property is not set let's not create the beam because we must have a prefix so first let me remove the default one okay no default anymore here you can see that the the context gives you nice assert utility so here that and the second thing which is even even a bit more funny is let's say that if the context is the prefix re is set but doesn't start with another case then the service is not defined either so that's food stand up to write whatever for whatever reason okay so let's run that and those two tests will fail because obviously we we are configuring the service we haven't done anything yet so we want to define that condition to define a condition you you create a class that extends from spring good condition and you'll get it context and you'll get the the metadata of where the condition has been defined we'll come back to that in a minute so you can basically now write any logic you want based on the current status of the context right so I'm saying give me the environment do we have a loaded prefix property okay so do we have that so let's take the first character is the first character in uppercase it's not an uppercase then I'm actually saying that the condition doesn't match here in this case it is a perky sorry in this case it isn't so you can write can you can write a detail as why didn't match and if you remember the other configuration we call that we've shown you you get a chance now to tell your team members okay I didn't do that because of this okay so we provide that infrastructure so that can be displayed when we show the or configuration report you have all those nice messages so using that infrastructure gives you the same the same level of support as the Springwood ones it's a bit what we've shown you with the keys where you add an annotation processor and then you can have your custom keys in Indi ID by the way this is by no means this is another configuration specific concept right so if you build if you build the spring boot up and you want to expose some configuration items for your app regardless of the other configuration you do the exact same thing and it will work notice also that we have a nice DSL to come post under messages so now I want to apply this condition to my auto-configuration so how do I do that I'm just adding the standard Spring Framework conditional where you can specify a class and let's run that doing that was easy what the template did everything right yes so you still don't have this nice conditional on something right what what what does it need what do you need to make that happen it's simply composition so let's create a conditional on Valley hello prefix or whatever use case you are currently implementing so this is this is a new notation so yeah remember if you use an annotation you still have all those crazy Mita thing to add you always forgot them so no matter how many yes from somewhere else if you don't do that it won't work nothing to do with spring good by the way for once then the only thing you have to do really is to move this to your condition right so if you look if you look at a standard condition you'll notice this pattern of saying this this annotation basically requires this condition to kick in and the advantage of doing so is that you can now make the implementation package private so you don't have to expose that anymore so let's replace that with our annotation conditioner prefix and run the test again it's really moving that that definition somewhere else okay so let's go back to the app I'm going to tune the condition a bit more so what I want to say is want to make sure that the exception message is as precise as possible so for condition can actually take the class of an annotation and that will be used to derive the the message in in the kinetic report all right actually I was looking at something and I didn't look well don't Stefan yes so let's remove the let's remove the prefix so that should not create the beam right that should not create the beam in practice you still have to customize Oh wonderful forgot to remove that okay so since we didn't provide that condition that that property our condition should fail and we have a nice message saying that we didn't provide that thing okay so it's a very effective way so not only yeah we actually showcasing two things at the same time not only it will show up in the other configuration reports but if the application failed to start because it required the beam and that beam will not wasn't present then we have a separate component called the failure analyzer we're going to talk to you about that later it actually inspects the other configuration reports for matching pins and it gives you this nice error message so creating a good good message is actually very useful so again if I'm putting a value with the lowercase the application will fail as well and you get this whatever the business project you have in your condition well technically if you use the infrastructure that we provide you'll get the same native spring boot support that you'll get with all the other other configurations that we provide so one thing that we often find is that it's easy to fall into some traps when you're writing your own conditions and on other configurations and we'll list a few of those to really make sure that everything's clear so let's take a few classes our configuration classes let's say you write another configuration that creates a data access being if taking a single daily JDBC template and then another one that just creates that and then another one that takes a single data source and creates a JDBC template you can see that there's a relationship between between those three the thing is if they don't run in the right order then you won't get the same thing that you'd expect so this is an ordering problem that can be quite a big problem especially since if we don't enforce that imagine starting your Bui application and sometimes you get the right thing sometimes you don't so we want to enforce that and make sure that it's triggering in the right order so if you take those three other configurations there's a way to to tell to declare that order with the add photo configuration Auto configure after annotation so you can say you should definitely process that Auto configuration after JDBC you should Auto configure that one before the other one etc so once you have declared that order and those other configurations are processed in the right order and you can expect what should happen which is this one creates a data source that data source is used in the JDBC one which creates internally this template which is used there and creates the data access so if you want that you need to order things otherwise you won't get the expected result so you're not very familiar with that as a spring user because you expect the application context to do everything for you right which is a nightmare for us I'm not even kidding it's really a nightmare including dealing with cycles and whatnot but in this case it's very different right we process a condition to say does that bean exist do I have only a bin of that type one bin of that type and in order to make sure it will will always be consistent with the current auto configuration that r20 defined we need to make sure that that that condition runs at the right time and we can't use the application context to figure those links because it doesn't work the same way so it's very important that you order your tow configuration cool then another trap that's easy to fall into is the condition alone class not not said that had the right at the right place so let's say we have this Auto confusion our own configuration class trying to configure Jesus as a jsonparser and you have the conditional on class annotation at the beam method at level if you do that then when the occupation is processed then we see oh that that conclusion class has no conditions so let's go let's load that configuration class and then loading that class will load will read the methods and when you read the method you have to read the types and here will the JVM will try to read the JSON type it won't be there it'll blow up so that condition their conditional class is not at the right at the right place because that type is not known at that level so like we said before if you want to make sure to not fall into that trap you should move the conditional in class at that level and you get two things one it's working and - and - it's faster because we won't even load that class at all we'll just look at look at our index and we'll do that on computer compilation time and it'll be super fast one thing just to remind you we've got two phases one about looking at the user configuration and the other one a lot of configurations so if you look at this and this is a application configuration so something that you have in the user and your own application so if you try right lifting on the left yeah so this is processed and during the first phase and if you try to have some conditions like condition and condition on class things like this should work right it's a condition so we have basic condition but for some specific conditions the ones we highlighted before it definitely it won't work at all I mean much like you expect there's a chance it will work but you you can't be sure so because at that point if you if you if you want to check if there's a custom bin instance somewhere at that points during that first phase there there may not be but if there should be one provided by auto-configuration at that point those aren't being processed we we don't even know about those so it's it's too early we can't know about this at that point so we're doing that you won't really be respecting the opinions of the application you'll just do something that's not expected so don't do that don't use that condition those conditions in user configurations right so let's go ahead and customize the app a bit more and let's build something that's not another configuration but something that allows you to tune how the audio environment is processed so um I have this file somewhere on my machine hello is that no way okay and it's in your user yeah of course I need to wake up you know so there okay I have on my own directory in the dot hello / Settings directory I have a lo perfect at hi right so now let's assume for a second that you're building an app and you you have rules within the team and you want to share some well you want to be able to define some local settings but you don't want to put that in the git repo you want to have that in your in your home and home directory for instance so how can you ask spring boot when it starts the app to actually look at that location and update the environment with those information so things about what what you you'll be able to do quite convenient so um let's implement that do I have that already or not I always forget I do they're convenient to type when you have nothing to type right so the the oak point is environment pass processor it's a way for you to tell the spring boot that you want to do something extra with the environment before starting yep so this is very easy I'm getting the user own directory for location which is not a low settings location if there is a file then I'm loading the file and I'm adding the file in the list of property sources of the environment so we will show that in a minute so now I want I want that thing to be invoked regardless right so I've put it in the app but you could have put that in the Auto configuration or you could you could have put that in some shared library that your company is using whatever the use cases so I want to make sure that this is invoked regardless of user configuration and the way to do this well it will look familiar because we've done that already this afternoon is to create a spring factories file and define the fully qualified name of our implementation so I told you the key for Auto configuration is enabled configuration and the key for an environment post processor is environment was necessary very very very hard then fully qualified name and same thing this is the way to declare it and once we have that we know about that environment pass processor and it'll be invoked a startup time there we go so now I have hi world okay so let's quickly turn on this app into a web app just to show you one more feature and let's make sure that our management yeah but it's it's brooding the snapshot from the internet you know so maybe I should switch to you can do this one thing that we use the environment pass was prosperous cross processor for I believe is for dev tools right yes so when you have dev tools on your class path and you're running up the application locally you probably notice that there are a few things that we customize for you for example the we set the cache HTTP cache for resources to zero we make sure that the templating engines don't cache things so when you change the template the changes are reflected stuff like that so those are all properties and those properties are changed for you an application startup so we change the defaults in an environment pass processor so that's one of the use case for for this if you if you want to use it so now you need to switch to dancing right now I don't have anything interesting to say no okay whatever let's see there on my phone maybe ok let's try that I always do a nuclear option there we go there's a city maven process sometimes that hangs if the network is slow so dance okay what do you mean you can do it you know I'm stuck on the keyboard I can't do anything okay other something more interesting as well doesn't want to dance yeah trying to think of something dance it would work I'm telling you so I know your two beers now yeah yeah three make it three he's mad good scanning files to index okay so what we're actually trying to change here is that since spring boot tirado by default we don't expose all the actuators in points because we found that in some cases it was easy to create an application at actuator push it to production and forget that you didn't secure those endpoints and those some of those can be quite sensible with security with regards to security because you expose a lot of things so for now we're doing the same thing which is only exposed the ones that are safe and if you want to expose more you have to do just like stay funded you have to provide a configuration property saying I want to expose those or I want to expose everything with a wild-card so that's that's a new feature in Springwood to where if you require a particular key of the environment you'll get a very detailed output so in this case I can see that the value that's actually being used by amplication is high we know that it's coming from the ello local with the ello local property sauce so let's link that to actually this right and these are the property sources that could have matched so you can also see where in that file the property is being defined so line one character 14 these are the other property sources that may have match and there's an extra one here and the trick is that the order of the property sources is the order in which they will be evaluated so as soon as you find a key in one this is the one that we are going to use right so arrow locally is before application config so the value isn't howdy but the value is high okay same thing if you look at the environment if you look at the environment you'll get all the property sources with all the keys so a bunch of information as you can see and Brian mentioned dev tools you have this tools here we don't do you know you just have actuator you know but it's basically it's super useful because we had at some point we had a lot of reports with developers saying oh i'm i didn't configure it that way i don't know why where he came came from and if you look at this sometimes you can you can see that you have you had an unexpected environment variable in your environment for example QA environment and you didn't know about or there was a file that i didn't know about and what and so on so this is the best way to know what's going on with obviously the configuration report if you look at those two things you pretty much know why and how things were configured for you how much time do we have left I wonder all right till we've got 30 minutes or so really we have 30 minutes 20 20 okay make it 20 okay cool so application events I need to apologize to the person I have a meeting with now Ian made a mistake in my agenda so Springwood events when you start a Springvale application this is how things enroll so you run the application then you first have an application event which is the application storing event so you can use those events and to hook those into those and do something when at that point of the application starting process so but what's really important here also is that you understand what we do on startup and also the things that we do the order in which we do it why we do it that way that will explain for instance I had a question during the break what wasn't really that question but the person said I'm using add property sauce in my configuration and they can do it seems that it's not being applied at the right time so I hope that this will help to demystify them yeah so first you have the the storing event at that point we start initializing the logging infrastructure but it's not ready yet so you can see logs at that point and the reason why we do this is log back by default when you initialize it and you don't give it a configuration it locks a debug level by default so we don't want to do that at this point because we don't know what the login configuration will yeah so it should provide an opinion in your application properties saying I want to log things that info and that package like this and with that format of logging and if when you start your applications you get a different format and at some point it gets applied they'll be too strange so this is this is one of the reasons then you get application environment prepared prepared event and then at that point what we are doing is we are reading the configuration files we are applying the environment postprocessors so that's what we created right before and that's when the logging initialization is done and at that point things are being logged properly and that's why the environment as processor that we've just showcased previously it runs at the right time so it's invoked before the application context even starts even before the logging system completes so for instance if you want to move a log in configuration to the settings file you want to say oh on my machine i want to debug that that package in trace rather but I don't want to hard-code that in the project itself you can put that in that file and it would be taken into account and then application prepare event and the application context is refreshed so that's wearing things start really to happen we get the contexts refreshed event which is the only event that's that's Spring Framework based all the other events are spring boot specific and due to the spring boot initialization contact we first even you've probably seen it if you if you use spring framework directly so that that's an event that says beans are the beans are ready basically yeah and at that point we start the embedded servlet containers connectors but we are not making them available right away so because we want to make sure that your application is fully ready before you start serving traffic so at that point we start those connectors we don't make them available right away but since we have the port information at that point even if you said port 0 so take check one available so we have that port information available and at that point we make with we send an event which is the container initialized event and that event has information including the the actual port of your application your web server and right after you have the ready event your application is ready so even if your application is not a web application you'd still get the second one and at that point we run the command line runners so the ones we added earlier if you have something implementing compiler or application runner we do that at that point when the application I started and when your connectors are exposed and ready done failure analyzer we we've seen a few which you indeed so if in your analyzer it's pretty useful the goal of this feature is to provide a nice message that describes what's the problem and what you should do instead of just throwing stack traces at you so we have a few thinner analyzer and a figure in a few exceptions that go with them so a few exceptions that we deal with with failure analyzers for example for example important use if you're trying to start a web application and the poor is already used by something previously it was a stack trace and you get a better better understanding what's going on so all of those are kind of exceptions that we deal with right now and an example of that is that let's say you start your application and you get this and it will end adventure done so you get this very useful I'm sure which is you counted exactly 340 lines and you want to burn your computer at that point and with a filmer analyzer what you get is a nice not a stack trace anymore but you get a nice fader message that shows you that there's a cycle in your application because that was the exception that you couldn't read so there's a bean cycle in your application and it shows you in a nice descriptive way what's going on your application and probably where the cycle is and how probably how you should fix it yeah and the back story is that this this this stack trace we actually revert to a version of spring boot where that blood was present just to reproduce a stock Reza and we were so angry and so mad and it took so much time to actually find this cycle that we decided to implement this as a result so okay that you do why it's your custom one custom one we'll have time for that so let's say you have a complex failure in your application something in your auto configuration maybe or something or that your properties don't match about something and you instead of throwing statuaries at your at your developers you'd like to provide a nice descriptive message that something's missing something's not configured properly or maybe something is not available some resource is not available at that time there are many things that you can take care of right so here let's make it to theme okay let me get tail first it should same with the right exception I guess it didn't you have the file still on disk that is that it checking yeah the local file is that the one the local file in you're done hello oh good point yeah wonderful you get a cookie so let me override that here so let's say here instead of the previous message we had which is here the exception we'd like to take that exception which is invalid hello prefix exception and take that and turn that into a nice descriptive message so the idea here is whatever whatever exception it is that's focused what you're doing you know exactly what it is right and you want to tell something more to your users it's a fatter exception the application doesn't start because of it and of course they can read this well further need to scroll in the right way then they need to then they need to read this and you need to provide that information in the exception itself and maybe you want to have something more technical in the exception then what you actually display to the user don't you watch you update your ID right now no I guess it's fine dude ok so let's create a failure analyzer so invalid Ella perfect so invalid Java class invalid no prefix failure analyzer there we go and I want to there is there is a base class that gives us a nice feature so abstract failure analyzer you just give it the the name of the except factory bean and then oh you know I need to go back to God I think none of those famous classes that everybody loves you want proxy factory there you go sorry so invalid hello perfect exception there you go so what that that what that does it's actually when there is an exception that caused the application to fail it will it will look in the nested causes if it finds an application with that type and if it does it will call you with the exception that that occurred the base one and the one that it found and there you have a chance to massage the exception and check about things so that's what we do for the nose between definition exception we look into the other configuration report if by any chance there is a bin of that time that could have been defined so it's very important two things one is you need a dedicated type for the use case so you need an exception of your own and two you need to give some information in the exception itself because then you're going to to get it back to provide a good message to the user once we have that the only thing you need to return this failure analyzer federalizes sorry it's very easy to it's very easy to unit test because all you have to do is basically invoke that with an exception and make sure that you get the proper message and the failure analysis is three things it's a description an action and the actual exception and the reason why we pass the actual exception is because when you run in debug mode we will anyway we when we load the exception because you may want that detail in this case so a nice descriptive message that's what I'm doing right what you should do is fix the prefix and the provide that value that's the important part otherwise it's just another exception you don't really provide context yes and a failure so I need to make sure that this Lu so this ello invalid Ella perfect failure analyzer runs regardless of the user configuration right I don't want them to say hey by the way I know here you have this nice feature so I will enable it so I can actually see it you want that to be enabled by default so what do you do same thing yes spring factory is well done yeah and what's the key of the thing in the spring factories I don't know fully qualified name of that thing yes exactly and the value is the fully qualified name of what you provide oh there we go okay so we've declared it in the spring the factories and doing that we can restart our application and now we have description action in here no stacktrace but still it's like in other like all the other features it started as a feature in spring boots and we provided that infrastructure so you can reuse it in your own auto configuration and your own infrastructure and you still get the same experience as spring boots so we're not hiding anything in our infrastructure and quite the opposite where we want you to use it in your own or configurations exactly so how much time do we have - who could used six minutes there you go okay so we want to start with some soft landing so that you brain can rest for a bit so those are common questions that we had all over the place get our issues but not so about started performance so we often get the question my app takes a lot of times we start what's going on I think classpath scanning is slow and that's probably the culprit and someone thought that he tried to fix this situation because we get that feedback a lot so what that person did was we'll tell you about that later but we did some a few experiments and let's say you have a spring good application with 200 beans so 200 bean definitions for example so I don't remember exactly I think it's five thousand so you have five thousand classes so you have a package and sub packages and all that contains five thousand classes and amongst those five thousand classes you have 200 of them that are flagged with add component for instance so there are 200 of them that are candidates and 4800 that are just noise just regular classes that we shouldn't touch and that application when you started it takes 6.5 seconds to start so if you time the actual class path scanning of the of those classes how long do you think it takes okay so question 1.5 seconds when one siphon 51.5 who says 1.5 ohm out of 600 K remember ya vibrate unit has five thousand classes and 200 beams okay one second one everybody is afraid not to raise their hand 500 milliseconds okay usually that's almost everyone okay and 103 seconds very good very good ladies often yeah and there you go so often we think oh this is class pass scanning this this must take for ages and takes a lot of a lot of resources but it's not really the case but still a certain someone created a spring context indexer in spring framework to to improve that process maybe you can talk about this or you mean the other thing that was useless you mean so it's the same mechanism right the same mechanic we've seen we've already told you about at compile time detecting the conditions writing that in the index I've basically built the same thing for components so you add that to a module it will detect all the components right that to a file and when the application starts up where you read the file and we look at the components and we don't stand them at runtime basically and that creates the meta in spring components turns out that if you don't have if you have less that's 50,000 classes it doesn't make a single difference so it was pretty much useless yeah but then you have another problem and it's not always exactly good so yeah if you look that far basically the content of the file you're the fully qualified name of the of the class and all the stereotype that this class has and then we have a reverse index and then you can you can say okay give me all the classes that are mapped with oat Spring Framework stereotype component you'll get that and that's the outcome but if you have a lot a lot classes then you can use that one and you can definitely make a difference but then you have a different problem yeah yours that joke again sorry but it's partly solved or hidden okay then it's not that that thing so it still takes a lot of time to start I'm wondering what it is and we had someone one day as telling us that they had a strange behavior on Mac OS and that when they started spring do that it takes 13 seconds but when they run iTunes and then they retry it takes one or two seconds it's an extra report it's not a joke now it's an actual report yeah so questions again do you think that I change this way nobody nobody says that right or the spring team created a new annotation another one start faster with iTunes and it's hidden in our code base it's bacon spring good application somewhere yeah marinate it and or there's a local host DNS resolution thing with Mac OS Sierra obviously that was that one and the thing is we were not making fun of that person because often when you think you have a start-up time problem it's easy to think oh this is class path oh this is something and when you actually try to look at it and try to think what it is it's not always what you think it is so if you have a problem and we we are really often very often looking at start of time we have we are running tests for each release of spring boot comparing the time between releases and we make sure that when we see a difference we try to track down the difference and make that thing as optimized as we can but if you see a problem don't state to try to pinpoint what it is try to come up with a sample that we can take a look at and then from then we can maybe find an issue in spring boot or point you to the culprit other things that you can think of we've seen many of those it can be some kind of network configuration because you're trying to do something with the network at startup and it's taking a lot of time antivirus if you're on you're developing a developer laptop sometimes the inner viruses if you don't ignore your workspace or something like it can take a lot of time because you have a lot of files lack of entropy but that one has been fixed in spring boot one for ya with Tomcat previously if you were running into a container yes that was if you're running into a container that lacks entropy then the startup time could be longer but we fixed that in spring good one for so if you see people saying you should use slash dev slash you run something like this instead you have to do that Haley you have to do that anymore that was a specific problem of course there is a static code initialization or one neat trick that you can try is to use the JVM no verify flag that's the Yolo mode yeah so this will actually skip some very verifications on classes so this is not very you don't really need that unless you do JDK civilization or deserialization stuff like this but on a developer a laptop or a workstation you can definitely add that flag you know and it will make a difference for startup time and if you're interested in that topic please take a look at Dave sires repository about this there's a whole startup benchmark with many tests many cases and we're taking all those measures to see if the start times improves or not it's easier also to run those benchmarks on your own machine so you can quickly spot if something is wrong locally or some set up that's wrong okay and that was it you
Info
Channel: SpringDeveloper
Views: 41,933
Rating: undefined out of 5
Keywords: Web Development (Interest), spring, pivotal, Web Application (Industry) Web Application Framework (Software Genre), Java (Programming Language), Spring Framework, Software Developer (Project Role), Java (Software), Weblogic, IBM WebSphere Application Server (Software), IBM WebSphere (Software), WildFly (Software), JBoss (Venture Funded Company), cloud foundry, spring boot, spring cloud, microservice, microservices, microservice architecture, tomcat, jetty, undertow, liberty
Id: jDchAEHIht0
Channel Id: undefined
Length: 90min 37sec (5437 seconds)
Published: Thu Dec 14 2017
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.