dependency injection is a term i don't love because it sounds a lot more fancy than it is dependency injection is simply when you have a piece of code, which uses another piece of code and instead of using that code directly it's passed in instead when you pass something into be used we call it injection we inject the dependent code into the code that uses it while this part is quite simple, it unlocks some very powerful side effects that we're going to cover we have a business app where users can chat with their co workers, they can also send pictures and files to each other when a user sends something the file gets uploaded to our attachment service the attachment service is responsible for storing retrieving and processing all attachments we're gonna build up this whole service using dependency injection and we'll see what it enables us to do when a user sends a message with an attachment the message text gets sent to our standard chat service we want people to receive their messages almost real time so this service is all about speed the attachment on the other hand gets uploaded to our attachment service there's an endpoint in our node service attachment slash upload that the app connects to and uploads a file the attachment gets stored on the disc temporarily process in a few ways we'll talk about and then upload it to its final destination the default storage location is an s3 a part of amazon's web services it's a simple storage service that lets you put up files and pull them down we have some code here that takes the uploaded file and then uploads it to s3 unfortunately simple and elegant doesn't always like to co exist with business while us 3 is nice and straightforward and most of our clients are okay with it we have a few firms that don't want us to permanently store their data this means we actually need our service to handle multiple storage locations then depending on which company a user is from we need to put their attachments in the right place most of these picky clients just give us an sftp server to connect to, but one really wanted us to use web dev our first thought might be to simply extend our upload code with some if statements and then have the collar of the upload method pass and where to upload the file this is awkward for a few reasons first this one class has a ton of responsibility making the code pretty ugly the code for sftp is intermingled with the code from adbus and web dev even though they're pretty different there's a lot of paths the code can take and that makes the code harder to understand second using the class isn't very simple we have this one upload function which needs a bunch of info for where we're going to upload the attachment but what info it needs is very different depending on where it's going if it's aws we need the aws keys if it's sftp we need the address and private key and web dev needs a url and off key so we're kind of forced to have a bunch of these optional variables that need to be filled out in certain cases and then comments to tell you which ones to fill out this makes it pretty easy for the collar to make a mistake and finally the part of the code that actually calls upload over here needs to have all of this destination specific context to perform the upload, but really at this phase it just wants to upload the part of the code that knows best which company a user is from and can deduce where the file should go is up here at the beginning of the request, but right now we're forced to pass all of this information around let's see what happens if we use dependency injection instead let's create an interface that represents our attachment storage which contains a key upload method that does what the request handler wants to do upload an attachment then we create three different implementations of this storage interface the configuration for each is passed into their constructor there's no more optional variables that sometimes need to be set we require exactly these values and you get an error if you forget one so now once the user is authenticated and we know which company they're from we create the storage that the request handler should use instead of the configuration needing to be passed all the way to the request handler only the storage is passed to or injected into the request handler it's not aware of which storage is passed in or where the file is going it just knows that it can call upload that said this construction code is still a little too complex to put here so let's see if we can clean this up if we look at the input here it's really just this company configuration and the output is the storage which conforms to the storage interface so we can just move this out to a factory great but saving to the final storage destination is the last step of the process we have all these other stages that the upload goes through we run each upload through a virus scanner this checks the files for signatures of obvious viruses then if the files an image, we scale it down to a max width of 2500 pixels this is what we display to the user when they click on an image because it uses less bandwidth and loads faster then the file goes through a preview generation this is basically the thumbnail that pops up underneath an attachment in the chat, so the user can see what the attachment is without fully downloading it then the last step is encryption if we're storing the files on amazon s3, we pre encrypt the files before sending them up that way if there's a security breach at amazon, we can say that they're encrypted when we have to send it one of those, we were hacked by the way emails so let's see how we can make each of these requirements fit cleanly into our service for the virus scanner, we currently use a scanner called threat protect however, synergy security scanner has much better detection kpis and our plan is to switch to it, but sadly we haven't finalized the deal with synergy we're only allowed to test with it in our development environment not in production no worries we can create a shared interface for our two scanners and on an initialization, we pick one and inject that one into the request handler when we launch in development mode synergy security is initialized and in production the old threat protect scanners created our request antellar just scans the files, but doesn't know which scanner is doing it for image scaling we use the sharp library in order to inject that we simply wrap it up in an image scale or interface, the interface also contains a method, which tells us if an attachment support scaling we injected it to our upload request and only scale if the attachment supports it preview generation is the most complex given how many types of attachments there could be we have an interface that represents the different preview generators it takes the input file and then returns the preview image we have one implementation that handles document files, like word, dock slides etc one for videos which extracts the thumbnail from the video and one for images, but the image one can thankfully just reuse our image scaler we just inject the same image scaler from before into the image preview generator so we have all these preview generator classes, but we only need one at a time depending on which file type is being uploaded the upload request shouldn't need to worry about these details we'll inject a factory which takes on the burden of deciding, which preview generator to create the factory takes in the mine type of the upload and then returns the right preview generator to use so now the upload can simply just ask the factory for the preview generator and then use it and lastly we have encryption we only have one implementation of encryption we use aes, but the key is per user and comes from our key service so we inject our key service into the aes encryption and then the aes encryption into the storage factory then whenever, we get a request for a company that's configured to use aws the storage factory injects the as encryption into the new instance of as storage then the upload request gets this final constructed aws storage and simply calls upload without knowing that there's this whole chain of connected functionality and now we have our complete architect you can see that our service is configurable from this one spot, which makes it super easy to change once our deal with energy security goes through it's just these two lines to change our service want to add preview support for a new file type it just slots in like this no access to the key server when running the attachment service on your local development box no worries we can just use a fixed key when running locally injection basically just lets us pick and choose from our compatible puzzle pieces and then slot them in when we need them you'll notice that the time in which dependencies are injected varies a bit a few dependencies are resolved then injected right at startup this is often the most common scenario in dependency injection, but some dependencies that are chosen and injected when a request comes in in either case, their process is mostly the same we have some code that accomplishes something it lists the dependencies it needs and so we have filled those needs you might wonder why go through the hassle of creating interfaces and injecting things when we only have one implementation like we only have one implementation of encryption well, there's one big thing we haven't talked about if you look at our architecture here most of our components talk to each other through these interfaces which are injected in this means that each of these connection points we can control what is being used we've been using this to choose which implementation to use in our production service, but we can also make them use no implementation we can use injection to inject fake or mock implementations instead, which basically means we can slice and dice up our architecture to isolate sections of code during testing let's say we want to write a test for our aws storage class we can use a fake s3 which we run locally that pretends to be the cloud service then our test can call upload and we can verify that a file got uploaded to s3, but because of the encryption we can't actually check the content of the file and verify that it's correct and didn't get corrupted not to worry let's inject a mock encryption that basically just disables encryption when the aws storage class asks us to encrypt a file we'll just hand back a file that isn't actually encrypted now our test is able to verify fully that uploading and only uploading works because we've isolated it away from our dependencies what if we wanted a test encryption well, we could mock out the key store to return a key that we control instead of going all the way to the key service or if we wanted to integration test both our aws code and encryption code together we could do that by injecting our fake key store into the real encryption and then inject the real encryption into the aws storage a key thing here is that this is easy to do a natural side effect of having nice code is that it's easy to test without needing to hack around the code structure if you find yourself asking how can i test a private method or i need to set some internal variable in order to test that's a signal that you maybe need to pull some stuff out that you need to isolate some part of it by separating it and injecting it instead i'm gonna try something new with this video i truly think you only learned stuff by trying stuff so for those subscribe to my patreon, i'm going to start including some light experiments with videos for this one you can download the attachment service i wrote and i want you to reconfigure the service by changing the dependency injection and then you get to win some aesthetic points if you enter the results on the site。
粉丝22.3万获赞111.6万

php 的接口是一种定义规范的抽象类型,用于指定类。必须实现哪些方法?接口不包含方法的实现,只包含方法的签名 类。实现接口后,必须实现接口中定义的所有方法。以下是一个简单的接口定义视力。这个接口定义了一个 work interface, 包含一个 work 方法。所有实现该接口的类都必须实现 work。 方法。反射是 php 提供的一种能力, 他允许在运行时动态的检查和操作类方法和属性。通过反射可以获取类的名称、方法的参数列表、 属性的值等信息。以下是一个简单的使用反射获取类明的视力。依赖注入是一种设计模式,他的目的是结偶类之间的 依赖关系。通过依赖注入一个对象,可以将他所依赖的对象通过构造函数、方法、参数或属性注入到自己中,从而避免直接依赖这些对象。以下是一个简单的依赖注入视力。在这个视力中, 优斯尔麦尼这类依赖于一个沃奥格尔对象。通过将沃尔格尔对象作为构造函数的参数传入优斯尔麦尼,这实现了依赖注入。关注我,轻松带你学习面试技巧!

大家好,这个视频呢来做一个注册登录的功能,因为要实现数据的交付,所以这个实力呢,我们还要写一下后端,后端这里我们就用 php 来写,刚好可以通过这个实力给大家简单来介绍一下我们的项目,从前端的静态页面到后端的数据交互呢,具体是怎么分工还有整合的。 来看一下这个视频我们要实现的功能有哪些?首先这里看到有一个注册的页面,当然页面的布局呢,写的比较简单哈,这个不是我们这个实力的重点,我们主要学习实现整个功能的逻辑和思路。 我们可以通过这个页面呢在网站上面来注册一个账号,如果说你已经有账号了,就可以点击一下这一个去登录吧,就会跳转到这个登录的页面,当然如果说你还没有账号的话,我们就可以回去注册一个,我们先来注册一个账号,就叫小 k 师兄,邮箱这里呢随便来输一个,点注册好,这里呢就提示注册成功。然后呢给我们跳转到这个登录的页面,现在我们已经有账号了,用这个账号呢来登录一下,小 k 师兄, ok, 然后呢登录,哎,这里呢就给我们跳转到,你好,小 k 师兄,欢迎来到个人中心,当然我们这里呢是没有其他的数据和内容的,主要就实现下这一个注册登录的功能,我们可以点击一下这个 back, 然后呢就返回这个登录的界面, 再点击一下这一个注册,我们再注册一个账号,这次呢注册一个结轮 注册, ok, 现在我们用杰伦这个账号来登录一下,点登录,哎,现在呢,来到的这个个人中心呢,就是杰伦这个账号的,我们现在呢就可以简单的来实现,根据不同的用户请求呢来返回数据了。 刚才是小 k 师兄进行这个登陆的,所以刚才的个人中心呢,是小 k 师兄的,现在呢是杰伦这个账号登陆的,我们现在返回的呢,就是杰伦这个账号的这一个个人中心, 还有一个完整的注册登录功能,表单的验证呢,是必不可少的,并且前端和后端都需要进行验证, 我们这个实力呢就简单一点,前端的验证呢就用 h 五自带的一些表单验证规则,后端呢我们就用 php 来实现,比方我们这里返回这一个登录的页面,如果我们现在没有输入内容,直接点登录,哎,他会提示 请填写此字段,因为我们对这个字段呢做了限制,必须要输入内容,否则他是提交不过去的。这里我们是前端直接就进行验证了,假如现在我随便输入一个没有注册的一个用户名啊,随便输入的再点登录呢, 其实前端这一块他已经过来了,但是呢,这个时候后端他还要对他进行验证,他查找了数据库,哎,这个用户他找不到,对吧?他就会返回一个用户,不存在,再给他跳回到这一个登录的界面。如果我们现在输入一个注册过的账号,比方说杰伦,但是密码呢,我是随便输入的,这个时候点登录呢, 后段的验证他还是不通过的,他给我们提示一个密码输入有误,只有当我们这个用户经过注册并且登录的时候呢,我们这个用户名和密码都给他输入正确这个受点登录呢,才会进入到我们这个个人中心。好,我们就来学习一下这个实力 呢是怎么完成的,这个实力因为要用到后端 php, 所以呢必须要在服务器的环境下面呢来进行开发,我这里是已经搭建好这个环境的了,就在这一个三 w 这个目录下面呢,它就相当于我们这个服务器的一个跟目录。 然后呢我们这个实力这一个小项目呢,就会放在这一个阿姨楼顶这个文件夹里面哈,如果大家没有这一个环境的话,你对着我的代码来敲是敲不出效果的,最多只可以把静态的这些前端的页面给它敲出来,后端的数据呢是跑不起来的哈, 在这个项目的文件夹里面,我提前准备了这么几个页面哈,这一个 indestine html 呢,就是这一个入口文件,其实呢就是这个登录的界面,这里我提前写了一个封表单,封表单里面呢有两个字段,有一个用户名和一个密码的字段,下面这里呢就是一个提交的一个按钮, 在下面呢一个超链接哈,就很简单就这些内容。然后呢样式上面呢,我先准备了波底的一些基本的样式,其他重要的样式呢,我们重新来写,来看一下现在长什么样子。 要访问那个入口文件哈,因为我们现在在这个服务性环境下面的,所以呢就通过这个 logo host 下面这一个 i e log in 这个文件夹下面这个 indestine html 呢就进入我们这一个登录界面了,现在这个表单呢,没有样式,我们给他来写一下。先来控制一下这个风表单哈,给他一个 must with 四百像素,高度呢三百像素。再给他一个背景颜色啊 gb, 再给他加个边框一个像素的,实线的这个颜色,加点 mark 哈,把它移到页面的中间 体颜色给他黑色,再加点圆角五个像素的,先来看一下刷新,现在呢这样子,我们还要给他修改一下,加点 pad 等来挤一下里面的内容上下呢,二十五像素左右呢四十五像素。下面这个 div 呢,也要给他控制一下 宽度呢,给他百分之一百高度的话三十五像素。然后呢给他一个含高,也是三十五像素,再给他们加点墨镜 top, 让他们之间呢有一点间距。 ok, 再来看一下刷新,现在呢这样子啊,还要给他调整一下,来控制一下 input, 控制一下这些输入宽宽度百分之六十高度呢,二十五像素。还有含高呢,也是二十五像素。边框 字体颜色三个八 ally none, 字体大小十二像素,加点 padding 上右下左边的五像素,加点阴影内阴影 来看一下刷新等一下这个按钮,这里呢我们还要单独给他设置一下样式,现在呢我们先把这两个文本输入框呢,让他往右边对齐一点。第二页上面这里呢给他设置一个相对定位,然后印铺,这里呢 再设置一个绝对定位,放在右边 right 八十像素。来看一下刷新这个按钮,因为我们做的这个绝对定位,所以呢现在它的宽度 已经是相对这一个波点来说了,我们单独控制一下他的样式,拿到十分米,这个按钮 宽度呢百分之五十,高度呢四十像素含高,这里呢给他十五像素就可以了,自己大小呢也是十五像素。 背景颜色波的烂,他的这个 boss 三斗的话也是烂,也不需要加十个像素的圆角, 给个字体颜色,还要加个相对定位,再来看一下刷新, ok, 现在这个按钮呢,在这个位置啊,我们还要把它移到页面正中间一点,给他定一下位 top 呢,五十像素 life 呢,给他百分之五十,这样他居中,这里呢就是负百分之五十。再给这个 superme 呢,给他设置一个鼠标,移上去的一个啊,我的围泪,让他出现个手型,然后呢再给他切换一下背景颜色, 再来看一下刷新,现在这个按钮的位置呢就差不多了,我们再调整一下这个超链接, 拿到 a 这个标签宽度呢,给他一百八十个像素,然后让他 display with bro, 通过 martin 呢来调整一下位置哈,给他放在按钮的下方一点,水平呢也是居中。再来看一下刷新, 现在位置呢,差不多了,我们再把这一个背景颜色给他调透明一点,这样子看起来好看一点。透明背景这里应该怎么处理呢?大家这里是不是第一反应就用这个 office t, 对吧?那这里用 office t 有没有问题呢?我们试一下,我们就在这 这个风这个表单这里呢,给他加一个 oppo c k, 给他零点三的透明度,看下效果。现在刷新,哎,大家发现他透明是透明了, 但是呢,它不仅仅是这个背景颜色透明,对吧?它连这些文字呢,这些书框这些全部一起透明了,我们要的效果呢是它的背景颜色透明就好了,它的内容呢就不要进行这一个透明的处理。 其实这里呢也很简单,既然我们只要这个背景颜色透明就好了,那我们就不要对整一个风表单设置这一个 oppositty, 我们给这个背景颜色加入一个 a, 这个 a 代表的就是他的透明度,这里给他零点三,这样呢就是他的背景颜色透明,但是其他的内容就不会透明了,刷新, 哎,我们要的这个效果呢就出来了,我们再对这个文字呢加点文字阴影吧,这样子好看一点,加个 tastano 白色, ok, 这样子感觉呢就好看一点了哈。我们这个登录的页面呢,就做好了,登录的页面做好呢注册的页面其实是一样的,打开这个注册这个页面的 htv 文件啊,这里面呢和刚才我们这个登录的界面其实是一样的, 他无非呢就多了两项,多了一个密码,确认密码啊,邮箱这些哈样式那些其实都是一样的,我们就把这边这个样式给他复制过来,就从这个封这里一直到下面这里给他复制一下, 然后呢就放在这里,无非呢就是他的项目多一点,我们就把这个高度呢给他改大一点, 这里三百呢给他变成三百五十 div, 这里这些 macing top 呢,可以缩小一点的 来看一下效果,把这个 interesting html 我们就改成这个 register, ok, 现在这个注册的页面呢,我们也完成了静态的页面呢,我们基本上写好了前端我们剩下的工作呢,这里就只剩下这一个表达的验证,对吧?当然呢,表达的验证除了前端,我们后端也要进行验证,这里前端的验证呢,我就简单的用它 h 五内置的一些验证的规则就好了。 看一下我们写的这些字段哈,这些字段里面呢,我给他写了一个绿块的,这个绿块是什么意思呢?如果说我们加了绿块这个属性呢,就代表说我们这个字段呢,他是必填的,如果说你不填的话,他是提交不了的。 现在这几个字段呢,我都加了这个率快的,我先把第一个给它去除掉吧,再来测试一下。这边呢刷新, 先随便输一些内容哈。现在呢,因为还没有其他的验证规则,所以呢,可以随便给他输入,我点这一个注册,哎,没有问题,他没有任何的爆错,再来试一下啊,现在呢,第二个字段我给他空出来,其他的正常来输入, 再点注册。这个时候呢,哎,他就提示请填写此字段,因为我们第二个字段给他空出来了,对吧?但是第二个字段呢,是设置了绿块这个属性的,所以呢他是必填的,我们再给他说一些内容,第一个字段呢,我给他清空,因为呢第一个字段我把这个绿块已经给他去除掉了,这个时候呢,再点注册呢? a 他就没有问题了,可以提交过去了。然后就是油箱这个自断在 h 五里面呢,他是会帮我们验证油箱的格式的。这里假如说我随便输入哈,前面呢也是随便输入这里点注册呢,哎,他就会提示说要包含这个 a 这个符号,对吧?我们呢就给他加上一个 at, 再来提交。哎,其实呢还是不完整,他说不完整,再给他加上一个点 coa, 这样子呢,就是一个邮箱的格式,再点注册呢,就没有问题了。当然假如你觉得他的验证规则还不够好呢,那我们自己写一个验证规则呢,也可以简单来举个例子。 现在这个邮箱呢啊,我是以这个 cn 为结尾的,然后我点注册呢,哎,他没有任何的提示语是可以正常提交的,但是我希望提交过来的邮箱呢,都是以这个点收 n 结尾的,其他结尾呢,我就不允许他们注册。 这样子呢,我们就可以学一下自己的一个验证规则,找到这个邮箱这个字段。然后呢我们就给他加一个,加一个 pattern, pattern 里面呢写这个正则表达式就可以了,简单来写一下这个验证规则哈,首先我们这个邮箱呢, 肯定有这个 a 这个符号,对吧?然后呢,这个 a 的前面呢,他就不可以再出现这个 a 了,所以呢,这里就不可以再出现这个 a, 后面呢也不可以再出现这个 a, 也就是说呢,只可以有一个 a 的符号。最后就是以这个点 c o n 结尾, com 多了符结尾。好,来看一下我们的规则有没有生效啊?这边刷新一下,然后呢说一下内容, 刚才呢,我们提交的时候呢,这个 cn 他是可以提交过去的,对吧?他没有任何的提示,现在呢,我们点注册。哎,这个时候呢,他就说请与请求的格式匹配,也就是说呢,现在他是提交不过去的,给他改成这个点 cn, 再点这个注册呢,哎,就没有问题了。 当然我们这里的验证呢是比较简单的,大家正常在做的时候呢,可以直接一起来做好一点,像这些密码啊,用户名啊,限制一下它的长度,再多 多少位密码和确认密码呢,要一致哈,尽量在前端就给他验证好,没必要到后端呢再去验证。不过后端的验证呢,我们同样要做,必须要做好。我们这个视频呢就先到这里,前端的工作呢,我们基本上就完成了,下个视频呢,我们就结合一下 php, 处理一下后端的一个数据交互,感谢大家的。

ok, 那我们来讲一下我们的这个依赖注入,那么这个依赖注入啊,我们首先要理解 ioc, 那么什么是 ioc 呢?那么 ioc 呢?就是我们的 inversion of control, 什么叫 inversion of control 啊?就是控制反转, 那么又啥叫控制反转呢?来,我们来看一下下面这两幅图,对不对?首先我们看到这是一个奶茶店,那这个奶茶店呢?我没批干净啊,这边还录了点小东西,马上回头跟他要钱,是吧?帮你做了广告了啊。 ok, 这就是我们的一个奶茶店,各位,你们要去买奶茶的话,各位,你们要去买奶茶的话,你们是不是先跑去奶茶店呀?对吧?哎,我看到这个峰哥来了,啊,我,我看到那个骑马与砍杀十六世纪北半球的那个地图和模型作者 啊,这个场景,场景,场景,坐着来了啊,这个就是,你们是不是要去找这个奶茶店,对吧?你们去找到这个奶茶店之后呢? 然后去买奶茶,那么各位注意,这个时候是谁找谁,是你们找奶茶店,你们找他,他们把奶茶给你们,对吧?这是一点。第二点, 我们如果不是去奶茶店,我们去的是一个西餐厅,好,可来是一个西餐厅, 那么你们去了西餐厅之后,你们怎么样?你们会找一张座位坐下来,这个时候服务员就会上来了说,客官,您要什么服务呀? 哎,这个时候客这个服务员过来找你,向你去提供服务,这个过程叫做控制反转,本来是你去找这个服务, 而现在变了是服务来找你了,这就是一个控制反专的问题了,对吧?那么还原到我们的代码里面, 本来如果你要用一个服务,比如说叫 userbll, 对吧?我们都知道,在我们的三层框架里面,我们有一个叫做 dal, 就是我们的 data access layer, 我们的这个数据叫什么呢? 叫数据访问,对吧?叫数据访问,那么还有一个呢?叫 bll, 叫什么?叫 business 老警雷尔,就是我们的业务逻辑, 业务逻辑啊,业务逻辑, ok, 那么如果你们要用一个,在我们的控制器中去用一个 bll 层,我们应该怎么做?是不是应该去遛它呀?遛一个 bl, 对吧?这是什么?这是你去找他,对吧?你去找他, 那么现在变了,大人时代变了,不同了,是吧?你到西餐厅去了,这个时候你只要坐下来就行了,干什么呀?我等你送上门来呀,是吧?我等你送上门来呀,这就是 他来找你了,也可以理解成就是我点外卖嘛,对吧?本来我要去奶茶店的,那现在疫情严重,我被封在家里面了,我出不去了,那怎么办?哎,我打过 外卖,我点个美团,你把奶茶给我送过来啊,本来我找你的,变成你找我了,那么这么一个过程叫做控制反转。那么在我们的代码中的呈现就是我本身是需要去遛这个服务,去请求他,我去找你, 但是呢,现在反过来了,我就坐着,你呢,自动把服务给我注入进来,那么这个过程叫做控制反转。那么讲清楚了什么叫控制反转了, 我们来讲下一个问题,什么叫依赖出入?首先啊,各位啊,控制反转,你们是不是能理解了来控制反转的思路,通过我这个案例,你觉得特别清楚了, 敲个一我看看已经。这个时候,如果各位在去面试的时候,面试官再问什么是控制反转,很轻松的把这个问题解答出来了,哎,在我们 现实生活中,从什么情况到什么情况,那我映射的代码中又是一个什么情况到什么情况?这个叫控制反转,都没问题,是吧?先敲一波一我看看是不是都没问题了?都没问题,我们要讲依赖注入了。控制反转和依赖注入又是什么关系?来,首先控制反转是不是都没有问题了? ioc 控制反转啊,这两个不要搞困掉, 好, ok 啊, ok 啊,好,控制反转没有问题的,对吧?那我们来讲一下依赖猪肉,那么什么是依赖猪肉呢?对吧?既然理解了控制反转,那他和依赖猪肉有什么关系呢?很好理解, 依赖注入是实现控制反转的一种方法和手段啊。方法和手段?什么意思啊?来,我们刚 讲了,如果你在控制反转之前,你要去使用业务逻辑层,我们需要绿,对吧?那么用到控制反转之后,你要用到业务逻辑层,我只需要去把我的服务注入进来,那么这个注入进来,这个需要依赖注入吧, 那么这个注入进来是不是帮你去实现了这个控制反转呀?所以说依赖注入是控制手,是控制反转的一种实现手段。 哎,这又是一个面试点,对吧?到时候说解释一下什么是一带之路,解释一下什么是控制反转,清楚了吧?控制反转是什么?一带之路是实现控制反转的一种手段啊,就是这么个东西啊。 那么首先我们再来看一下依赖注入,对吧? dependency injection, 我们首先要离清谁依 依赖谁,为什么需要依赖谁注入?谁注入了什么,对吧?为什么谁依赖谁?为什么需要依赖谁注入谁又注入了什么呢?那么首先谁依赖谁啊?当然是我们的应用程序依赖于我们的 lc 容器,注意, 这里出现了一个叫 ioc 容器的东西,看好了啊,首先我们的应用程序依赖于我们的 ioc 容器,这是依赖,这是依赖。依赖注入的依赖是指的依赖的我们的容器。 第二个,为什么需要依赖应用程序?需要 ioc 容器来提供对象所需要的外部资源来,我们都说依赖猪肉,对吧?这个叫叫把不能是服务给猪肉进来,对吧?那么这个服务是什么呀?对吧?服务就是我们所需要依赖的一些外部资源,像我们的 bll 啊,这些东西都是我们所需要用的这些东西,那么谁注入了谁呢?很明显是 ioc 容器注入应用程序的某个对象。应用程序这,这个,这个应用应用程序所依赖的这个对象,比如说在我的这个 control 里面,我需要依赖于我们的 user bll, 对吧?我应用程序这个 ctrl 里面需要依赖我这个 user bll, 那么此时就是我应用程序所依赖的这个对象,所以谁注入了谁呢?很明显是 ioc 容器注入应用程序的某个对象,通过 ioc 这个容器去注入到我当前的应用程序这个里面,这个把 bll 给注入进来,注入了某个对象, 那注入了什么呢?就注入了某个对象所需要的外部资源呀,包括对象资源,常量数据都是可以注入的,都是可以注入的, ok 啊,那么这就是 依赖注入是什么东西?我们来看一下啊。在我们的 isp 当中的 code ioc 容器中,上网我们多次提到了一个 ioc 容器,对吧?上网我们多次提到了这个 ioc 容器,那么 ioc 容器是什么呢? 在我们的 isp netcord 六,对吧?这个里面的 ioc 容器就是指的 service connection, 从字面意思理解就是服务收集器,或者叫我们的这个服务集合,它是一个存放容器的罐子。 在这里所谓的服务就是指在开发中所需要使用的各种类的总称,注意, survives connection 不光只在外部项目中使用哦。如果各位在开发 winform 中,在开发 wpf 中我,我在 vip 般跟大家讲过,对吧?我首先用 wpf 开发的时候,我第一步是 做什么事情?让我们的外吧 a, 啊,不是让我们的这个,呃, wpf 容器化改造,对吧?我用 wpf, 我第一件事情先让他进行一个容器化改造, 让他能够在 wpf 里面用我们的容器,那么通过容器来让我们的服务进行一个注入,因为我们的 wpf 本身是不能够去注入我们的服务的,但是一旦经过容器化改造之后,他是可以注入我们的服务的,这个我们会再说。 那么首先我们知道这个 sp 当中的考证 ioc 容器就是我们的 so it's connection 这个类,那么从资源意思理解,他就是一个服务收集器 connection 嘛,收集器集合嘛, 我们的那个啊利斯特集合,他是不是记成了 iconic 啊,这是个集合,他就相当于是一个容器啊,是一个容器啊,是一个容器,那么这个容器里面会放多个服务, 那么不要被这个服务这个两个字呢所误导,其实就是我们所需要使用的各种工具类,或者各种类,我们统称为服务,统称为服务。 那么我们把这些服务先放到这个容器里面,当我们的某一个类在调用时发现,哎,在我这个类的构造函数中,有这些所谓的服务类型作为参数在这个里面,那么系统就会到我们的这个容器里面去找 相应的这个服务类型的实力是什么,然后把这个实力呢再丢到我们的这个构造函数的参数中,那这就是我们的这个依赖猪肉的这么一个服务。好,我们来看一下在我们的项目中如何去使用它。 首先我们需要把这个服务第一步,大象怎么放进冰箱啊?打开冰箱门,大象放进去,关上冰箱。 那么怎么注册服务啊?很简单,打开服务门,服务放进去,关上服务。哈哈,没有那么负责啊,没有,没有那么复杂,就一步使用这个叫 builder b u i l d builder, 点 survice, 点 add, 艾特什么呢? add trencent 爱的春生,春生就是我们的一个顺泰的一个服务注册,服务注册一共有三个生命周期,一个叫顺泰,一个叫坐拥玉,一个叫长,一个叫静态。啊,我们先看这个顺泰啊, ok, 在顺泰这个里面,我们需要注册哪个东西呢?我们来啊测试一下吧。在这个里面我们来搞一个了 swise, 搞一个 swise 添加一个文件夹,这个文件夹呢?我们叫 seivicsswise, 在这个 swise 里面 我们来添加一个文件,添加一个文件,这个文件叫做 userslvic surprise。 好,在 user surprise 里面呢,我们来写一个方法吧, um straight, 然后就要 get user name, 好吧, get user name, 在这个中呢,我们可以 return 一个我们的名字 i s。 好,那么这就是我们的这么一个服务,它功,它的作用是拿到我们的 usa, 那么我们把这个服务呢?给他注册进去。怎么注册啊?非常简单,我们只要在这个里面来一个,他这个里面其实他是有两个的。第一个是这个,加入这个 soice connection 是没啊,不是怎么 soice connection, soice transcent, 哎,他是定位有问题啊, it transcent 啊, 这个我的这个我微商九九扣的,还是有点小问题的啊,他定位不准,定位不准的话咱就不要他啊。这个里面呢,我们可以进行一个泛行的注册,在这我们把这个油三 se 啊 vicusus 给它放进来。 ok, 那这一步的动作就是把我们的这个服务给它放到那个容器里面去 啊,把这个浮碗放到我们的容器里面去,那放进去之后,下面我们就可以去使用它了。怎么使用呢?我刚刚讲了,非常的容易,就是在我们需要用到它的地方 给他构造函数管上就行了。比如说我的 test control, 这个里面我们只要写一个构造函数, cto r 啊,构造函数写好之后,我们只要把这个,嗯,那个叫 usersir survice icia suice 写上之后啊,这边我最好写上 user suice, 好,写上之后让他创建这个属性或者自传都可以啊,创建好之后,你看啊,通过这个属性去接收他传怪的参数, 去接收他闯过来参数,然后再 get 这个地方,我直接返回右侧 svise 点 get youseline。 好, ok, 这个时候我们来看一下它是一个什么样的结果,我们断点先打上,然后我们走一遭, 好,我们再来看一下,我们在这个盖上,我们点一下啊,走,首先先进入我们的构造函数吧,那构造函数我们发现,哎,这个里面是不是有一个 second demontteapi, 点 survised u suice 呀,对吧? 哎,有这些东西我们就想到,哎,好神奇啊,他的吊用去创建我们的 ctrl 的时候,竟然就把这个 usbs 给他敷上去了,是吧?既然你有值了,他是怎么找的呢?就是这样, 什么系统?在创建我们的 ctrl 的时候,他就先看,哎,我创建你的 ctrl, 首先我要去使用你的构造函数去创建这个类吧。构造函数,构造函数是干什么的呀? 构造函数的东西,他就是去构造这个类去用的,你要去创建这个类的实力,首先要用我通过构造函数去构造,所以叫构造函数嘛。哎,他看这个构造函数的时候发现,哦吼,你这个构造函数里面有一个参数叫 usbs, 嗯,我到我的容器里面去找一找,发现,好,我发现我的这个容器这个桶里面竟然有个叫 usos, 一个注册的一个类啊,好,既然有,那我就把这个类给创建一个实力,然后呢,去放到你这个构造函数里面去,去传餐,传进去,传完之后我这边就把这个餐处拿到了吧,拿到之后再给我们的这个属性,对吧?给了属性之后,下面 到我们的 get 里面去,然后 get 里面,因为我们这个 usbs 你是实力化的吧,进去之后,然后通过我们这个 gets usbs 返回一个 s 就结束了, 所以这个时候我们发现,哎,我们的值是不是就拿到了,对吧?那就是构造函数。当然了,我前面讲了,我们除了在这可以用,我们还能在哪用啊?还能在 minimoaapi 中去使用, 对吧?在 mrapp 中,我们直接在这写什么?直接在这去写我们的这个,这个,嗯,这,这个啊,我们重新写一下啊,这个就把 把它先保留着。好,这我直接,哎,给你一个这个玩意,哎,这个玩意来了, 我们可以直接通过这个玩意,哎,给你来一个 user surprise, 点 get user name 来看一下,依旧可以实现, 哎,发现没有?没有,要我传传值吧,他并没有把这个看成参数,对不对?走,哎, s 数也有啊,所以我们在迷你猫片中也可以去使用我们注册好的这个类,但是一旦我们这个类我没有给他注册这个是我们再来 看一下这个里面,他,就,哎,有问题了, f, 我走一个啊,不是啊,对, f, 我走一个啊, uh huh, 首先这样就出问题了,是吧?来这个 system invalid operation exception。 那首先我们这个样子出问题了, interviewer 的巴士, the mentor 的大声的 load infield body prometer, 这是不被允许的啊,这么一个东东。所以呢,我们先把这儿给 no 的,啊,漏的吗?不被允许吗?别出事啊,让我们再启动。 好,我们此时再来看一看,瞧一瞧,走过路过不要错过。走你。哎,断点了。 哦吼,曹雷这个断点命中都没命中吧。他直接给我返回 五百是吧。 unable to resolve survives for the type 这个 user surprise。 我不能去解析 user surprise 这个类型了。 why 哦? attempting to activ the activitor 这个这个 activitor 这个什么 second demonapi control 这个 test ctrl 啊,就是我现在没办法就解析你这个类型了啊,直到你这个里面有这个东西为止。 所以说发现 a 出问题了,就是说我如果不注册,不是说你这个里面没有传来的是一个闹的问题了,直接就是不让你进这个构造函数了,我构造函数都没法进。所以各位以后看到什么 unable to resolve survive 服务的态度吧啦吧啦吧啦吧啦。你们知道肯定是我这个构造函数里面的参数我没有注册,所以汇报这个错,他没法解析,那这个时候你们就要把你们构造函数,你要么把这个参数去掉,你要么呢让他重新注册进来, 那么这样呢,就可以实现我们的一个依赖注入了。好,到这里为止啊,没有问题,小伙伴敲五一依赖注入是怎么回事 啊?小一敲一下啊,公屏里面敲个小一,哎逼站着来逼站着来。这么多人进来了,你这个不敲小一的啊。 b 站今天也没人刷礼物。那好伤心好伤心。 好, ok, 我们继续啊。那么根据这个依赖注入啊根据这个依赖注入啊。我们还能听到一个东西叫做依赖倒置。 呃,我们首先听到业主还有个叫依赖倒置,依赖的蜡, 依赖倒置是吧?依赖倒置, ok, 那么什么叫依赖导致呢?依赖导致就是说我们需要去利用我们的抽象作为相应的依赖,对吧?我们要把这个通过抽象去接收我们相应的对象,然后依赖于我们的抽象,对吧? 啊?就是应该用我们的这个叫接口,接口就是我们的抽抽象吗?我们不使直接使用这个 usos 这个实体类,那么什么这是什么意思呢?来各位来看一下,一般呢,我们在这个使用的时候呢,他是这样子的, 那 usos 呢?一般情况下我们有一个实体服务,对吧?有个 bl 摇成,我们是不是还有一个叫 ibl 摇成啊?对吧? ibl 摇成, 那么 ibl 算是什么呢?就是我们的接口了,这个接口能起到什么作用呢?对吧?接口能起到什么作用呢?很明显吗?就是说我如 如果在我的这个下端 controls 啊, cunt 二 ol, l, e 啊, clot 这个里面,我要去用这个 bll, 那我就是用一个 ibll, 对吧? 去依赖于这个 ibl, 而不是去依赖一个实体,那么这个接口在这就相当于连通了我的 blu 和 ibl, 就连通了我们的 blu 和我们的啃臭啊这么一个作用。 那么这个接口他有两个作用,第一个是规范我们这个 usbs 里面的类型,就是说我的这个接口里面有哪些类型,我的这个 usbs 这个类里面就必须有哪些类型, 就必须有哪些类型,那就是一个,那第二个就是说我如果去依赖于我,第一个就是对他的一个规范,对吧?那第二个呢?就是说我的这个 前端,我的前端,我的口臭去依赖于我的这个接口,而不依赖于这个时限,那我这个时限,我内部我随它怎么变, 我只要是跟这个接口的方法保持一致,那么我的口臭这一层是能保持稳定的,我一个大门都不用改, 我哪怕你 usualize 里面天翻地覆,我的 ctrl 里面什么都不用改,对吧?因为我的依赖的接口是稳定的,所以这是接口的两个东西啊,两个作用,那么我们怎么去写呢?非常简单, usual surprise, 那这边写上我们的 i usual surprise, ok, 那么我们这边生成一个 isos 这么一个接口,那么这个接口生成好之后呢?我们就把这个东西,哎,写上写上。 那么我们依赖于这个接口之后,我们要去用的时候,我们一般呢,以前是这么用的,比如说我这个 usoais, 对吧?那我要用的时候呢?我可以用一个 i usersois, 这个 usersoice, 对吧?等于到我们的 new usersoice, 哎,这就依赖于抽象吗?对吧?依赖于抽象,用一个接口去,呃,来, 纳尼?无法将 usbas 存在一个引显示转化,哎,八盖路的,出问题了吗?没错,哎,怎么,哎,怎么这没有显示啊? 啊,这在这啊,出错了吗?啊,这回好了是吧?应该不会报错了吧?你这个啊, ok 啊,刚刚没有保存 好了,那么这个 uccis 就可以给这个 iciuiuccis, 那么反过来讲, iccis, 既然是这个 ucci, 既然继承于 icis, 我们也可以把这个 iuccis 看成我们的 uccis 的一个负类,那么负类可以接收子类,叫女士替换,对吧?叫女士替换, 这样是可以实现的,那又叫依赖抽象,又叫以理事替换。那么这是我们正常的一个 new 的时候,我们依赖于抽象,那么在我们依赖注入的时候,我们怎么去依赖抽象呢?其实也很简单了,在这个地方,你看爱的圈子,其实这个里面有两个东西, 一个东西叫做八格牙路,不是不是八格牙路啊,一个东西呢?是我们的啊,找不到就算了啊,找到了啊,找到 是这个,一个是我们的,这个叫 testwise teeth lies teeth lies 叫什么?叫 the type of server 啊? the type of the surprise to add 一个服务类型,然后呢? i am politician, 这什么?还是 t i? 呃,叫 t in politician, 这是 type of the impulsitation to use, 就是我们的这个类型的一个实现类型,这是我这个类型是什么类型?然后它的实现类型又是什么? 所以很简单,在这我的类型,我既然是依赖抽象,那么我的类型就是 i usualize, 那么我怎么去实现这个类型呢?他的实现类型是什么呢?哎,他六的那一边是有所, 这是我们刚刚那个 iussus, 然后那个 surprise 等于 newuussusus, 是通过这个 new, 这个 ususus 去实现这个 iususus 对象的吧,所以这个服务的类型是 iususus, 而他的实现类型是 usb, 就这么个道理。那么我们这样写完之后,哎,我们这个时候呢,再启动一下,我们来看看,瞧他会有什么变化不? f 五走一个。 好,我们来看一看啊,瞧一瞧,看一看,走过路过不要错过,继续踹他一脚,继续五百 unable to resolve surprise for the type use a surprise。 哎,不对啊,怎么还爆这个错呢?我这边明明有注入啊, 为什么还说我没法解析这个 ucci 这么一个玩意呢?哎,这我就不明不明白了啊。别不明白,因为我们注册的时候,你说明了你注册的福利型变了, 不是 usbs 了,你注册的服务类型明确是 i usbs, 而 usbs 只是一个实现类型, 哎,是这么一个东西,所以那我在这个你们要用的时候呢,我就不能用 usbs 去作为这个啊构造函数参数了, 因为我在系统里面去找,我在容器里面找,系统看到,哎,我这个构造函数里面有个叫 usos 的类型,但是我的容器里面没有一个服务注册类型叫 usuccos, 只有 iccs, 所以他找不到这个 usbs 就报错了,但是我们在这如果写上 afcs, 那此时呢, 他又能正确了,我们来看一下, 哎,是不是又出来了,哎,走,哦哦,对不对?好,还有是吧,有了啊,是吧,数据就有了,那么正常返回,那么肯定是能够返回我们这个相应的 s 这个数据的,对吧?那这就是这么一个东西啊,这一块能明白。小伙伴,敲个一, 哈哈,几个敲六六六了是吧?这敲一啊,敲一来,小一,敲起来,敲在公屏中,来公屏中扣个一啊,扣个一, 这样的话就好了啊,在逼账的时候,就算是录录屏视频的话,那扣一啊,说明也有人扣弹幕,是不是那一点小心思嘛,对吧? ok 啊,没问题,小伙伴,哎,在公屏里面扣个一啊,在弹幕里面扣个一哈,弹幕里面扣个一,哈哈,好, okok, 那么这是怎么样写?那个小伙伴说了,哎,不行啊,我就要用 usbs, 对吧?我可以选择癌癌 usbs, 也可以选择 usbs, 选择权在我, 哎,你不能限制我的选择呀,是不是,那这一块我们该怎么办呢?是吧,那这一块我们该怎么办呢?选择权在我呀,啊,你不能够, 不能够这么限制我的这个选择呀,那我这个时候应该怎么去搞这个东西呢?哎,我发现 vip 上面有个小红桶。小红桶,你,你,你是 vip 吗?怎么没看到啊?小红桶是 vip 吗?第一次来看,我第一次看到这个这个名字啊, 啊,在 vip 课堂里面,那么我既要有 iuuss 八 s, 又要有 ucs 八 s, 怎么办呢?其实, 其实没啥技术含量,你看看你写两遍不就行了吗?是吧,一个右手手爱死,一个啊,右手手爱死吗?你写两遍啊,写两遍我们来 f 五走一个啊,不要 f 啊,我们这边啊,依旧把它改成右手手爱死, 这个时候可以用这个抽象去接收我这个 usb 啊,这就不用改了, 好,看,他会不会报错啊,我心里也没底,是吧,也没底,走你。哎,没报错是吧,数据来了,所以这种情况呢,你写两遍吗就可以了吗?对吧?哎, ok, 这是一个啊,好了,那么这一块呢,就是我们的这个依赖注入的这么一个简单东西。

你要问我控制反转依赖注入这些有什么好处?那我可以给你滔滔不绝的讲上一天一夜。但是在面对那些依赖极其复杂的大型项目时,那写起来非常的勾心, 比如我们的势力代码,尽管我只是想让 people 说一句话,但是呢,你想要构建一个人的时候,不得不给他安上一个手,给他安上个鼻子,还有个嘴巴。这些依赖多就算了,而且还很深。 不仅如此,他们先后实力化的顺序还不能搞乱了。那这对于一个大型的项目来说,心智负担是极其严重的, 那怎么办呢?所以对于这种比较复杂的依赖,入入推荐使用 where, 此时你只需要把所有依赖的构造函数全部都丢进去,至于顺序什么的完全不重要。最后通过函数 的反馈值告诉外尔你需要什么类型的结构体。一段非常简短的指令过后,他就会根据构造函数的类型声明信息,帮你补全所有的上层依赖。这个时候我们整个依赖注入的流程就会变得非常的愉快而且轻松了。

比如说在这再来讲一下这个步骤好,比如说这个步骤有什么好讲的呀?这个步骤看上去很简单呀,不就是利用这个类的午餐购置方法去得到一个对象吗?好,关键问题在于,你看哦,其实我们有的时候工作总结你可能也这么写的哦。来,看,我先把这里先删除掉。 来,我先问大家。哎,我代码如果改成这个样子,首先我问大家,我现在 you 的 service 这个类里面有几个购置方法?来,大家告诉我,我看有没有同学会打错啊? 来,有几个过程啊?大家告诉我啊。好,我看有同学打两个。哪来的两个嘛?只有一个。好吧,有同学打,我相信打两个的同学,你肯定是认为说当前 youtube service 里面还有这个无偿的,他没有无偿的了,懂吗?你看报错看清楚没?这里有 个红线报错没有无偿的了。有人说为啥没有无偿的,那你去问告诉您好不好?你别问我,这个东西不是我搞的好,所以说你如果说你要注意你,对吧?你现在只有这一个告知方法,如果说你真的还需要那个无偿的告知方法,那你就自己再重写一下,这才表示有两个, 懂不懂?好,那么来看,哦,还是回来,我说了,现在这个类里面他就只有这么一个过程方法,那么你现在这也是一个病对象呀。对,只有一,这,这是个病对象。那么按照我们讲的,你这个病对象,你最终,呃应该也要去把它创建出来,那么创建出来,你现在没有无偿的过程法,那么 spring 能不能用,能不能用这个过程方法呢? 老大觉得能不能用?会不会 supreme 他会不会来用这个歌词方法?觉得会的打一觉得不会的打零,会不会来用这个歌词方法对不对?你只有这么一个可以用啊。 那 spring 会不会来用呢?好,我看有人说不会。那所以大家可能还是 spring 这一块还是学的不是那么扎实。我们来试一下,我们这里打印一个嘛, 用了没有?用了发现没?这里打了个一,很明显用了,而且有没有同学能够发现还有一个非常重要的事情,你看我们下面这里打印出来值了,下面这里无非就是我呃, test 方法执行,那么所以他打印这个属性,他关键问题是他打印出来值了, 哪里负的值?我这个属性上面我没有加 autobio 的注解,所以只有这一个地方就是构造方法,这个地方会给我们 ott 设备是属性去负值,那么 我们这个购置方法 supreme 他不仅仅用了,他还传的一个 word service 对象给进来了,明白吗?不然你这个属性你哪来的值呢?所以说这个也是一个点啊,我等下也会讲的。 好啊,这是一个方,呃,这是一个情况,我们再来看另外一个情况来看哦,我们再把这个无偿的把它给加上。那么呢,大家告诉我现在 spring 会用哪一个零还是一? 还是什么?会用哪一个零?为什么零?对哦 a, 好像同学大家都能够答对,那为什么呢?有没有同学能够告诉我,为什么你有无偿的,他就用无偿的呢?为什么不用下面这一个, 对吧?你下面这个可以用啊,刚刚还刚刚就用了,你为什么又不用了呢?就很奇怪对不对?好,我们先不管,我再换一个,我把它注射掉,我再来加一个。有仓的 来,我再来加一个。呃,两个参数的勾字方法,来这里来打印一个二来现在会用哪一个?会用哪一个报错。那为什么报错呢?嘿,有的用一 有那些有没有觉得要用二的来他确实会报错啊,你看他报什么错?我们大家看一下他说创建 user service 并的说报错了,对不对?创建不出来吗?就是这个意思。那为什么创建不出来呢?他下面有更深层次的原因,他说找不到某个方法,找不到哪个方法呢?找不到这个方法。这啥意思 啊?什么盈利的?这是什么方法?这就是我们说的无偿的过账方法,懂吗?你一旦看到这种呃错误你就知道它相当于是告诉你 users 里面没有无偿的过账方法,所以它报错。那这就奇怪了呀, 你怎么没有?确实是没有无偿的购置方法啊,我现在确实是没有。这个是你没有无偿的购置方法,你怎么要报错呢?你这个方法不能用吗?可以用啊,刚刚都用了呀,对不对?或说你下面这个方法他不能用吗?我跟他说下面这 个个子方法 spring 他要用,他也能够用,你看吧,我来运行啊,你看他也能够用。所以说白了这三个个子方法 spring 他要用,他都能够用。好。那为什么像我们刚刚这种情况他要报错呢? 来看啊,所以这个时候我们就可以站在呃 spring 的角度来分析这个问题。你想嘛如果说你是 spring 啊,你发现现在这边有一个类它是一个病对象,它定义成为的病,那么我作为 spring, 我我首先要去创建出来一个对象,我就得去用你这个类里面的购置方法才能去创建出来一个对象,那么我用哪一个呢? 你想嘛?你现我现在一个类里面有两个,我 spring, 我用哪一个呢?我不知道用哪一个,懂吗?你现在有两个,我不知道用哪一个,所以我报错就是除非程序员你明确的告诉我了我应该用哪 哪一个,那么我就我就不会报错了,我就知道用哪一个了,那么我程序员我怎么明确的告诉 spring 我要用哪,你要用哪一个购置方法呢?来,我们有一个方式,就是加注解,你可以加上 auto y 的注解, 这就表示我程序员明确告诉 supreme, 你就用这一个个字方法。我现在一个店里面我确实有多个个字方法,但是你就用这一个就可以了,我给你标记好了,懂我的意思吗?你看我们刚刚这个答案会报错,但是我加上这个注解之后,他还会不会报错呢?我们再跑一下, 那他就没有跑了,他就用的就是我这一个。对,你看我再把这个座椅加到这个上面来,哦,加到呃,这里来,我们再来运行一下,他就会用这一个,懂吗?好,我我会给大家总结的,你先看哦来,是不是?所以相当于我程序员我明确的告诉 spring 你应该用哪一个,但 老有同学问那两个都加呢?两个都加会怎么样?你想嘛?如果说你是 supreme, 你发现两个都加了,你用哪一个?你是也是照样是蒙的,对不对?所以说他照样也是包括, 懂吗?只是这一个,但有人说那么 at resource 可不可以呢?不可以。你看嘛? at resource 它没有这个功能,你看 at resource 里头不能加在构造方法上面的,你只能加在类上面,加在属性上面,加在普通方法上面,是不能加在构造方法上面的, 懂吗?还包括像有的人可能会想到像什么 primary 注解,它也没有这个功能,它也不能加在构造方法上面,相当于只有我们的 auto y 的注解它有这个功能, 就是你可以明确的告诉 supreme 要用哪一个个字方法啊,这个意思啊。当然了,假如我们没有指定,那么有人就可能会想到我,我现在我开始的情况,像这种情况,对吧?也是 是有两个购置方法,但是 supreme 它会用这个无仓的,这是为什么呢?其实也很好理解,就是还是这样的, supreme 发现你这个内里面有多个购置方法, supreme 它不知道用哪一个,但是就像有同学刚刚答错了一样,我们通常会认为我这个内里面有一个无仓的, 或者我们也会呃,把这个无偿的构成方法就理解为一种默认的一个实现,就是兜底的一种方案, 懂吗?就说 supreme 也是这么理解的,我发现你这里面有多个购置方法,而且你又没有明确的指定,没有明确的告诉我要用哪一个,然后你又有多个, 那么我就会去找这多个里面有没有无偿的,如果有无偿的,我就用无偿的,如果没有无偿的,我就会报错,能理解了吧?像我们刚刚讲的这种情况有多个,但是你这多个里面没有 无偿的, supreme 他说找不到无偿的,所以他就会报错,但是如果说你现在一旦加上这个无偿的,那么 supreme 他就会用这个无偿的。来,我问一下大家听明白没,听明白的可以打个一, 所以我总结一下啊,总结一下就是你看嘛,假设一个类里面只有一个购置方法,那没什么好说的, spring, 他就用这唯一的一个, 对不对?好,假设一个列里面有多个个字方法,那么 supreme, 首先看你这多个中间某一个上面你是不是加了 autobio 的注解,只能有一个加了 对不对?那么加多了也会报错嘛,那么我就会用加了这个注解的。那么如果说都没有加 otoy 的注解呢?我就会去看这中间啊,有没有无偿的各种方法,如果有无偿的,我就用无偿的,如果没有无偿的,那我就真的不知道用哪一个了,我就会报错,就是 这个意思,懂吗?所以就这个意思啊,所以就是我大概总结一下,大家回头可以自己去写写笔记啊之类的好不好?所以这是这个好,那么呃,我们再看啊,你看,现在我就有三个构成方法,其中有一个无偿的,那么我刚刚也试了啊,他就会用无偿的,但是如果说我再加上 otw 的注解呢?那现在会用哪一个? 说白了就是零和二嘛,用谁他不可能用一的哦,对不对?用谁?用二对不对?能想明白吗?为什么用二的自己能想清楚吗?第三个对的, 很明显嘛,我说了无偿的购置方法,它相当于只是 supreme 它最后的一个兜底的机制,对,它最后才会去看你有没有无偿的,而且,对啊,我我,而且我跟 i a 讲了,我们加上这个注解,就表示程序员 我明确的告诉 spring, 你就用这一个就好了,那 spring 肯定用这一个啊,我都明确告诉你用这一个了,你还不用这一个,你啥意思, 对不对?所以说加了注解的肯定用注解的,懂不懂?好,属实是呃,我们刚刚讲的这一块逻辑。好吧,所以这个东西啊,可以发现我们其实换一个了,叫做推断购置方法, 就是推断个子方法,相当于 supreme, 他现在要利用这个类啊,我要去申请一个并对象,但是我首先得决定我应该用这个类里面的哪一个个子方法去得到一个对象,所以这个叫做推断个子方法。 好,那么我选择好了购置方法之后,其实就就像我最开始要去讲的啊,你看我现在只有他一个,那么 spring 就会用这一个购置方法,但是还有一个非常关键的问题是什么?我再来跑一遍啊,还有一个非常关键问题是 spring 他不仅仅来用了这个 这方法,他传了一个 word service 对象进来了,懂吗?你看嘛,我这里运行了一下,他用了,但是他还给这个属性负了值, 懂不懂?所以这是一个呃,更加呃就是呃看上去很厉害的一个功能了,所以我们要去想哦,就 spring 你到底是把哪一个 order service 对象传进来了呢? 好,接下来我讲的这个问题,大家能能不能听懂来,能听明白的先可以先给我打个一,就是我接下来讲的是我到底 supreme 内部他是把哪个 word service 对象传进来了呢? 对不对?好,来,大家自己思考一下来下哦,我现在 spring 我也来执行这个构设方法了,相当于说我相当于我需要一个 order service 对象,那么我 spring 我会从哪里去获得一个 order service 对象?你看嘛, order service 它也是一个病,对吧?那么他会从哪里去获得一个 order service 对象呢?还记不记得病?工厂来我前面讲过一个东西的,还记不记得?就这个 map 吗? 懂吗?我前面不是讲过这个 map 吗?这个 map 用来干嘛的?他就是去用来存我们的并对象的,对不对? 存并对象的吗?那么你现在不是就是需要一个 word service 的对象吗?那我是不是就可以开始从这个 map 里面试着去找一下你这个 map 里面有没有 word service 对象?如果有,烂了就直接拿出来用嘛,对吧?那如果没有呢?假设没有呢? 有可能没有,对不对?没有怎么办来?没有无非就两个选择,一个选择去创建,一个选择就是返回空对 map 里面没有,那要么就去把这个 order 位置的并对象把它创建出来,要么就返直接返回一个空传给这个购置方法吗?对不对?那么 spring 它选择的哪一种呢?选择的是创建,就是这里有一个点啊,就是 spring, 呃,虽然我们语法上面我们是可以传一个绕进来的, 但 spring 他不会,永远不会传一个绕进来的。注意我说的哦, spring 他来调这个购置方法的时候,他永远不会传一个绕进来的。 他,你,你如果真的没有一个 order 设备时对象可以传进来,他会报错的。来,我给大家举个例子,就像我说的,我现在假设 map 里面没有,然后我,我说白了,我想去创建 order 设备时,这个并对象, 你要创建 order service 的病对象,你前提是你 order service 得是一个病,懂吗?那我现在如果说我都不让他是一个病, order service 他都不是个病,那你肯定不会在这个 map 里面,而且你肯 也创建不出来,那么你只有一条路,就是闯一个空进来,能懂我的意思吗?就你创都创建不出来吗?所以你只有一种选择,就是闯一个空进来,那么他会不会闯一个空进来呢?我们运行一下,你就你就知道了。 那他没有,很明显,他就像我刚刚说的,他报错了。他报了什么错?他就说穿进 user service 的病失败了。那为什么失败呢?他说他找不到 order service 类型的病, 看到没?他说白了,他这两个加起来就表示说我一定要有一个 order service 的并对象传进来,因为在 spring 里面,他认为这个购置方法的参数就相当于是一种强制依赖。 我现在要声称 you 的 service 对象,我就一定得要有一个 order service 对象,如果没有这个,呃,强制的这个依赖的这个 order service 对象,我就会报错,我不会 传一个空进来的,懂不懂?来这个地方能理解吗?能理解的话打个一就说,像我们说的,你前提是你 word service 你一定得是一个并对象,懂吗?啊?你才有可能在这个 map 里面,就算这 map 里面没有我也才有可能能够把这个 word service 的呃,并对象把它创新出来 啊。创建出来,那就好说的嘛,创建出来,你创建出来一个,你就把它传进去,那就没什么好说的啊。我就不再接着讲 word servie 是怎么创建的了好不好?我们还是回到前面这里来,那假设这个 map 里面有一个 word service 对象呢? 对,假设有啊,那么我怎么去找到他呢?那这里就也很重要啊,也很重要,怎么去找到他呢? get 啊,那么对,有的人就立马讲到了是 get, 这个没问题。那 get 的话,那么是不是我们就需要传入一个 key, 那么我这里能够把 什么东西作为 k 传进去呢?来,是不是这个名字?对啊,用这个可能想到的就是,那我就把这个字符串嘛,这个常说的名字当做 map 的 k, 我我去 get 它 啊,要看能不能 get 到。那这个思路可不可以呢?这个思路其实很正常的一个思路,但是他不可以。为什么呢?其实你想吧,假如我这里写的是叉叉叉, 来我这么写的话,我是不是还是需要一个 order service 对象?但是你拿这个叉叉叉去 map 里面去 get, 你能 get 出来东西吗? 是不是 get 不出来,对不对?可能麦克里面你真的有 order service 的并对象,但是你你名字不叫做叉叉叉吧?对,所以说,呃,很难就可能 get 不出来,或者说你可能这么写的,对吧?有,我相信有同学代码有的时候复制过来了的时候他没有把这里去改掉,你现在直接拿 member service 去 map 里面去查,那么你大概率查出来的对象是什么?是不是 member service 类型的?那你能够拿来用吗?是不是用不了,对不对?用不了。所以说一般啊,我们通过名字去查,好像总是,呃,有可能就就查不到,或者有可能就白找了,对不对?那么最保险的方式是什么? 是不根据类型去 map 里面去找,因为你是需要一个 order service 类型的对象吗?所以我直接根据这个类型去 map 里面去找。那找到的肯定就可以用啊,肯定就是 order service 类型啊,对不对?好,那么在想啊,我直接根据类型去 map 里面去找,是不是又会有其他问题呢? 对病的名字是不能一样的啊,要么会报错,要么会一个覆盖掉另外一个,因为在 supreme 里面只能一个,只能有一个就是名字是唯一的。好吧,所以 注意啊,我这里不去演示了,我再重复一遍,在 spring 里面如果说你两个病的名字是一样的,要么就是会其中一个覆盖掉另外一个,要么会直接报错。 好了,在我我这里不展开去讲了啊,来回答我的问题用来说的。我根据类型去这个 map 里面去找,我有没有可能会有其他的问题?来 l 同学回答正确 类型他可能就就不一样了,懂吗?我们。呃,比如说这个 map 里面我有可能是存了一个 k 一,我对应了一个 v 一对象,我可能还有一个 k 二,我对应了一个 v r 对象。来注意这个 v 一对象和 v r 对象,它是两个不同的对象,那么它的类型有可能一样呀, 这个没有限制的,他们两个的对象的类型可能都是 order service 类型。那如果说我现在再去找,我是不是就能够把那两个对象都找出来?那找 找出来之后传哪一个呢?对,这就是一个问题了。好吧。啊,因为说有没有这种可能啊?有没有在有没有可能在我这个 map 里面有两个 word 设备时类型的对象,有没有这种可能? 很有可能,我跟他说啊,只不过大家可能有的时候理解上面就理解错了。来我我先问大家一句话,大家看这句话我说的对还是错?我说 orders, 来注意听啊。我说 order service 是单立病,那就表示在我私奔容器里面只能有一个 order service 类型的病对象。 来认认真听一遍,我们不去打字了。我说 order service 是单立病,那就表示在十倍容器里面只能有一个 order service 类型的病对象,最重要的是对还是错。

依赖注入我们用的非常多,英文名是 dependencing addression, 这个名称看上去有距离感。有位大神写了一篇文章,大家可以说一下,叫做 dependencing addression dimestified, 大概意思是说二十五美金的名称用在了五美分的概念上。我来给大家讲一个故事啊。首先假设你去学校给大给孩子办入学手续,去到学校里发现办入学手续需要先提交户口本, 而你又去办户口本,但是你又发现办户口本需要先办一个出生证明,就一个,这这个东西就叫依赖创建入学手续,这个对象依赖于户口本,而创建户口本这个对象又依赖于出生,又依赖于出生证明,是不是觉得很麻烦?注意哈,我们现在 聘请一个小秘书,你一开始就告诉,就告知他户口本啊,出生证啊,这些对象是怎么生成的?这也叫注入这些依赖,这样你带着他一起去办入学手续,对方要什么小秘书就提供什么。而这个小秘书就是现在市面上流行的依赖注入框架, 比如谷歌的柱子,顺着这个思维,你再去好好看一些细节,相信你很快就能完全搞懂依赖猪。

今天威哥给大家解析一道源自阿里伊面的面试题, spring 有支持几种依赖注入的方式,接下来我们就开始解析这道面试题。依赖注入全称 definition 杰克士,人,简称 d i, 他是 spring 控制反转思想的具体实现。我们知道,控制反转是指我们将对象的创建交给了 ioc 容器来管理,而依赖注入则是在 ioc 容器 在运行期间动态的将某种依赖关系注入到对象之中。所以依赖注入和控制反转是从不同的角度在描述同一件事情及通过引入 ioc 容器,利用依赖关系注入的方式实现对象之间的结偶。 spring 中依赖注入的方式主要有以下三种,一、 自断注入我们可以通过 alt wire 的注解实现自断属性的依赖入入。该方式最大的优点就是使用简单和灵活,但是遗憾的是它却是一种不建议使用的注入方式。二、 set 注入 set 注入是指将一个类的依赖通过设置一个公共的 set 方法注入到该类中。 set 方法通常在类中被定义为帕布利克,并且以 set 开头,接着是一个单词表示注入的属性的名称。 通过这种方式,每个塞的方法都可以单独注入一个对象,使用起来同样非常灵活。三、构造器注入这也是 spring 官方比较推荐的一种注入方式, 从 supreme firmwork 四点三版本开始,如果当前类中只有一个构造方法,那么 alt where 的注解也可以省略。小伙伴们,关注威哥,更多精品内容持续与你分享!

好,那我们继续下面我们对这个奥特威尔的啊,这个注解啊,他的功能我们进行扩展一下啊。呃,这个奥特尔一般情况下,我们在开发时用的最多的,就直接是在我们的属性上去添加一个奥特威尔的 啊,那 speed 容器呢?哎,看到这个 out where 的,它识别之后呢,会自动从容器当中找对应的你这个数据类型的,并然后进行匹配 啊,这是我们之前讲的是吧?而且这奥特 ver 呢,平时我们可能有的时候还会用到这个方法上啊,虽然比较少,但是有时候也会用是吧?那我们现在的奥特曼用到这个方法呢?他是对应的这个 u 字丢属性的一个赛的方法是吧?其实这个奥特 ver 在用到方法上啊,你是不是赛的方法其实都可以啊。好,我把它注掉, 把这个我们也注掉。下面呢,我们去演示一下。比如说在这个地方我有一个方法, 方法名随便叫叉叉叉对吧?然后它内部的参数呢?是个 user 哎, d u user d u, 我在这打印一下对吧?如果这个 uzdo 能正常打印,我是不是能证明住进去是吧?我这样啊,加一下叉叉叉冒号 uzdo 对吧?你这么写当然不行的,我需要干嘛呀?需要在上面加一个 auto beer 行吧。再是加 out where 的,那死病识别之后,你这个名字是不是并不叫 set user do 是吧?那通过这个我们去证明它在进行注入时,它是根据这个什么呀?嗯,这参数的这个类型去匹配的, 能明白吧?好,那现在呢?我去执行执行。哎,你发现叉叉叉,这个 userdo and p l 是不也能被注进去吧? ok, 所以这时候扩展这个点, 咱们随着这个扩展点呢。我接着再讲啊。再讲,我再 copy 一下对吧?这个方法叫 yyy 啊。我要干嘛呢?看着啊。嗯,当然把它改成 yyy 是吧?我在这个地方我不写 u 的 do 背心呢,我写个集合, 它的发型是 user d o 对吧?我这个叫 user d o list, 把它打一下, 这能看懂吧?那这是什么意思呢?这这个意思代表是这个 y y y。 方法是要求 spring 容器从你这个容器当中去找一个 user d o 类型的病, 不仅仅是一个,有几个可以找几个, ok 吧。那找完之后把它扔到哪呢?就给我扔到这 这个对应的这个集合当中。例如集合内部要的就是 u z d o 类型的对象。好,那现在我去执行一下 对吧。看这个 y y 打印的。 y 打印的是外,是外表括号。那什么意思啊?代表它是这个集合是吧?只不过它现在集合只有几几个元素,只有一个元素 可以吧?你可以干一件事是吧?干什么事?把刚才这个 user d y p l 二把它干嘛?哎,把它给打开是吧?打开之后呢?我们再去对应的执行, 你会发现叉叉叉不变哎,说为什么叉叉没报错呢?因为叉叉刚我们讲过,他在根据类型进行注入时,他找容器当中有几个,一个直接注入就行了是吧? 如果有多个情况,他在二次去匹配谁匹配名字,你这名字是不是叫 you? 而我现在这个哪呢?哎,这个容器当中是不是有个名字叫 you 子 do 的,还有叫叫 userdo 二的,是不是这个一就匹配就 userdo 是匹配成功的,所以直接在这就住进去了对吧?而我这个地方是不是他要的是个 userdo 这个类型的是吧?你有几个?我说要几个是不都往这个集合扔?所以最终你发现一跟二干嘛? 这是不二吧。哎,这这个不太好看。这个是不二,这是不一,是不都被注入到这个集合当中的吧?哎,这个指示点是我给大家扩展的啊。

本期和大家聊一下如何用 reds 解决高并发抢购,我们来看看下面这个代码,当销量小于库存的时候就可以抢购,抢购后往 number 加一下,一个抢购就不能再进去买了。逻辑没什么问题,但是在我们连接数据库执行语句的时候,难免出现阻塞延迟, 当你订单并发小的时候看不出来,但是在抢购的时候,第一次抢购的还在查数据库还没返回抢购成功, redis 也还没有往库存上加一。可是已经有第二个抢购进来了,他也完全符合销量小于库存的判断,于是他也进入了抢购,那你一个库存就被抢购了两次。 这里我们加一个 sweep 来模拟数据固阻色,这样子就清楚很多。第一个还在抢购的时候,第二个五秒内就进来了,也完 全符合衣服判断。这个时候我们就可以利用 reds 做一个锁,大概逻辑如下,再看看代码如何实现锁, 这就是一个简单的防止抢购超卖的解决方法,如果对你有用的话,请关注一下吧! nice。