spring控制反转ioc
在项目中,常用mvc设计模式来解耦。
mvc:模型Model,视图View,控制器Controller
视图负责页面的显示,与用户的交互。
控制器负责将视图与模型一一对应起来。相当于一个模型分发器。所谓分发就是:①接收请求,并将该请求跳转(转发,重定向)到模型进行处理。②模型处理完毕后,再通过控制器,返回给视图中的请求处。一般使用Servlet实现控制器。
模型负责实现功能,简单理解为javabean
三层架构:一种用于解耦合提升代码复用率的软件架构。可以分为表现层,业务逻辑层(service),数据访问层(dao),最后加上实体类库。


但某些代码里,ui调用业务层,业务层又调用持久层。层层调用下来导致耦合度非常高


解决办法:使用工厂模式创建bean对象
bean:可重用组件,比如一个service可以被很多serverlet使用,一个dao可以被很多service使用
javabean:很容易简单理解成实体类,但实际上概念远大于实体类。用java编写的可重用组件都是javabean。
所以该工厂就是用来创建我们的service和dao对象。
如何创建?
1,需要一个配置文件来配置service和dao
配置文件内容:唯一表示=全限定类名(key = value的形式)
2,通过读取配置文件中配置的内容,反射创建bean对象





此时若是少了实现类,不会引起编译期异常,而是转换成运行期异常。

但上述工厂模式解耦依然存在一些问题,如果连续打印五次service实现类,会发现这五个实现类都有不同的内存地址,为五个不同的实现类

但此处不需要用多例模式,多个实现类的生成,是因为用了newInstance;这段代码每次都会调用默认构造函数创建对象。
调整方法:只使用newInstance一次创建对象,再马上存起来,这就需要一个容器。
创建容器的过程:于是定义一个map,用于存放创建的对象→实例化容器→取出配置文件中所有的key→根据key获取value→反射创建对象

控制反转(inversion of control),把创建对象的权力交给框架。
使用spring的ioc解决程序的耦合。


ApplicationContext就是spring的核心容器对象,有三个常用实现类:
ClassPathXmlApplicationContext:它可以加载类路径下的配置文件,要求配置文件必须在类路径下,否则无法加载
FileSystemXmlApplicationContext:可以加载磁盘任意路径下的配置文件(必须有访问权限)
AnnotationConfigApplicationContext:用于读取注解创建容器
核心容器的两个接口引发出的问题:
ApplicationContext:它在构建核心容器时,它创建对象时的策略是立即加载,即只要一读取完配置文件,马上创建配置文件中配置的对象。(单例对象适用)
在说工厂模式解耦时,说过我们的service也好dao也好,都是没有类成员的,所以没有线程安全问题。所以我们可以直接使用单例模式,创建service和dao。又因为service和dao都是单例的,所以倾向于用ApplicationContext马上创建对象,创建一次就再也不用创建了。
BeanFactory:它在构建核心容器时,采取延迟加载的方式。当什么时候根据id获取对象了,什么时候才真正的创建对象。
什么时候用,什么时候创建,适合多例模式。
BeanFactory是一个顶层接口,功能不够完善,实际开发中更多使用它的子接口或者ApplicationContext

<把对象的创建交给spring管理>
spring对bean的管理细节:
1创建bean的三种方式:
第一种:使用默认构造函数创建
在spring的配置文件中使用bean标签,配以id和class属性,且没有其他属性和标签时,采用的就是默认的构造函数创建bean对象。如果类中没有默认构造函数,则对象无法创建
第二种:使用普通工厂中的方法创建对象(使用某个类中的方法创建对象,并存入spring容器)实现代码如下:
<bean id = "instanceFactory" class="com.itheima.Factory.InstanceFactory"></bean>
<bean id = "accountService" factory-bean="instanceFactory" factory-method="getAccountService"></bean>
有了instanceFactory,他是一个工厂,可以为我们创建对象。我们就是要用它里面的方法去创建,这是时候需要定义一个service,等下可以用id取出
,这个service对象是怎么来的?是通过id所指向的工厂-bean对象里面的工厂-method方法来获得的。
第三种:使用工厂中的静态方法创建对象(使用某个类中的静态方法创建对象,并存入spring容器)
<bean id="accountService" class="com.itheima.factory.StaticFactory" factory-method="getAccountService> </bean>
2bean对象的作用范围
bean标签的scope属性:
作用:用于指定bean的作用范围
取值:常用前两个单例和多例的
singleton:单例(默认值)
prototype:多例
request:作用于web应用的请求范围
session:作用于web应用的会话范围
global-session:作用于集群环境的会话范围(全局会话范围),当不是集群环境时,他就是session
3bean对象的生命周期
单例:
出生:容器创建时对象出生
活着:容器还在,对象就活着
死亡:容器被销毁,对象消亡
故可以说对象的生命周期和容器相同
多例:
出生:使用对象时,spring框架会创建
活着:使用过程中对象一直活着
死亡:长时间不用且没有别的对象引用,由java的垃圾回收机制回收

spring中的依赖注入dependency injection
依赖注入能注入的数据类型有三类:
1基本类型和string
2其他bean类型(在配置文件中或者注解配置过的bean)
3复杂类型,也叫集合类型
注入的方式也有三种:
1使用构造函数提供:

使用的标签constructor-arg,标签位于bean标签的内部,里面的属性有type,index,name,这三个用于指定给构造函数中的某个参数赋值。value用于提供基本类型和string类型的数据,ref用于指定其他的bean类数据(指的是核心容器中出现过的bean)。所以只要是xml配置过的或者注解配置过的,都能引用

可以用now这个id取出来,接收则不能用value,需要用到ref
优势:获取bean对象时,注入数据是必须的操作,否则对象无法创建成功,这就更不易被遗忘忽略
弊端:改变了bean对象的实例化方式,使创建对象时就算用不到这些数据,也必须提供
2使用set方法提供:

涉及的标签:property,出现的位置:bean内部
标签的属性只有name,value,ref。name用于指定注入时所调用的set方法名称。value:基本类型数据和string。ref:指定其他的bena类型数据
注:property标签里面的属性名并不管你定义的变量名,而是关心set方法叫什么名称,去掉set把首字母变小写
优势:创建对象没有明确限制,可以直接使用默认构造函数
弊端:如果某个成员变量必须有值,则获取对象时有可能set方法没有执行
3使用注解提供:下一节
============================
关于集合类型数据的注入

用于给List结构集合注入的标签:list,array,set
用于给Map结构集合注入的标签:map,props
结构相同可以互换