欢迎光临散文网 会员登陆 & 注册

spring控制反转ioc

2021-03-02 23:10 作者:世界永不足够  | 我要投稿

在项目中,常用mvc设计模式来解耦

mvc:模型Model视图View,控制器Controller

视图负责页面的显示,与用户的交互。

控制器负责将视图与模型一一对应起来。相当于一个模型分发器。所谓分发就是:①接收请求,并将该请求跳转(转发,重定向)到模型进行处理。②模型处理完毕后,再通过控制器,返回给视图中的请求处。一般使用Servlet实现控制器。

模型负责实现功能,简单理解为javabean

三层架构:一种用于解耦合提升代码复用率的软件架构。可以分为表现层,业务逻辑层(service),数据访问层(dao),最后加上实体类库。

mvc和三层架构的对应关系

 

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

解决办法:使用工厂模式创建bean对象

    bean:可重用组件,比如一个service可以被很多serverlet使用,一个dao可以被很多service使用

    javabean:很容易简单理解成实体类,但实际上概念远大于实体类。用java编写的可重用组件都是javabean。

所以该工厂就是用来创建我们的service和dao对象。

如何创建?

    1,需要一个配置文件来配置service和dao

        配置文件内容:唯一表示=全限定类名(key = value的形式)

    2,通过读取配置文件中配置的内容,反射创建bean对象

配置文件可以是xml也可以是properties,此处是properties
类加载器动态获取文件
优化解耦后变成了依赖配置文件

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

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

但此处不需要用多例模式,多个实现类的生成,是因为用了newInstance;这段代码每次都会调用默认构造函数创建对象。

调整方法:只使用newInstance一次创建对象,再马上存起来,这就需要一个容器。

创建容器的过程:于是定义一个map,用于存放创建的对象→实例化容器→取出配置文件中所有的key→根据key获取value→反射创建对象

控制反转(inversion of control),把创建对象的权力交给框架。

使用spring的ioc解决程序的耦合。

id唯一标志,class全限定类名
两种方法都可以获取bean对象,第一种强转,第二章字节码文件

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配置过的或者注解配置过的,都能引用

spring读取了class的全限定类名,反射创建对象存入核心容器

可以用now这个id取出来,接收则不能用value,需要用到ref

优势:获取bean对象时,注入数据是必须的操作,否则对象无法创建成功,这就更不易被遗忘忽略

弊端:改变了bean对象的实例化方式,使创建对象时就算用不到这些数据,也必须提供


2使用set方法提供:

注入只需要set方法,不需要get

涉及的标签:property,出现的位置:bean内部

标签的属性只有name,value,ref。name用于指定注入时所调用的set方法名称。value:基本类型数据和string。ref:指定其他的bena类型数据

注:property标签里面的属性名并不管你定义的变量名,而是关心set方法叫什么名称,去掉set把首字母变小写

优势:创建对象没有明确限制,可以直接使用默认构造函数

弊端:如果某个成员变量必须有值,则获取对象时有可能set方法没有执行

3使用注解提供:下一节

============================

关于集合类型数据的注入

同样用set方法注入,但不能在property标签里面用value和ref

用于给List结构集合注入的标签:list,array,set

用于给Map结构集合注入的标签:map,props

结构相同可以互换

spring控制反转ioc的评论 (共 条)

分享到微博请遵守国家法律