理解spring IOC 的使用和他的含义

springIOC

官方文档导航条
springbean注入官方文档官方文档
springbean构造方法注入官方文档
springbeanSet注入官方文档
自动注入的优点官方文档
自动注入的缺点官方文档
spring懒加载官方文档
springbean的作用域官方文档
关于spring单例bean依赖非单例bean引发问题的解决方法官方文档
spring的回调方法官方文档

用了这么久spring 到底什么是IOC?**

控制反转(Inversion of Control,缩写为IoC),是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度。其中最常见的方式叫做依赖注入(Dependency Injection,简称DI),还有一种方式叫“依赖查找”(Dependency Lookup)通俗点说就是 ioc是一种设计模式 而DI(依赖注入是这个模式的一种实现方式)

Dependency Injection(依赖注入)

依赖注入关于什么是依赖关于注入和查找以及拖拽

为什么要使用spring IOC?

在日常程序开发过程当中,我们推荐面向抽象编程,面向抽象编程会产生类的依赖,当然如果你够强大可以自己写一个管理的容器,但是既然spring以及实现了,并且spring如此优秀,我们仅仅需要学习spring框架便可。当我们有了一个管理对象的容器之后,类的产生过程也交给了容器,至于我们自己的app则可以不需要去关系这些对象的产生了。

spring实现IOC的思路和方法?

spring实现IOC的思路是提供一些配置信息用来描述类之间的依赖关系,然后由容器去解析这些配置信息,继而维护好对象之间的依赖关系,前提是对象之间的依赖关系必须在类中定义好,比如A.class中有一个B.class的属性,那么我们可以理解为A依赖了B。既然我们在类中已经定义了他们之间的依赖关系那么为什么还需要在配置文件中去描述和定义呢?spring实现IOC的思路大致可以拆分成3点

  1. 应用程序中提供类,提供依赖关系(属性或者构造方法)
  2. 把需要交给容器管理的对象通过配置信息告诉容器(xml、annotation,javaconfig)
  3. 把各个类之间的依赖关系通过配置信息告诉容器
    == 配置这些信息的方法有三种分别是xml,annotation和javaconfig维护的过程称为自动注入,自动注入的方法有两种构造方法和setter自动注入的值可以是对象,数组,map,list和常量比如字符串整形等==

spring编程的风格

schemal-based-------xml 配置文件的方式
annotation-based-----annotation 注解的方式 java-based----java
Configuration java配置类

注入的两种方法

官方文档关于spring注入 关于bean的操作都可以参考这里
以下示例显示了基于 XML 的配置元数据的基本结构:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="..." class="...">  
        <!-- collaborators and configuration for this bean go here -->
    </bean>

    <bean id="..." class="...">
        <!-- collaborators and configuration for this bean go here -->
    </bean>

    <!-- more bean definitions go here -->

</beans>

该id属性是一个字符串,用于标识单个 bean 定义。
该class属性定义 bean 的类型并使用完全限定的类名。

实例化一个容器

ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");

以下示例显示了服务层对象(services.xml)配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- services -->

    <bean id="petStore" class="org.springframework.samples.jpetstore.services.PetStoreServiceImpl">
        <property name="accountDao" ref="accountDao"/>
        <property name="itemDao" ref="itemDao"/>
        <!-- additional collaborators and configuration for this bean go here -->
    </bean>

    <!-- more bean definitions for services go here -->

</beans>

在前面的示例中,服务层由PetStoreServiceImpl类和两个类型JpaAccountDao和JpaItemDao(基于 JPA 对象-关系映射标准)的数据访问对象组成。该property name元素是指JavaBean属性的名称,以及ref元素指的是另一个bean定义的名称。id和ref元素之间的这种联系表达了协作对象之间的依赖关系。有关配置对象依赖项的详细信息通俗点说就是你的类有一个属性是另外一个对象 ref=“这个输定对应对象的实现类” 这样就能注入进去了

以下示例显示了数据访问对象daos.xml文件:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="accountDao"
        class="org.springframework.samples.jpetstore.dao.jpa.JpaAccountDao">
        <!-- additional collaborators and configuration for this bean go here -->
    </bean>

    <bean id="itemDao" class="org.springframework.samples.jpetstore.dao.jpa.JpaItemDao">
        <!-- additional collaborators and configuration for this bean go here -->
    </bean>

    <!-- more bean definitions for data access objects go here -->

</beans>

让 bean 定义跨越多个 XML 文件会很有用。通常,每个单独的 XML 配置文件都代表您架构中的一个逻辑层或模块。
您可以使用应用程序上下文构造函数从所有这些 XML 片段加载 bean 定义。该构造函数采用多个Resource位置,如上一节所示 。或者,使用元素的一个或多个实例从另一个文件或多个文件加载 bean 定义。以下示例显示了如何执行此操作:

<beans>
    <import resource="services.xml"/>   //导入一个xml文件 类似引入相当于这个文件类似html的导入
    <import resource="resources/messageSource.xml"/>
    <import resource="/resources/themeSource.xml"/>

    <bean id="bean1" class="..."/>
    <bean id="bean2" class="..."/>
</beans>

在前面的例子中,外部豆定义是从三个文件加载: services.xml,messageSource.xml,和themeSource.xml。所有位置路径都相对于执行导入的定义文件,因此services.xml必须与执行导入的文件位于同一目录或类路径位置, messageSource.xml并且themeSource.xml必须位于resources导入文件所在位置下方的位置。如您所见,前导斜杠被忽略。但是,鉴于这些路径是相对的,最好根本不使用斜杠。根据 Spring Schema,被导入文件的内容,包括顶级元素,必须是有效的 XML bean 定义。
以上翻译官方文档

Constructor-based Dependency Injection(基于构造函数注入)

基于构造函数注入bean官方文档
在这里插入图片描述

Setter-based Dependency Injection(基于 Setter 的依赖注入 )

基于set方法注入
在这里插入图片描述

自动装配

上面说过,IOC的注入有两个地方需要提供依赖关系,一是类的定义中,二是在spring的配置中需要去描述。自动装配则把第二个取消了,即我们仅仅需要在类中提供依赖,继而把对象交给容器管理即可完成注入。在实际开发中,描述类之间的依赖关系通常是大篇幅的,如果使用自动装配则省去了很多配置,并且如果对象的依赖发生更新我们可以不需要去更新配置,但是也带来了一定的缺点
自动装配的优点参考文档:
自动装配有点参考文档
缺点参考文档:
缺点参考文档

自动装配的方法

no 不自动装配
byName 根据名字自动装配
byType 根据类型自动装配
constructor
自动装配的方式参考文档:自动装配官方文档

spring懒加载

懒加载官方文档
默认情况下,ApplicationContext实现会在初始化过程中急切地创建和配置所有 单例bean。通常,这种预实例化是可取的,因为可以立即发现配置或周​​围环境中的错误,而不是在几小时甚至几天之后。当这种行为不可取时,您可以通过将 bean 定义标记为延迟初始化来防止单例 bean 的预实例化。一个延迟初始化的 bean 告诉 IoC 容器在它第一次被请求时创建一个 bean 实例,而不是在启动时。如果你想为所有的对都实现懒加载可以使用官网的配置
在 XML 中,此行为由 元素lazy-init上的属性控制,如以下示例所示:

<bean id="lazy" class="com.something.ExpensiveToCreateBean" lazy-init="true"/>
<bean name="not.lazy" class="com.something.AnotherBean"/>

springbean的作用域

springbean作用域官方文档

spirng的作用域参数

  • singleton : (默认)将单个 bean 定义范围限定为每个 Spring IoC 容器的单个对象实例。

  • prototype :将单个 bean 定义范围限定为任意数量的对象实例。

  • request : 将单个 bean 定义范围限定为单个 HTTP 请求的生命周期。也就是说,每个 HTTP 请求都有自己的 bean 实例,该 bean 实例是在单个 bean 定义的后面创建的。仅在 web-aware Spring 的上下文中有效ApplicationContext。

  • session : 将单个 bean 定义范围限定为 HTTP 的生命周期Session。仅在 web-aware Spring 的上下文中有效ApplicationContext。

  • application : 将单个 bean 定义范围限定为ServletContext. 仅在 web-aware Spring 的上下文中有效ApplicationContext。

  • websocket : 将单个 bean 定义范围限定为WebSocket. 仅在 web-aware Spring 的上下文中有效ApplicationContext。

<bean id="accountService" class="com.something.DefaultAccountService" scope="prototype"/>//scope可以替换为任何作用域参数例如:singleton 

request,session,application的解释

在request,session,application,和websocket范围只有当你使用一个基于web的Spring可ApplicationContext实现(例如 XmlWebApplicationContext)。如果将这些作用域与常规 Spring IoC 容器(例如 )一起使用ClassPathXmlApplicationContext,IllegalStateException则会抛出抱怨未知 bean 作用域的 。

<bean id="loginAction" class="com.something.LoginAction" scope="request"/>

Spring 容器LoginAction通过loginAction对每个 HTTP 请求使用bean 定义来创建bean 的新实例。也就是说, loginActionbean 的范围在 HTTP 请求级别。您可以根据需要更改所创建实例的内部状态,因为从同一loginActionbean 定义创建的其他实例看不到这些状态更改。它们是针对个人要求的。== 当请求完成处理时,该请求范围内的 bean 将被丢弃。通俗点说就是一个请求进来就是根据repuest参数来赋值生成==
当使用注解驱动的组件或 Java 配置时,@RequestScope注解可用于将组件分配给request作用域。以下示例显示了如何执行此操作:

@RequestScope
@Component
public class LoginAction {
    // ...
}

Singleton Beans with Prototype-bean Dependencies

当我们的bean为单例的 但是他的依赖为非单例这个时候就会引起单例的bean只会调用一次依赖导致 非单例的依赖bean也为单例
解决办法
解决bean为单例依赖为非单例的官方文档

public abstract class CommandManager {

    public Object process(Object commandState) {
        MyCommand command = createCommand();
        command.setState(commandState);
        return command.execute();
    }

    @Lookup
    protected abstract MyCommand createCommand();
}

spring声明周期和回调

spring的生命周期官方文档
要与容器对 bean 生命周期的管理进行交互,您可以实现 SpringInitializingBean和DisposableBean接口。容器要求 afterPropertiesSet()前者和destroy()后者让 bean 在初始化和销毁​​ bean 时执行某些操作。

Guess you like

Origin blog.csdn.net/weixin_43979902/article/details/120187794