三层架构¶
由于单一职责原则,这里把三个职责集中在一起,是不合适的.
三层架构:
三层架构依次调用

统一接口¶
DAO并不总是从文件访问数据,还可能从数据库 网络访问.因此,会有很多DAO层.
我们一般会给所有DAO层提供同一的访问接口.即面向接口编程.
service层一般也同理.
我们的架构变成了这样
其中,dao层提供统一的接口UserDao,而UserDaoImpl是一个实现类.
tip:这里包名的命名impl 实现类的命名UserDaoImpl都是固定的规范.
service同理

把SpringbootDemo1当中的代码抽取出来:
注意了,这里我们发现lines需要从dao中获取,因此我们需要有一个dao成员.这个成员类型应该是接口类型,这样可以利用多态.
最后:

高内聚低耦合 IOC&DI¶
最好能解耦.刚才的代码耦合关联度还是太高了 刚才层与层都是通过写死成员来关联的.这很不好. 我们可以创建一个容器.把一个UserServiceImpl对象放到一个容器中,让UserController从容器当中获得对象. 这样,如果我们想修改UserCOntroller选取的Service,UserController本身的代码不用动.
如何把UserService放到容器中 -- 控制反转
如何让UserController获得容器中的数据 -- 依赖注入
IOC是Spring的第一大核心.IOC容器也叫Spring容器
为什么叫控制反转?之前,应该是service自己创建对象,放到容器里,控制权在service里.现在控制权反过来了.
为什么叫依赖注入?以前是固定写死了Controller依赖于某个Service,现在的依赖则是我们注入的.
代码实现¶
加上Component注解之后:就会把这个类交给IOC管理
加上autowired之后,在运行时,程序会自动从容器中查询找到该类型的Bean对象,并且赋值给这个成员

IOC使用细节¶
下面三个是对coomponent的封装,也就是包含了Component.
常见的工具类配置类不能归属于这三层架构,因此还是会使用Component
代码¶
点开看一下,可见就是封装:
Controller其实不用专门加,因为restController已经依赖了Controller了.
一些问题:
而Service和repository可以被component替代.但建议还是写明.
如果后面用来mabatis这样的框架,那么就不用repository了.(后面再说)
细节¶
bean的名字¶
IOC中如何区分每个bean?其实每个bean都有它的名字.默认的名字就是类名首字母小写.
控制台中通过actuator监控就能看到我们定义的bean
我们也可以指定名字:
这个value就表示有一个属性value,添加属性就能重命名:
但通常我们不会指定名字.
组件扫描¶
组件扫描要扫描到四大注解才能正确生效.
如果没有扫描到,会在控制台报错.
DI细节¶
三种方式¶
userService是一个属性.因此这叫属性注入.
也叫构造器注入.成员变量一般被final修饰,表示不可变.
如果当前类的构造函数只有构造器一个,那么autowired也可以省略.
这样写之后,类创建对象时,会自动调用setter方法,来进行初始化.
事实上,本质就是需要时会自动把bean对象赋值给成员/传给构造函数/传给setter
优缺点¶
属性注入¶
因为对于外界来看,由于没有getset方法,那么就根本不知道Controller依赖了Service.(而后两者都可以从public的方法的参数获知有这层依赖关系)
另外,由于没有getset方法,实际上底层是通过反射来给userService赋值的,这破坏了封装性.
构造器注入¶
由于有final,故比较安全.
setter注入¶

官网推荐使用构造器输入,但是真实企业开发中往往用属性注入.
按类型注入¶
也就是说,autoWired会默认到IOC中查找类型为UserService的bean来进行注入,它的依据是类型,所以说叫"按类型注入"
那么:
如果符合条件的bean有多个怎么办?¶
比如我实现了多个Service类:
新建一个Service2类:
会发现报错:
因此结论是会多个报错.
如何处理?¶
primary:指定哪个类优先
qualifier/resource:指定用哪个类注入.
注意,这两个要写的不是类名,而是bean的名字.
tip:注解的顺序不影响,即autowired和qualifier哪个在上不重要.
resource不是Spring提供的,而是javaee规范中提供的.
