[MUSIC] When you create controllers, they're magically instantiated by Spring. It automatically discovers the controllers as we've seen. Looks at all of the annotations on those controllers and then figures out what requests to map to the controller. But often our controllers are going to depend upon a bunch of other objects that we define. And we would probably not necessarily like to define exactly how we instantiate and create our controller completely in the controller itself. We'd like to be able to configure it different ways, depending on the situations in, which it is being used. So for example, let's say we have a controller, @controller, and we're going to call this public class and we'll make this our video service. [BLANK_AUDIO] We now have a simple Spring controller, and let's say that we would like to have different storage options for our videos. So, somewhere else, we go and define an interface called storage system. So, we have a member variable, called StorageSystem. And we'll call this storage. So we now have a member variable, that's of type StorageSystem. And StorageSystem is a interface that we've defined somewhere else. So maybe in our storage system we have different implementations. We might have, for example, a implementation that stores things in Amazon S3. [SOUND] And we call that AmazonS3Storage. Or maybe we have one that stores things locally. And we'll call that local storage and these will be different classes that would implement the storage system interface. So we'd like our controller, our video service controller to be able to operate on either type of storage system. Now one way we could do this is we could simply say equals and then instantiate this specific storage system that we wanted to use. So we could say storage equals AmazonS3Storage and create a new one, or storage equals new local storage, but then that's going to make it so that this video service object. Every time we want to change the type of storage system we're using for it, we're going to have to go and rewrite the code itself, recompile the application. And that's not what we'd like to do. What we'd like to do is be able to, when we start up the application in a particular configuration, we'd like to have this automatically paramaterized and injected into the controller, the appropriate storage system that we want for that particular use case. And Spring gives us a way to do this, through a process known as dependency injection. So what dependency injection is, is we can define, objects, that a particular class depends on. So, a video service depends on having a storage system object provided to it. That is the storage system is a dependency that the video service needs. And the injection part in dependency injection means that spring can automatically fill in and provide an object that implements the storage system interface, without us having to construct it. Now the way that we do this and this is going to seem like magic at first, is we go and we add a special annotation to this memory variable called at AutoWired. Whoops, dot AutoWired, and what this says is, whenever you go and instantiate a video service, Spring, you must also find a storage system object that can be automatically wired or injected into this variable. So, what Spring is going to do, is it's going to look through the configuration that's provided to it, and it's going to try to find an implementation of storage system in that configuration. And if it can find a configuration, some, in that configuration a implementation of storage system. Then it's going to automatically take and create an instance of that object or reuse an existing implementation that's already been created and inject it or automatically set the storage system, or the storage member variable, to that value. So, it automatically looks at this video service needs an implementation of storage system. It automatically finds an implementation for it that you've defined in your configuration. And then it automatically sets your member variable to the value that was defined in your configuration. And so this is really nice, because we can create a video service that depends on any number of other objects. So for example, we might have another dependent object that's you know, User Manager, that is defined in interface somewhere else. And we'll call this users. And then we can just say @AutoWired for it. [BLANK_AUDIO] And Spring, will automatically, for every single one of these dependencies that we define by adding AutoWired, it will automatically go and look through the configuration, find an appropriate object that implements the interface that we've defined here, that we depend upon. And then get that object and set our member variable to it. So it goes and automatically instantiates and configures whole hierarchies of objects, through dependency injection to build our application. And we can control how all of this done, is done by providing different configuration objects to spring. To populate the different AutoWired properties of our objects, we need a way of telling the dependency injection mechanism in Spring, how to map to these individual interfaces. Their class is expected to be in AutoWired. And the way that we do that is with a configuration object. So in Spring, we can create a class that defines the mappings between the actual concrete implementations of the different interfaces, that our controllers and other objects depend upon, and the actual specific class that we want to use for that interface. So, to do this, we can simply create, a class, we'll call this VideoConf, and we annotate it with the @Configuration annotation. [BLANK_AUDIO] And what that tells Spring and the dependency injection is that go and look at this class, VideoConf, and construct an instance of it, and look inside of it for the mappings to some of these AutoWired dependencies that we need. And then in order to fill something like the storage system, we could simply add a method, public. [BLANK_AUDIO] Storage system, and then we’ll call this method storage system. And then in the method we could simply say. Return new LocalStorage. [BLANK_AUDIO] So, in this class, in this configuration class, we've created a method that's called StorageSystem, and when you invoke it, it gives you the actual implementation, in this case, LocalStorage, that we would like to use for this auto-wired storage system dependency. And then all we need to do is add @Beam as an annotation to this method. And so what'll happen is, at runtime, Spring will go and create an instance of your VideoConf object. And then it will look for all of the methods annotated with @Beam and then it will automatically call them to get the appropriate class that you want to implement each of the interfaces defined by the return type. So, in this case, if we say, @beam StorageSystem. What that means is, is that we're going to create an instance of LocalStorage. And then everywhere in our code that we have a member variable that's of type StorageSystem that has @AutoWired, Spring is automatically going to go and take the value that it got back from this method and set the appropriate member variable with that value. So, we're completely decoupling how our objects get constructed and configured from the configurations. All we have to do is create a class that has @AutoWired on the various dependencies or other objects that it depends on. And we define those dependencies by having an interface that abstracts away the details of the different implementations like S3 storage versus local storage. And then in order to define for a particular application use case, how we map those different implementations of storage system, we create an @Configuration annotated class. And would create methods with @Beam annotation to define and create the actual implementations. Now, this may seem really complicated, and at first, it's a huge leap to sort of wrap your head around what's going on. But, once you understand how this dependency injection mechanism works, it's a really powerful part of Spring that allows you to write more modular, and reusable code. So, what's going on at runtime is when, Spring instantiates your video service, it goes and it reads, and it sees @AutoWired. It then goes and says, what type do I need? And, it looks, at the type of the member variable that's being AutoWired. And then what it does is it goes through and it looks in the configuration object and it says, is there a method that's annotated with @Beam that returns the appropriate type that I'm looking for? If yes, I need to call it and get the return value from it and use that to plug into this member variable. Now, one of the things that's really useful to know is by default in Spring, it's only going to call this method once. So it's going to call and create one instance of LocalStorage, and then every other class that is using that same storage system and has @AutoWired, they will all get a reference to exactly the same object. That's the default behavior. Now, you can change it, so that each time it sees @AutoWired, it will call this method and get a new instance of that object that should be plugged in. But by default, and usually this is what you want in many cases, you want every single place where you're using a storage system to get a reference to the same storage system. And so, very quickly you can do singleton like behavior where you have a single object that is plugged in to a whole bunch of different classes. And you don't have to figure out complicated mechanisms for passing that object around to all of the places that it's actually needed. Spring can automatically figure out what your dependencies are based on @AutoWired, go and look in your configuration object and match up the return types of the @Beam annotated methods. And then do all of the wiring to take this object that's returned, and plug it in to all the places that reference a storage system and have @AutoWired on it. So it's a very, very powerful mechanism in Spring.