对 Spring IOC 机制及其配置方式的的总结

用通俗易懂的语言解释IOC 目录 一、从Spring到IOC 二、初识IOC(对比新建一个对象三种方式——新建方式、工厂方式、依赖注入) 2.1 新建方式 2.2 工厂方式 2.3Spring依赖注入 2.4 Spring相关问题 三、IOC原理——关于Spring容器是如何完成依赖注入的整个过程的 四、IOC进阶——ref的使用 五、Spring的另一种配置方式——注解配置(从xml配置到注解配置) ... 阅读详情

1、Spring Ioc 的基本原理:BeanFactory

Spring Ioc 容器的代表就是 BeanFactory 接口,它其中定义了一些获取 Bean 的方法 getBean()。ApplicationContext 接口扩展了 BeanFactory,还提供了与 Spring AOP 集成、国际化处理、事件传播及提供不同层次的 context 实现。我们可以从 BeanFactory 和 ApplicationContext 任选一个来使用,但是 BeanFactory 过于低级,所以 ApplicationContext 用得更加广泛。

ApplicationContext 有多个具体的实现,以供我们从不同类型的配置文件中获取 Bean 实例。以下是比较常用的一些:

  1. AnnotationConfigApplicationContext:从一个或多个基于 Java 的配置类中加载应用上下文
  2. AnnotationConfigWebContextLoader:从一个或多个基于 Java 配置类中加载 Web 应用上下文
  3. ClassPathXmlApplicationContext:从类路径下面一个或多个配置文件中加载上下文
  4. FileSystemXmlApplicationContext:从文件系统中的一个或多个配置文件中加载上下文
  5. 其他……

以 AnnotationConfigApplicationContext 为例,其继承关系如下:

AnnotationConfigApplicationContext 继承关系

当获取到了 ApplicationContext 之后,我们就可以使用它来获取 Bean 实例。ApplicationContext 从 BeanFactory 继承了一系列方法用来获取 Bean 实例:

    Object getBean(String var1) throws BeansException;
    <T> T getBean(Class<T> var1) throws BeansException;
    <T> Map<String, T> getBeansOfType(Class<T> var1) throws BeansException;

这里我们给的是三种基本的方法,它们还有一些多态的方法。与其区别仅在于,增加了一些可选的参数。

以 AnnotationConfigApplicationContext 的使用为例。我们只需要使用注解指定一个配置类,并通过注解指定扫描的包的地址,然后系统会自动对包进行扫描,装载 Bean 并进行管理,

    @Configurable
    @ComponentScan(value = "me.shouheng.spring.componentscan")
    public class ComponentScanConfiguration {
    }

然后,我们就可以获取 AnnotationConfigApplicationContext 实例,并从中来获取系统管理的 Bean 了,

    public static void main(String...args) {
        // 指定 Spring 容器的配置类为 ComponentScanConfiguration
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ComponentScanConfiguration.class);
        // 通过 Bean 类的 Class 类型获取 Bean 实例
        FirstBean firstBean = context.getBean(FirstBean.class);
        firstBean.say();
    }

当然,自定了扫描的包之后,我们还需要通过注解来指定哪些类是我们的 Bean 实例,以及它们在 Spring 容器中的表现,比如单例还是每次实例化一个实例等等,稍后我们会对其进行总结。

除了使用 Java 类和注解,我们还可以在 XML 中配置 Spring 容器。在早期的 Spring 版本中,这是比较常用的一种配置方式。它的实现方式也很简单,即使用 ClassPathXmlApplicationContext 类,通过构造方法指定 XML 配置文件的路径,拿到了 ClassPathXmlApplicationContext 实例之后,用它的方法获取 Bean 即可,

    public static void main(String...args) {
        // 系统会到 resources 目录下面的 componentscan 目录下面的 ComponentScan.xml 文件中寻找 Bean 实例
        ApplicationContext context = new ClassPathXmlApplicationContext("componentscan/ComponentScan.xml");
        // 通过 Bean 类的 Class 类型获取 Bean 实例
        FirstBean firstBean = context.getBean(FirstBean.class);
        firstBean.say();
    }

上面是 Spring 的容器作用的基本原理,即指定了扫描的路径之后,Spring 容器会对路径自动扫描,装载 Bean,然后自动对其进行管理。显然,相对于我们显式地进行管理,它使用起来更加方便。不过,上面是它作用的基本原理。Spring 容器理解起来并不难,只是它的各种配置方式比较灵活,需要整理下才能更好的掌握。下面我们对 Spring 的常用的配置方式进行总结。

2、Spring Ioc 的配置

如上所述,早期的 Spring 通过 XML 配置的方式比较多,后来则提出了通过注解和 Java 类来进行配置的方式。下面我们来对两种配置方式进行梳理。

2.1 Xml 配置的结构

当我们使用 XML 来配置 Bean 的时候,其基本的格式如下(这里我们省略了命名空间的声明):

    <beans xmlns=...>
        <import resource="../hello/HelloWorld.xml"/>
        <bean id="universal" class="me.shouheng.spring.universal.UniversalBean"/>
        <alias name="universal" alias="my_universal"/>
    </beans>

在 XML 中主要下面几种类型标签供我们使用:

  1. import:用于导入其他的 XML 配置文件,这样就可以让我们对配置文件进行功能分类;
  2. bean:用来声明 Bean;
  3. alias:用来为一个 Bean 起一个别名;
  4. beans:beans 根标签中还可以加入 beans 子标签;
  5. description:文件描述

注:可以在 IDEA 中通过点击标签或者标签的属性进入到 spring-beans.xml 中查看各个标签的定义和解释。

2.1.1 beans 标签

beans 标签中有几个属性需要注意下,

属性取值范围说明
profile字符串可类型用来快速切换 beans 环境,比如生成环境和开发测试环境等
default-lazy-init取值范围为 defaul, true 和 false同 bean 标签的 lazy-init 属性含义相同,即延迟初始化,表示只有在用到的时候才会被初始化,默认为 default,即继承外部 beans 的属性,否则为 false
default-autowire取值范围为 defaul, no, byName, byType 和 constructor同 bean 标签的 autowire 属性含义相同,即表示自动注入的方式。默认值为 default,即继承外部 beans 的属性,否则使用 no.
default-autowire-candidates字符串类型同 bean 标签的 autowire-candidate 属性,通过名称样式匹配注入的对象,比如 “Service", "data” 等。
default-init-method字符串类型同 bean 标签的 init-method 属性,接收字符串类型。可以写入 Bean 的方法名称,当该 beans 标签中的任何 bean 被创建的时候,都会调用该方法。
default-destroy-method字符串类型同 bean 标签的 destroy-method 属性,接收字符串类型。可以指定 Bean 的方法名称,当该 beans 标签中的任何 bean 被销毁的时候,都会调用该方法。

特别说明:

1. profile 属性的特别说明

profile 属性用来快速切换 beans 环境,比如生成环境和开发测试环境等。使用方式是在 XML 配置文件中的末尾处通过如下方式添加如下代码:

    <beans profile="dev">
        <context:component-scan base-package="me.shouheng.spring.componentscan"/>
    </beans>
    <beans profile="dev2">
        <context:component-scan base-package="me.shouheng.spring.componentscan2"/>
    </beans>

激活配置的方式有以下几种:

  1. 在 web.xml 中通过 context-param 指定,注意这里定义的是 default 值,在非生产环境,可以用系统变量 spring.profiles.active 进行覆盖:
<context-param>
    <param-name>spring.profiles.default</param-name>
    <param-value>production</param-value>
</context-param>
  1. 启动 main 方法的时候在 Run Configuration 中通过修改虚拟机参数 VM Options 进行修改。比如 -Dspring.profiles.active="dev2"

  2. 单元测试的时候通过注解 @ActiveProfiles("dev2") 来指定。

2.1.2 import 标签

import 标签可以指定多种数据源的配置文件,常用的如下,包括 class 路径、resource 目录下的 xml 中,文件系统和网络:

    <beans xmlns=...>
        <import resource="classpath:"/>
        <import resource="classpath*:"/>
        <import resource="DiConfig.xml"/>
        <import resource="file:"/>
        <import resource="http:"/>
    </beans>

这里 classpath 和 classpath* 的区别是:classpath 只会到你的 class 路径中查找找文件;而 classpath* 不仅包含 class 路径,还要到 jar 文件中(class 路径)进行查找。可以在 classpath 路径上使用通配符 * 进行模糊查找,比如 classpath:applicationContext-*.xml。

2.1.3 alias 标签

用来为 bean 指定别名,接收两个参数,一个是 name,即 bean 原来的名称;一个是 alisa,即 bean 的新的别名。

    <bean id="hello" class="me.shouheng.spring.hello.beanimp.HelloApiImpl"/>
    <alias name="hello" alias="h"/>
2.1.4 bean 标签

bean 标签用来指定我们的 bean 实例的构造方式,用来为 bean 的属性赋值等等。它的属性和子元素比较多,可以通过 spring-bases.xml 中的 beansAttributes 和 beanElements 两个分组来查看。

1. bean 标签的属性

属性名称类型和取值范围说明
id字符串类型bean 的唯一的 id,同一 beans 标签中同一 id 不可以被多次使用
name字符串类型用来指定 bean 的名称,多个 name 之间使用 ,, ; 或者 分割
class字符串类型用来指定 bean 的类型,除非该 bean 只作为其他 bean 的父 bean 使用
parent字符串类型用来指定父 bean 的 name
scope字符串类型,取值 request, session, prototype 和 singleton用来表示 bean 以何种方式创建,以及生命周期。
abstract布尔类型默认 false,用来指定该 bean 是否作为其他的 bean 的父 bean 使用。如果使 true,那么这种 bean 不会被初始化。
lazy-init取值范围为 defaul, true 和 false延迟初始化,表示只有在用到的时候才会被初始化,默认为 default,即继承外部 beans 的属性,否则为 false。
autowire取值范围为 defaul, no, byName, byType 和 constructor表示自动注入的方式,默认值为 default,即继承外部 beans 的属性,否则使用 no.
depends-on字符串类型对两个 Bean,A 和 B,若在 A 的配置中设置它的 depends-on 属性为 B,那么 A 会在 B 初始化完成之后再被创建,而 B 要等到 A 销毁了之后才能被销毁
autowire-candidate
primary布尔类型
init-method字符串类型可以写入 Bean 的方法名称,当该 beans 标签中的任何 bean 被创建的时候,都会调用该方法。
destroy-method字符串类型可以指定 Bean 的方法名称,当该 beans 标签中的任何 bean 被销毁的时候,都会调用该方法。
factory-method字符串类型与 factory-bean 属性配合使用。系统创建 Bean 的时候,使用 factory-bean 指定的工厂 Bean 和 factory-method 指定工厂方法创建该 Bean 实例
factory-bean字符串类型见 factory-method 属性

2. Bean 标签属性的特别说明

  1. scope 属性的四个取值的说明

    1. singleton 表示单例作用域,每个容器中只会存在一个实例,而且其完整生命周期完全由 Spring 容器管理。默认就是单例的。如果 Bean 是延迟初始化的,那么该 Bean 会在首次使用的时候创建并放在单例缓存池中。
    2. prototype 表示原型,每次向容器请求获取 Bean 都返回一个全新的 Bean,即每次都创建的全新 Bean。
    3. request 表示每个请求需要容器创建一个全新 Bean。比如提交表单的数据必须是对每次请求新建一个 Bean 来保持这些表单数据,请求结束释放这些数据。
    4. session 作用域表示每个会话需要容器创建一个全新 Bean。比如对于每个用户一般会有一个会话,该用户的用户信息需要存储到会话中,此时可以将该 Bean 配置为 web 作用域。
  2. 延迟初始化 lazy-init:

    1. 延迟初始化适用于可能需要加载很大资源,而且很可能在整个应用程序生命周期中很可能使用不到的 Bean。
    2. 在 <beans> 标签中通过制定 default-lazy-init="true" 可以将内部全部 bean 延迟初始化。
  3. init-method和destroy-method:在 Bean 标签中通过这 init-method 和 destroy-method 分别指定初始化时和销毁时调用的方法。

    1. init-method:指定初始化方法,在构造器注入和 setter 注入完毕后执行;
    2. destroy-method:指定销毁方法,只有 singleton 作用域能销毁,prototype 作用域的一定不能,其他作用域不一定能;
    3. 可以使用 @PostConstruct 和 @PreDestroy 注解标记指定的方法来实现生命周期回调,要使用这种方式还要在 XML 中加入 <context:annnotation-config> 标签,或者使用 <context:component-scan/>;
    4. 实现生命周期的第三种选择是实现 InitializingBean 和 DisposableBean 接口。
  4. 自动装配属性 autowire:自动装配就是指由 Spring 来自动地注入依赖对象,无需人工参与。Spring 支持 no、byName、byType、constructor 和 default 5 种自动装配,默认是 no 指不支持自动装配。byName 表示按照名称装配,byType 表示按照类型自动装配,constructor 也是按照类型来装配的,只是用于构造器注入方式。我们来总结一下自动装配相关的内容:

    1. 不是所有类型都能自动装配,Object、基本数据类型等无法自动装配;
    2. 数组、集合、字典类型的根据类型自动装配和普通类型的自动装配是有区别的,它们需要根据泛型信息注入;
    3. 自动装配的缺点就是没有了配置,在查找注入错误时非常麻烦,还有比如基本类型没法完成自动装配,所以可能经常发生一些莫名其妙的错误;
    4. 自动装配注入和配置注入同时存在时,配置注入的数据会覆盖自动装配注入的数据;
    5. 自动装配要求被装配的 Bean 中的对象实例有 Setter 方法。
    6. 下面是自动装配的一个示例:

我们定义如下的 FirstBean,它其中有一个 SecondBean 类型的实例字段,并且有一个 Setter 方法:

public class FirstBean {
    
    private SecondBean secondBean;
    
    public void setSecondBean(SecondBean secondBean) {
        this.secondBean = secondBean;
    }
}

那么,我们按照如下的方式进行自动装配:

    <bean name="firstBean" class="me.shouheng.spring.autowire.FirstBean" autowire="byName"/>
    <bean name="secondBean" class="me.shouheng.spring.autowire.SecondBean" />

3. bean 标签的子元素

这里的标签主要有:meta、constructor-arg、qualifier、lookup-method 和 replaced-method。

  • meta 标签:用来给 Bean 添加一个任意的 Metadata 信息,以键值对的形式;

  • constructor-arg 标签:用来通过构造函数注入属性值,以创建 Bean 实例。它可以包含的属性包括

    • index 属性:字符串类型,用来指定当前参数在构造函数的参数列表中的位置,以放在当构造函数参数列表中存在两个相同类型参数的情形
    • type 属性:字符串类型,用来指定当前构造函数的参数的类型。
    • name 属性:字符串类型,用来指定当前构造函数的参数的名称。
    • ref 属性:字符串类型,用来指示当前的参数所引用的 bean,也可以通过 <ref bean='...'/> 形式指定。
    • value 属性:字符串类型,用来指示当前的参数引用的值,也可以通过 <value>...<value/> 形式指定。

下面是一个使用实例,

    <!-- 使用属性进行赋值 -->
    <bean id="universal2" class="me.shouheng.spring.universal.UniversalBean">
        <constructor-arg name="hiTo" value="Spring"/>
    </bean>
    <!-- 或者使用下面这种方式 -->
    <bean id="hello" class="me.shouheng.spring.hello.beanimp.HelloApiImpl">
        <constructor-arg name="value">
            <value>My simple value.</value>
        </constructor-arg>
    </bean>

显然,constructor-arg 标签的 index, type 和 name 属性用来指定当前的参数是构造函数中的哪一个。而 ref 和 value 用来指定当前参数的值。ref 和 value 只是ref 和 value 标签的一个补充。除了使用属性来直指定,我们还可以使用更加强大的子标签的形式来为构造函数的参数赋值。它的子标签包括 bean, ref, idref, value, null, array, list, set, map 和 props,分别对应各种不同的数据类型。它们与 property 标签支持的类型基本一致,稍后我们会进行说明。

  • property 标签:用来对类的属性进行注入,这要求该类提供了该属性的 setter 方法。它提供的属性包括:
    • name 属性:字符串类型,用来指定当前构造函数的参数的名称。
    • ref 属性:字符串类型,用来指示当前属性所引用的 bean,也可以通过 <ref bean='...'/> 形式指定。
    • value 属性:字符串类型,用来指示属性的值,也可以通过 <value>...<value/> 形式指定。

显然,name 用来指定当前属性的名称,ref 和 value 用来指定属性的值。此外,还可以通过使用子元素来指定属性的值。它在 constructor-arg 标签支持的子元素的基础上增加了 meta 标签。稍后我们会进行说明。

  • qualifier 标签:即限定描述符,用于细粒度选择候选者。它有两个子标签,type 和 value 分别用来指定候选的 Bean 的类型和值。

  • lookup-method 标签:它只有两个标签 name 和 bean。用来使容器覆写指定的方法,并将 bean 属性指定的 bean 作为结果返回。比如

public interface Boss {
    Car haveCar();
}
<bean id="bmw" class="org.hope.spring.bean.lookup.Car" p:brand="奔驰GLC260" />
<bean id="boss" class="org.hope.spring.bean.lookup.Boss">
    <lookup-method name="haveCar" bean="bmw"/>
</bean>

此时使用 boss 实例的时候,调用 haveCar 方法将返回 bwm 对应的 bean。

  • replaced-method 标签:与上面的标签类似,只是用来替换 bean 中的某个方法。比如下面的实例中,用来将 yiJianLian 中的 onPlace() 方法替换为 yao。这里的 yao 不是一个普通的类,它需要实现 MethodReplacer 接口,其实就类似于代理模式的应用。
<bean id="yao" class="org.hope.spring.bean.replacedmethod.Yao">
</bean>
<bean id="yiJianLian" class="org.hope.spring.bean.replacedmethod.YiJianLian">
     <replaced-method name="onPlace" replacer="yao"/>
</bean>

4. 赋值标签

这里我们来梳理下上面提到的一系列的赋值标签:bean, ref, idref, value, null, array, list, set, map 和 props。下面是一个基本的数据类型注入的例子,

    <bean id="hello" class="me.shouheng.spring.hello.beanimp.HelloApiImpl">
        <!-- 注入普通的字符串类型 -->
        <property name="string">
            <value>Simple String</value>
        </property>
        <!-- 注入数组类型 -->
        <property name="stringArray">
            <array value-type="java.lang.String">
                <value>1</value>
                <value>2</value>
                <value>3</value>
            </array>
        </property>
        <!-- 注入列表类型 -->
        <property name="stringList">
            <list value-type="java.lang.String">
                <value>1</value>
                <value>2</value>
                <value>3</value>
            </list>
        </property>
        <!-- 注入集合类型 -->
        <property name="stringSet">
            <set value-type="java.lang.String">
                <value>1</value>
                <value>2</value>
                <value>1</value>
            </set>
        </property>
        <!-- 注入哈希类型 -->
        <property name="stringMap">
            <map>
                <entry value-type="java.lang.String" value="1" key="1"/>
                <entry key="2" value="2"/>
            </map>
        </property>
    </bean>

2.2 XML 配置方式总结

2.2.1 获取 bean 实例的几种方式
  1. 通过 <bean> 标签和 constructor-arg 或者 propertry 标签初始化 bean;

  2. 通过通过静态工厂方法获取实例,即只通过 factory-method 指定。比如下面的例子中,这里要求 UniversalBean 类中包含一个静态的 staticFactory 工厂方法,并且工厂方法的参数是 hiTo1 和 hiTo2:

    <bean id="universal4" class="me.shouheng.spring.universal.UniversalBean" factory-method="staticFactory">
        <constructor-arg name="hiTo1" value="Spring"/>
        <constructor-arg name="hiTo2" value="Winter"/>
    </bean>
    
  3. 通过实例工厂方法获取实例:需要同时使用 factory-bean 和 factory-method 标签。以下面的程序为例,此时 FactoryBean 实例方法 factory 中包含两个参数 hiTo1 和 hiTo2:

    <bean id="factory" class="me.shouheng.spring.universal.FactoryBean"/>
    <bean id="universal5" factory-bean="factory" factory-method="factory">
        <constructor-arg name="hiTo1" value="Spring"/>
        <constructor-arg name="hiTo2" value="Winter"/>
    </bean>
    
2.2.2 p 命名空间

可以使用 p 命名空间来简化 setter 注入,比如上面的 refBean 可以使用如下的方式进行简化:

    <bean id="refBean" class="me.shouheng.spring.di.RefBean" p:diBean-ref="di"/>

注意这里需要引用 p 命名空间:

    xmlns:p="http://www.springframework.org/schema/p"

它的规则其实就是 p:字段名="值",如是字段是引用类型,那么就是 p:字段名-ref= “Bean 的 id”。

2.2.3 循环依赖

所谓的循环依赖就是:A 创建的时候需要使用 B,B 需要用到 C,而 C 又要用到 A。按照注入的方式不同又分成:构造器循环依赖 和 setter 方法循环依赖。构造器循环依赖表示 Bean 在创建的时候依赖于其他的 Bean 而造成的循环依赖,此种循环依赖无解,只能通过抛出 BeanCurrentlyInCreationException 异常表示循环依赖。对于 setter 方法循环依赖又分成两种情形:单例作用域的循环依赖 和 prototype 作用域的循环依赖。前者是可以解决的,而后者无法解决。因为单例作用域的 Bean 在创建之后会被放在 Bean 创建池中待用,而 prototype 作用域的 Bean 不会被 Spring 容器缓存,无法提前暴露创建完毕的 Bean。

2.3 自动装配

2.3.1 基于 XML 的自动装配

所谓的自动装配,在 XML 中,就是指通过 XML 指定扫描的包之后,Spring 自动装载使用注解声明的 Bean. 它的使用非常简单,使用 context 命名空间中的 component-scan 来指定要扫描的包即可。

<!-- 注意,使用以上配置我们需要引用 context 命名空间,可以使用分隔符来指定多个扫描的包 -->
<context:component-scan base-package="me.shouheng.spring.componentscan"/>

默认地,它会扫描 @Component, @Repository, @Service, @Controller 注解声明的类,并将其加载到容器中。这四个注解可以使用各自的 value 字段指定该 Bean 的 id(默认将首字母小写之后作为 Bean 的名字)。这个几个注解分别用到下面的几种类型的类上面:

  1. @Component 通用的构造型注解,标识该类为 Spring 组件。
  2. @Controller 标识该类定义为 Spring MVC 控制器。
  3. @Repository 标识该类定义为数据仓库。
  4. @Service 标识该类定义为服务。

自动装配的时候,可以通过为字段添加 @Autowired 注解来实现,也可以不指定注解,但是要给字段提供 Setter 方法和构造方法。通常,建议使用基于构造方法的注入方式。@Autowired 注解有一个 required 的布尔类型字段,默认为 true,表示如果找不到可装配的 Bean 就抛异常;将其设置为 false 时,如果找不到也不会抛异常,但是如果最终没有注入值,又恰好用到了它,可能会在运行时抛出 NPE 异常。

关于 <context:annnotation-config> 与 <context:component-scan/> 标签的区别:如果用 <context:annotation-config/> ,我们还需要配置 Xml 注册 Bean,而使用 <context:component-scan /> 的话,注册的步骤都免了。当然前提是我们对需要扫描的类使用的注解(比如 @Componet, @Service 等),而如果同时使用两个配置的话,<context:annotation-config/> 会被忽略掉。就是说 <context:component-scan/> 的功能是包含 <context:annnotation-config> 的,前者不仅可以使用注解配置,还可以扫描自动包下面的 Bean。

2.3.2 基于注解的自动装配

当然,同样的功能你还可以通过使用基于类的配置方式实现。这里我们用 @Configurable 将其声明为一个配置类,然后使用 @ComponentScan 注解指定要扫描的包路径。这里的 @ComponentScan 注解与 XML 中的 component-scan 相似。

// 基于注解的自动装配
@Configurable
@ComponentScan(value = "me.shouheng.spring.componentscan")
public class ComponentScanConfiguration { 
}

// 通过如下的方式来获取一个上下文
AnnotationConfigApplicationContext context = 
    new AnnotationConfigApplicationContext(ComponentScanConfiguration.class);

2.4 基于 Java 配置

与基于注解自动扫描的方式不同的是,基于纯 Java 的配置方式中,只需要使用 @Configurable 注解即可。与在 XML 中不同的是,这种配置方式中你可以直接使用 Java 方法来生成 Bean 实例,并直接使用该实例的方法来为其赋值。因此,本质上讲,它只是把 XML 中的工作转换到了 Java 中进行处理。在定义 Bean 的方法之上使用 @Bean 注解即可将返回的类型作为一个 Bean 使用:

@Configuration
public class JavaConfig {

    @Bean("first")
    public FirstBean firstBean() {
        return new FirstBean(secondBean());
    }

    @Bean("second")
    public SecondBean secondBean() {
        return new SecondBean();
    }
}

2.5 混合使用多种配置方式

以上提供了基于 Java 和基于 XML 的两种配置方式,实际上我们可以混合使用多种不同类型的配置方式。这里我们简单列举一下好了:

  1. 在 XML 中引用基于 XML 配置:<import resource="AspectConfig.xml "/>
  2. 在 XML 中应用基于 Java 的配置:<bean class="me.shouheng.spring.javaconfig.JavaConfig"/>,没错就是将配置类当作 Bean 引入;
  3. 在基于 Java 的配置中引用基于 Java 的配置:@Import(value = {JavaConfig.class})
  4. 在基于 Java 的配置中引用基于 XML 的配置:@ImportResource(value = {"classpath:aop/AOPConfig.xml"})

总结

这篇文章总结了 Spring IoC 容器的一些基本的配置方式。其目的在于通过阅读了这篇文章之后,使读者能够了解 Spring 都提供了哪些 API,以便在使用的时候,能够使用它们来解决问题。

Spring IoC 详解:原理、实现与实战 本文系统介绍了Spring IoC的核心概念与实现机制。首先解释了IoC(控制反转)和DI(依赖注入)的关系,梳理了Bean、容器、作用域等核心概念。详细分析了XML、注解和Java Config三种配置方式,深入解读了IoC容器的工作原理和Bean生命周期。文章还提供了常见应用场景、源码机制简析、最佳实践和常见问题解答,强调IoC在系统解耦、配置管理等方面的优势。通过掌握这些内容,开发者能更有效地构建灵活、健壮的Spring应用。 阅读详情

相关推荐

嵌入式学习之QT学习---14 QT跨平台运行之把QT程序交叉编译到ARM开发板

想要把qt工程放到开发板上运行,就需要用到交叉编译。由于qt是跨平台的,所以只需要换个编译器编译一下就可以。 以“定时器”的例子为例,在移植之前还需要进行一个准备工作,在windows下运行的时候,电脑屏幕很大,但是运行的窗口只有一点点大,开发板也有外接屏幕,如何让运行窗口自动适配开发板的外接屏幕呢?令其占满屏幕显示,而不是一小块。 第一步:需要设置一下,先给ui布局,如果不布局,控件就不会随着屏幕的大小的变化而变化。 第二步:利用代码来获取屏幕的大小,给widget.cpp文件下添加如下代码 #inclu

qq_42822743的博客 5456

Spring.profiles多环境配置原理

配置项目 Spring的profiles有两个变量可以配置 spring.profiles.default 默认值,优先级低。当active没有配置时,使用此变量。spring.profiles.active 优先级高,指定当前容器使用哪个profile 一般用法 声明多profile 如果使用spring的profiles机制,第一步要在applicat

supportUAT的专栏 2960

开关电源EMC整改实录:用WSX系列共模电感搞定30MHz辐射超标

本文详细介绍了开关电源EMC整改实战,通过WSX系列共模电感成功解决30MHz频段辐射超标问题。文章分析了共模干扰的产生机制,对比了不同磁芯材料的性能差异,并提供了电路布局优化与安装技巧,最终通过实测数据验证了整改方案的有效性。

weixin_29305313的博客 413

SpringIOC机制详解

所谓Bean的作用域其实就是指Spring给我们创建出的对象的存活范围,在配置文件中通过bean的scope属性指定取值范围说明singleton默认值,单例的prototype多例的requestWEB 项目中,Spring 创建一个 Bean 的对象,将对象存入到 request 域中sessionWEB 项目中,Spring 创建一个 Bean 的对象,将对象存入到 session 域中。

互联网底层民工的博客 9560

手把手带你搭建一个语音对话机器人:5分钟定制个人AI小助手

通过本文的简单步骤,你已经掌握了如何用 Python 搭建一个语音对话机器人。我们使用了实现语音识别,利用 OpenAI API 生成对话内容,并通过gTTS将文本转换为语音。整个流程非常简洁,你可以根据自己的需求进一步扩展机器人功能,甚至将其集成到实际的应用场景中。

小蜗牛的珍贵百宝箱 4803

C#上位机部署YOLO模型:ONNX转换+推理加速+内存优化全攻略

本文针对C#上位机部署YOLO模型的三大痛点,提供从模型转换到优化部署的完整解决方案。首先介绍将YOLO模型转换为ONNX格式的必要性和方法,包括自动和手动两种转换方案及常见问题解决。然后详细讲解C#环境配置和基础部署流程,包括图像预处理、模型加载、推理计算和结果解析。最后提出推理加速和内存优化策略,通过硬件适配、多线程处理和资源复用等技术手段,实现工业场景下的高效稳定运行。全文提供可直接复用的代码片段和实测验证方案,覆盖YOLOv5/v7/v8全版本,帮助开发者快速实现轻量化部署。

这里只有干货:从 Modbus 通信到 MES 对接,从 YOLO 训练到工控机部署,带你搞定工业软件开发全流程。 785

Spring注解驱动开发三切换环境Profile

@Profile注解 Spring为我们提供的可以根据当前环境,动态的激活和切换一系列组件的功能。指定组件在哪个环境的情况下才能被注册到容器中,不指定,任何环境下都能注册这个组件。 接口类如下: 看一下Javadoc,什么都明白了。 /** * Indicates that a component is eligible for registration when one or mo......

小小默:进无止境 1278

5GS 协议栈 — PFCP 协议 — URR 用量上报规则

目录 文章目录目录URR 用量上报规则UEE 的参数Usage Report 的参数示例 URR 用量上报规则 29244 5.2.2 Usage Reporting Rule URR 的作用? 用来告诉 UPF 如何对 PDR 识别的 SDF 或 Application 业务进行使用量统计信息的上报。CP 收到 Report Information 后,可用于计费或者管控(e.g. 超量限速)等用途。 URR 在哪个流程里下发的? N4 会话建立流程。 N4 会话修改流程。 URR 是怎么工作

烟云的计算 4587

IOC概念和原理

1.什么是IOC IOC即为控制反转,把对象的创建和对象之间的调用过程,交给Spring管理。不需要像se阶段一样new对象。 使用IOC的目的:为了降低耦合度。所谓耦合度就是某模块(类)与其它模块(类)之间的关联、感知和依赖的程度,是衡量代码独立性的一个指标,也是软件工程设计及编码质量评价的一个标准。 2.IOC的底层原理 假如有以上俩个类,传统创建对象我们需要在UesrService类中调用uesrDao中add方法需要先在UesrService中new uesrDao的对象,再调.

weixin_52875557的博客 7509

【DRAM存储器十五】DDR介绍-关键技术之DLL和prefetch

详述DDR DLL和预取原理以及几个DDR相对初代SDRAM新增的时序参数

highman110的博客 4362

ICC2:使用analyze_lib_cell_placement检查lib cell的pass rate

我正在「拾陆楼」和朋友们讨论有趣的话题,你⼀起来吧?在place之前需要使analyze_lib_cell_placement命令去检查lib cell在当前的site row/power plan/legalize设置的环境下能够正常place和legalize。下面分享一个脚本去报告pass rate低于2%的lib cell。

m0_61544122的博客 673

详细说说Spring的IOC机制

Spring 的 IOC(控制反转)是框架的核心机制,用于管理对象的创建和依赖注入,通过将控制权从应用程序代码转移到容器,实现组件间的解耦。传统开发中,对象主动创建依赖,导致紧耦合。IOC 将对象创建和依赖管理的控制权交给 Spring 容器,由容器负责实例化、配置和组装对象。IOC 的具体实现方式,容器通过构造器、Setter 方法或字段注入,将依赖对象传递给目标组件。

大户影视的博客 1675

高通SDX12:ProSLIC Si32185移植调试

高通 SDX12 语音芯片slic 音频驱动 Si32185

不秃头的程序猿Gabriel的博客 2036

Spring学习路径-IOC机制

控制反转(Inversion of Control,IOC)是 Spring 框架的核心思想之一,其本质是将对象的创建和依赖关系的管理从程序代码中解耦出来,交给 Spring 容器(Container)负责。传统开发模式:对象 A 需要使用对象 B 时,由 A 自己创建 B 的实例(如new B()),导致 A 与 B 强耦合。IOC 模式:对象 A 的依赖对象 B 由 Spring 容器创建并注入到 A 中,A 无需关心 B 的创建细节,只需被动接受即可。

2403_87486006的博客 1409

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

Spring IoC容器

核心技术 发行版5.0.8 这一部分的指导文档覆盖了所有的完全集成到Spring框架中的技术。 这些技术中首要的便是Spring框架的控制反转(IoC)容器。Spring框架的IoC容器的全面的处理是与Spring的面向切面编程(AOP)的彻底实现紧密相关的。Spring框架拥有他自己的AOP框架,该技术在概念上是很容器理解的,并且成功的解决了在Java企业编程中的AOP需求的80%的点。 该框...

hongbochen1223的专栏 1万+

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

Spring IOC 入门

IOC(控制反转)是一种设计思想,将对象创建和依赖管理的控制权从开发者转移给容器。DI(依赖注入)是实现IOC的具体方式,容器自动将依赖对象注入到类中。Spring IOC是Java中的实现,提供XML、注解和Java配置三种方式管理Bean。通过@Component等注解声明Bean,@Autowired实现依赖注入(推荐构造器注入)。Spring还支持多种Bean作用域(如单例、原型等)。IOC的优势包括解耦、简化开发、便于测试和统一管理对象生命周期。

sunddy_x的博客 919

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

问:聊聊Spring IOC机制

Spring IOC(控制反转)是Spring框架的核心机制,通过将对象的创建、赋值、管理等操作交给IOC容器,实现了对象之间的解耦。IOC容器负责读取配置文件或注解,根据配置创建和管理对象,并支持构造方法注入、set方法注入等依赖注入方式。Spring IOC机制降低了程序的耦合度,提高了可扩展性和可维护性,其底层实现依赖于Spring容器和多个类的协同工作。

技术铺掌柜 1496

Spring IOC的实现机制是什么?

Spring IOC的实现机制是什么?

java1234的博客 969

细致讲解Spring IOC原理,一篇全都掌握

Ioc—Inversion of Control,即“控制反转”。是一种设计思想。在Java开发中,Ioc意味着将你设计好的对象交给容器控制(由容器来创建及注入依赖对象),而不是应用程序直接控制。DI—Dependency Injection,即依赖注入:组件之间依赖关系由容器在运行期决定。形象的说,即由容器动态的将某个依赖关系注入到组件之中。依赖注入的目的是为了提升组件重用的频率,使系统灵活、可扩展。

乾坤未定,你我皆是黑马 1599

spring IOC容器的三种注入方式

spring IOC容器的三种注入方式 set方法注入 把需要注入的类写成属性,给它设置一个set方法。实现代码如下: public class B { private A a; public void setA(A a){ this.a == a; } } 接着在配置文件中类A注入到类B里面去 &amp;amp;lt;bean id=&amp;quot;aa&amp;quot; class=&amp;quot;com.study.j

qq_43489222的博客 9133

Spring IoC基于注解的DI详细配置全解【两万字】

详细介绍了基于注解和Java Config的核心Spring IoC机制的配置和使用。

终生学习践行者 5615

Spring框架核心之IoC?

本文详细介绍了Spring框架的核心机制IoC(控制反转)。IoC通过将对象的创建和依赖管理权交给Spring容器,实现了组件间的解耦。文章解析了IoC的核心概念、工作流程及实现方式(XML配置、注解和Java配置),并对比了传统开发与IoC开发的差异。重点阐述了依赖注入(DI)作为IoC的实现手段,包括Setter注入和构造器注入两种方式。通过代码示例演示了如何定义Bean、配置依赖关系及获取Bean实例。此外,还介绍了Bean的作用域、生命周期管理以及循环依赖等关键问题。

X13100387636的博客 1033

Spring框架之IOC容器的学习

Spring框架之IOC容器的理解 Bean的作用域 Spring中依赖的注入方式 模板设计模式解析

PIKapikaaaa的博客 376

Spring(1)—maven依赖、IOC、Spring配置说明、依赖注入、bean的作用域

一、搭建环境 1、maven spring依赖 <!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>

weixin_42182892的博客 1238

spring IOC

控制反转(IoC)是一种设计思想,其核心是将对象的创建权、依赖关系的维护权从业务逻辑代码中剥离出来,交给第三方容器(如 Spring IoC 容器)统一管理。传统方式:对象 A 依赖对象 B 时,需要在 A 中主动new B()创建实例,控制权在开发者手中。IoC 方式:对象 A 只需声明依赖 B,IoC 容器会自动创建 B 并注入到 A 中,控制权由容器掌握(“反转”)。

hyh1795844373的博客 977

Spring FrameWork IOC

其中,主要包括:1.支持IOC(控制反转)和AOP(面向切面编程)的容器 2.支持JDBC和ORM的数据访问模块(主要是针对sql) 3.支持声明式事务模块 4.支持基于Servlet的MVC开发 5.基于Reactive的web开发6.集成JMS、Java Mail、JMX及缓存等其他模块所以,java spring可以说是覆盖了整个程序编程的一个框架,

m0_65376383的博客 1003
上一篇: 常用的 CMake 指令总结
下一篇: 对 Spring AOP 机制及其配置方式的的总结
开发者如是说
博客等级 码龄10年 67粉丝 163原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值