Spring IoC和DI详解以及装配Bean

STM32F103模拟SSI时序解析:实现高精度绝对式编码器位置读取 本文详细解析了如何在STM32F103微控制器上通过软件模拟SSI协议时序,实现高精度绝对式编码器的位置读取。文章从项目驱动出发,深入剖析了SSI通信原理、硬件电平转换连接、核心软件模拟代码实现及关键时序参数调试方法,并提供了使用示波器进行波形对齐与优化的实战指南,为成本敏感型工业控制与机器人项目提供了高性价比的解决方案。 阅读详情

Spring框架

Spring 框架是 Java 应用最广的框架,它的成功来源于理念,而不是技术本身,它的理念包括 IoC (Inversion of Control,控制反转) 和 AOP(Aspect Oriented Programming,面向切面编程),它是一个轻量级的 DI / IoC 和 AOP 容器的开源框架,来源于 Rod Johnson 在其著作 《Expert one on one J2EE design and development》 中阐述的部分理念和原型衍生而来。

Spring的优势

  • 低侵入 / 低耦合 (降低组件之间的耦合度,实现软件各层之间的解耦)
  • 声明式事务管理(基于切面和惯例)
  • 方便集成其他框架(如MyBatis、Hibernate)
  • 降低 Java 开发难度
  • Spring 框架中包括了 J2EE 三层的每一层的解决方案(一站式)

Spring的功能

  • Spring 能帮我们根据配置文件创建及组装对象之间的依赖关系
  • Spring 面向切面编程能帮助我们无耦合的实现日志记录,性能统计,安全控制。
  • Spring 能非常简单的帮我们管理数据库事务。
  • Spring 还提供了与第三方数据访问框架(如Hibernate、JPA)无缝集成,而且自己也提供了一套JDBC访问模板来方便数据库访问。
  • Spring 还提供与第三方Web(如Struts1/2、JSF)框架无缝集成,而且自己也提供了一套Spring MVC框架,来方便web层搭建。
  • Spring 能方便的与Java EE(如Java Mail、任务调度)整合,与更多技术整合(比如缓存框架)。

Spring框架结构

上面简短的介绍了一下Spring框架,下面正式开始讲述标题的内容

 

Spring Ioc简介

IOC:Inverse of Control(控制反转),控制反转不是什么技术,而是一种设计思想,在IOC之前,我们想获得一个对象,就通过new关键字,那在IOC就是将原本在程序中手动创建对象的控制权,交由Spring框架来管理。在xml文件中配置bean的信息或者配置自动扫描包等,把程序中的类装载到Spring容器中管理。

那么IOC有什么好处?(面试)

这个问题其实就是问我们与new相比,IOC的优点在哪里。

假设我们现在有一个Animal接口,我们需要获得一些动物的叫声,新建一个Cat实现类

//Animal接口
package dto;

public interface Animal {
    void cry();
}

//Cat实现类
package dto;
public class Cat implements Animal {
    public void cry() {
        System.out.println("I am Cat!");
    }
}

//测试类
import dto.Animal;
import dto.Cat;
import org.junit.Test;
public class testSpring {
    @Test
    public void test(){
        Animal animal = new Cat();
        animal.cry();
    }
}

那如果我们现在想获得狗的叫声怎么办,新建一个实现类Dog

package dto;
public class Dog implements Animal{

    public void cry() {
        System.out.println("I am Dog!");
    }
}

然后将测试代码改成Animal animal = new Dog(),其余代码不变。这是传统使用new实例化对象,如果程序大量使用的new来实例化对象,一但程序需要改动或者扩展应用,那开发者就太难受了。

下面我们来看看使用spring来实现上述例子

上面的Animal接口和Cat、Dog实现类不变,增加spring.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
       http://www.springframework.org/schema/beans/spring-beans.xsd
       ">
    
    <bean id="cat" class="dto.Cat" />
</beans>

测试类如下

import dto.Animal;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:spring.xml"})
public class testSpring {

    @Autowired
    private Animal animal;

    @Test
    public void test(){
        animal.cry();
    }
}

运行结果

那现在我需要得到Dog的叫声,测试代码不需要任何修改,只需要修改spring.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
       http://www.springframework.org/schema/beans/spring-beans.xsd
       ">

    <bean id="dog" class="dto.Dog" />
</beans>

运行结果:

从上面的例子我们可以看出spring的强大,通过依赖注入的方式我们可以将实例化对象配置在xml文件,然后使用接口自动装配我们实例化对象,这样做的好处:一、松耦合  二、便于扩展

Spring DI简介

DI:Dependency Injection(依赖注入),上面的ioc是一种思想,那么具体的实现呢就是依赖注入。比如A对象需要一个B对象,那么我们可以通过在xml文件中配置或者通过注解等方式将其交给spring容器管理,这样当系统运行时,spring会在适当的时候将B注入给A对象,这样就完成了对象之间的依赖关系,至于B是怎么构造的,何时构造的,A不需要关心。

简单来说一句话,DI(依赖注入)其实就是IOC的另外一种说法,DI是由Martin Fowler 在2004年初的一篇论文中首次提出的。他总结:控制的什么被反转了?就是:获得依赖对象的方式反转了。

 

装配Bean

Spring容器负责创建应用程序中的bean并通过DI来协调这些对象之间的关系。作为开发人员,需要告诉spring要创建哪些bean并且如何将其装配在一起,spring中装配Bean的三种主要方式:

  1. 在XML中进行显示配置
  2. 在Java中进行显示配置
  3. 隐式的bean发现机制和自动装配

三种方法的优先性

spring提供了三种方式来装配Bean,但是我们优先使用自动配置机制。显式的配置越少越好。当你必须要显示配置Bean的时候(比如有些源码不是由你来维护的,当你需要为这些代码配置Bean的时候),推荐使用类型安全并且比XML更加强大的JavaConfig。最后,只有当你想要使用便利的XML空间,并且在JavaConfig中没有同样的实现时,才应该使用XML。

优先性:自动装配->Java显示配置->XML配置

在XML中配置Bean

使用 XML 装配 Bean 需要定义对应的 XML,这里需要引入对应的 XML 模式(XSD)文件,这些文件定义了配置 Spring 的XML元素,使用idea创建XML文件:

一个简单的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 http://www.springframework.org/schema/beans/spring-beans.xsd">

</beans>

在上面的XML文件中,<beans>是该模式中的一个元素,它是所有Spring配置文件的根元素。

装配简单属性值

下面是一个简单的例子

package dto;

public class Student {
    private String name;
    private int age;

    /* setter and getter */
}
<bean id="student" class="dto.Student">
        <property name="name" value="沈腾"/>
        <property name="age" value="40"/>
</bean>

​​​​简单解释一下:

  • bean元素是在XML文件声明Bean的属性,类似@Bean注解,下面会讲到这个注解
  • id是这个bean的名字,id属性遵守 XML 语法的 ID 唯一性约束。必须以字母开头,可以使用字母、数字、连字符、下划线、句号、冒号,不能以 / 开头。也可以使用name属性来代替id属性,甚至可以不写id属性,例如
    <bean class="dto.Student">
            <property name="name" value="沈腾"/>
            <property name="age" value="40"/>
    </bean>

    这个时候,Spring将会根据"全限定类名#{number}"来进行命名。在这里就是“dto.Student#0”。其中#0是一个计数的形式,用来区分相同类型的其他bean,当第二次声明一个没有id属性的bean时,就会是“dto.Student#1”,这种自动化命名很方便,但是如果你后续需要用到这个bean的引用,那还是通过id属性进行明确的命名。

  • class 属性显然就是一个类的全限定名
  • property 元素是定义类的属性,其中的 name 属性定义的是属性的名称,而 value 是它的值。

装配集合类型

上述是装配简单的类型变量,下面来演示如何装配集合类型,新建一个CollectionType类。

package dto;

import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

public class CollectionType {
    
    private Integer id;
    private List<String> list;
    private Map<String, String> map;
    private Properties properties;
    private Set<String> set;
    private String[] array;
    
    /* setter and getter */
}

在XML中该如何装配它们

 <bean id="collectionType" class="dto.CollectionType">
        <!-- 装配Integer类型的id -->
        <property name="id" value="1"/>

        <!-- 装配List类型的list -->
        <property name="list">
            <list>
                <value>list-1</value>
                <value>list-2</value>
                <value>list-3</value>
            </list>
        </property>

        <!-- 装配Map类型的map -->
        <property name="map">
            <map>
                <entry key="key1" value="value-1"/>
                <entry key="key2" value="value-2"/>
                <entry key="key3" value="value-3"/>
            </map>
        </property>

        <!-- 装配Properties类型的properties -->
        <property name="properties">
            <props>
                <prop key="prop1">value-prop-1</prop>
                <prop key="prop2">value-prop-2</prop>
                <prop key="prop3">value-prop-3</prop>
            </props>
        </property>

        <!-- 装配Set类型的set -->
        <property name="set">
            <set>
                <value>set-1</value>
                <value>set-2</value>
                <value>set-3</value>
            </set>
        </property>

        <!-- 装配String[]类型的array -->
        <property name="array">
            <array>
                <value>array-1</value>
                <value>array-2</value>
                <value>array-3</value>
            </array>
        </property>
</bean>

复杂类型的装配大概就是这些,更复杂的类型都可以进行分解,例如list中的对象可以不是一个基本类型,而是一个自定义的类

例如List 属性使用 <list> 元素定义注入:

<property name="list">
    <list>
        <ref bean="beanOne"/>
        <ref bean="beanTwo"/>
    </list>
</property>

Map 属性使用 <map> 元素定义注入:

<property name="map">
    <map>
        <entry key-ref="keyBean" value-ref="valueBean"/>
    </map>
</property>

Set 属性使用 <set> 元素定义注入:

<property name="set">
    <set>
        <ref bean="bean"/>
    </set>
</property>

命名空间装配

除了上述的配置之外,spring还提供了对应的命名空间的定义,只是在使用命名空间的时候要先引入对应的命名空间和 XML 模式(XSD)文件。使用c-命名空间需要在XML的顶部声明其模式:如下所示

这里将c-命名空间和通过构造器注入初始化bean方在一起讲

上面其实就是Spring根据XML中的配置然后利用反射类的实例对象调用setter方法来实现属性注入,如果你将类中的setter方法去掉,运行时就会报错

下面通过构造器参数的方式实现属性注入:

具体到构造器注入,有两种选择:<constructor-arg>元素或者使用Spring3.0所引入的c-命名空间

继续以Student类为例

package dto;

public class Student {
    private String name;
    private int age;
    
    public Student(String name, int age){
        this.name = name;
        this.age = age;
    }

    /* setter and getter */
}

下面对比一下两种不同的方式实现

<!-- 使用<constructor-arg>元素 -->
<bean id="student" class="dto.Student">
     <constructor-arg name="name" value="沈腾"/>
     <constructor-arg name="age" value="40"/>
</bean>
<!-- 引入c-命名空间之后 -->
<bean id="student1" class="dto.Student"
     c:name="沈腾" c:age="40"/>   

c-命名空间属性名以 “c:” 开头,也就是命名空间的前缀。接下来就是要装配的构造器参数名,在此之后如果需要注入对象的话则要跟上 -ref(如c:cd-ref="card",则对cd这个构造器参数注入之前配置的名为 card 的 bean)

很显然,使用 c-命名空间属性要比使用 <constructor-arg> 元素精简,但是它直接引用了构造器参数的名称,这不利于安全性,因此我们可以使用下面这种方式

<bean id="student1" class="dto.Student"
          c:_0="沈腾" c:_1="40"/>

我们将参数的名称替换成了 “0” 和 “1” ,也就是参数的索引。因为在 XML 中不允许数字作为属性的第一个字符,因此必须要添加一个下划线来作为前缀。

p-命名空间

在构造器实现属性注入的方式有c-命名空间来替代<constructor-arg>,那么p-命名空间则是属性注入<property>元素的替代方案,首先在XML头部进行声明:

    <!-- 使用<property>元素 -->
    <bean id="student" class="dto.Student">
        <property name="name" value="沈腾"/>
        <property name="age " value="40" />
        <property name="card" ref="card">
    </bean>
    <!-- 引入p-命名空间之后 -->
    <bean id="student1" class="dto.Student"
        p:name="沈腾" p:age="40" p:card-ref="card"/>

使用p命名空间的方式和c-命名空间很像,先以p:开头,后面是属性名和属性值,如果属性需要注入的是一个对象,则需要在属性名后面加上-ref表明要注入的是一个Bean的引用

util-命名空间

util-命名空间的出现是因为p-命名空间不能用来装配集合,因此在装配集合的时候就没有一种便利的方式,首先还是在头部声明其格式:

接下来看一下util-命名空间的使用:

首先在Student类中添加一个list对象

package dto;

import java.util.List;

public class Student {
    private int id;
    private String name;
    private List<String> list;

    /* sttter and getter */
}
    <!--  仅仅使用p-命名空间  -->
    <bean id="student1" class="dto.Student"
          p:name="沈腾" p:id="40">
        <property name="list">
            <list>
                <value>value-1</value>
                <value>value-2</value>
                <value>value-3</value>
            </list>
        </property>
    </bean>
    <!--  使用util-命名空间后  -->
    <util:list id="list">
        <value>value-1</value>
        <value>value-2</value>
        <value>value-3</value>
    </util:list>

    <bean id="student2" class="dto.Student"
          p:name="沈腾" p:id="40" p:list-ref="list" />

使用util-命名空间后可以将list移出到bean的外面,并将其声明到独特的bean之中

<util:list> 只是 util-命名空间中的多个元素之一,下表提供了 util-命名空间提供的所有元素:

元素描述
<util:constant>引用某个类型的 public static 域,并将其暴露为 bean
<util:list>创建一个 java.util.List 类型的 bean,其中包含值或引用
<util:map>创建一个 java.util.map 类型的 bean,其中包含值或引用
<util:properties>创建一个 java.util.Properties 类型的 bean
<util:property-path>引用一个 bean 的属性(或内嵌属性),并将其暴露为 bean
<util:set>创建一个 java.util.Set 类型的 bean,其中包含值或引用

隐式的bean发现机制和自动装配

Spring从两个角度来实现自动化装配:

  1. 组件扫描(component scanning):Spring会自动发现应用上下文中所创建的bean
  2. 自动装配(autowiring):Spring  自动满足bean之间的依赖

首先我们来看看组件扫描,创建一个表示动物类型接口animal:

package dto;

public interface animal {
    void cry();
}

然后我们再新建一个cat类实现animal:

package dto;

import org.springframework.stereotype.Component;

@Component
public class Cat implements animal{

    public void cry() {
        System.out.println("我是cat");
    }
}

在cat中我们使用了@Component注解,这个简单的注解表明该类会作为组件类,并告知Spring要为这个类创建bean。这样就不要显示的配置Cat bean,因为你已经使用了@Component注解,Spring会为我们处理好。

但是组件扫描默认是不启用的,我们还需要显示配置一下Spring,命名它去寻找带有@Component注解,并为其创建bean,下面来创建一个配置类CatConfig

package dto;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan
public class CatConfig {
}

简单解释一下:

上面@Configuration注解表示这是一个配置类,@ComponentScan注解,这个注解能够在Spring中启用组件扫描,如果没有其他配置的话,@ComponentScan注解默认会扫描与配置类相同的包,也就是dto包以及这个包下面所有的子包,查找带有@Component注解的类,并且会在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"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context         
       http://www.springframework.org/schema/context/spring-context.xsd">

    
    <context:component-scan base-package="dto" />

</beans>

下面新建一个Test1来测试一下

import dto.Cat;
import dto.CatConfig;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import static org.junit.Assert.assertNotNull;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes= CatConfig.class)
public class test1 {

    @Autowired
    private Cat cat;

    @Test
    public void catShouldNotNull(){
        assertNotNull(cat);
    }

 }

代码运行是绿色表示通过,之前配置bean时都有指定id,我们使用 @Component注解类是并没有指定id,那么Spring将根据类名指定一个ID,那Cat类的id就是cat,也就是将类名的第一个字母变成小写,当然我们也可以去指定id名,列如:

package dto;

import org.springframework.stereotype.Component;

@Component("bigCat")
public class Cat implements animal{

    public void cry() {
        System.out.println();
    }
}

还有另外一种为bean命名的方式,不是使用@Component注解,而是使用Java依赖注解规范中提供的@Named注解,上面的@Component注解可以替换成@Named注解,两者有细微的差异,但是大多数情况下,二者可以互换。了解就好,开发的时候推荐使用@Component注解

设置组件扫描的基础包

@ComponenetScan有两个属性:basePackages和basePackageClasses

上述使用@Component注解没有指定包,那么Spring会默认以配置类所在的包作为基础包来扫描组件,当然我们也可以指定包名

package dto;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan("dto")
public class CatConfig {
}

我们也可以使用basePackages明确指定设置基础包

package dto;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan(basePackages = "dto")
public class CatConfig {
}

basePackages是一个复数形式,它可以允许我们指定多个基础包,以逗号隔开

package dto;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan(basePackages = {"dto","Controller","Service"})
public class CatConfig {
}

在上面的例子中,所设置的基础包是以String类型表示的,但是这种方法是类型不安全的,一但我们重构代码,包名改变了,那么指定的基础包可能就会出错。这是就可以使用@basePackageClasses属性,列如

package dto;

import Controller.baseController;
import Service.baseService;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan(basePackageClasses = {Cat.class, baseController.class, baseService.class})
public class CatConfig {
}

我们不在使用String类型名称来指定包,俄日basePackageClasses属性设置的数组中包含了类,这些类所在的包将会作为组件扫描的基础包。

如何在应用程序中所有的对象都是相互独立的,彼此之间没有依赖,那组件扫描就足够满足要求了,但是很多对象会依赖其他对象才能完成任务,这样我们就需要有一种方法将组件扫描得到的bean和它们的依赖装配在一起,所以来了解一下自动装配

自动装配———@Autowired

简单来说,自动装配就是让Spring自动满足bean依赖的一种方法,在满足依赖的过程中,会在Spring应用的上下文中寻找匹配某个bean需求的其他bean。为了声明要进行自动装配,我们需要借助Spring的@Autowired注解

首先在Service中新建一个接口:

package Service;

public interface CatService {
    public void printInfo();
}

然后为上面接口编写一个实现类:

package Service;

import dto.Cat;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component("catService")
public class CatServiceImp implements CatService{

    @Autowired
    private Cat cat;

    @Override
    public void printInfo() {
        cat.cry();
    }
}

上面要实现的就是将cat对象实现自动装配

//第一步:修改CatConfig文件,将Service包也加入到组件扫描中去
package dto;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan(basePackages = {"dto","Service"})
public class CatConfig {
}


//第二步:编写测试类
import Service.CatService;
import dto.CatConfig;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes= CatConfig.class)
public class test1 {

    @Autowired
    private CatService catService;

    @Test
    public void test(){
        catService.printInfo();
    }

 }

运行结果:

  • 在Spring初始化bean之后,它会尽可能得去满足bean的依赖,在本例中,依赖是通过带有@Autowired注解进行声明的
  • 但是如何没有匹配的bean,那么在应用上下文创建的时候,Spring会抛出一个异常,为了避免异常的出现,可以将@Autowired的required属性设置成false,比如@Autowired(required=false),Spring尝试进行自动配置没有发现匹配的bean,就会让这个bean处于未装配状态,但是代码中如果未进行判空处理可能出现NullPointerException

@Autowired注解不仅仅能配置在属性之上,还允许用在构造器,Setter方法或者任何方法上:

//第一种,作用在属性上
@Autowired
private Cat cat;


//第二种,作用在构造器上
private Cat cat;

@Autowired
public CatServiceImp(Cat cat){
    this.cat = cat;
}


//第三种,作用在属性的setter方法上
private Cat cat;

@Autowired
public void setCat(Cat cat){
    this.cat = cat;
}

//第四种,作用在一个普通方法上
private Cat cat;

@Autowired
public void insertCat(Cat cat){
    this.cat = cat;
}

只要任何能注入这个cat对象的方法都可以使用@Autowired,推荐使用这种自动装配来完成依赖注入,这样会使得配置文件大幅度减少,满足约定优于配置的原则,增强程序的健壮性。

  • 上述的自动装配有一个问题,如果有多个bean都能满足依赖关系,Spring将会抛出异常,因为它不知道该装配哪一个bean

自动装配的歧义性(@Primary和@Qualifier)

我们在上面的例子中新建一个Animal接口的实现类dog,

//Animal接口
package dto;

public interface Animal {
    void cry();
}

//Dog实现类
package dto;
import org.springframework.stereotype.Component;
@Component("dog")
public class Dog implements Animal {

    public void cry() {
        System.out.println("I am dog");
    }
}

//Cat实现
package dto;
import org.springframework.stereotype.Component;
@Component("cat")
public class Cat implements Animal {

    public void cry() {
        System.out.println("I am Cat");
    }
}

//测试类
import dto.Animal;
import dto.CatConfig;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes= CatConfig.class)
public class test1 {

    @Autowired
    private Animal animal;

    @Test
    public void test(){
        animal.cry();
    }
}

idea直接就提示报错,说有两个bean

  • @Primary 注解:
    代表首要的,当 Spring IoC 检测到有多个相同类型的 Bean 资源的时候,会优先注入使用该注解的类。
  • 问题:该注解只是解决了首要的问题,但是并没有选择性的问题
  • @Qualifier 注解:
    上面所谈及的歧义性,一个重要的原因是 Spring 在寻找依赖注入的时候是按照类型注入引起的。除了按类型查找 Bean,Spring IoC 容器最底层的接口 BeanFactory 还提供了按名字查找的方法,如果按照名字来查找和注入不就能消除歧义性了吗?
  • 使用方法: 指定注入名称为 "cat" 的 Bean 资源
//使用Qualifier注解
public class test1 {

    @Autowired
    @Qualifier("cat")
    private Animal animal;

    @Test
    public void test(){
        animal.cry();
    }
}

//使用@Primary注解
@Component("cat")
@Primary
public class Cat implements Animal {

    public void cry() {
        System.out.println("I am Cat");
    }
}

 在Java中进行显示配置

使用组件扫描和自动化配置是推荐使用的方式,但是有时候自动化方案行不通,比如说,你想将第三方库中的组件装配到你的应用中,在种情况下,是没有办法在它的类中添加@Component和@Autowired注解的。因此必须使用显示的配置,XML配置我们上面已经讲过了,下面来通过@Bean装配bean

首先新建一个配置类并且使用@Bean注解

package dto;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class StudentConfig {

    @Bean
    public Student createStudent(){
        return new Student();
    }
}

@Configuration注解表明这个一个配置类,可以用来代替XML文件,然后在createStudent方法上使用bean注解,@Bean注解会告诉Spring这个方法会返回一个对象,这个对象要注册为Spring应用上下文中Bean。默认情况下,bean的ID就是带有@Bean注解的方法名,在本例中,bean的方法名是createStudent。

测试类

import dto.Student;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import static org.junit.Assert.assertNotNull;

public class testSpring {

    @Test
    public void test(){
        //从Java配置中加载应用上下文,并扫描dto包
        ApplicationContext context = new AnnotationConfigApplicationContext("dto");
        Student s = (Student) context.getBean("createStudent");
        assertNotNull(s) ;
    }
}


运行结果是绿色,证明s对象已经被创建。当然也可以使用@Bean(name="student")指定bean的名字

Bean的作用域

在默认的情况下,Spring IoC 容器只会对一个 Bean 创建一个实例,但有时候,我们希望能够通过 Spring IoC 容器获取多个实例,我们可以通过 @Scope 注解或者 <bean> 元素中的 scope 属性来设置,例如:

// XML 中设置作用域
<bean id="" class="" scope="prototype" />
// 使用注解设置作用域
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)

Spring 提供了 5 种作用域,它会根据情况来决定是否生成新的对象:

作用域类别描述
singleton(单例)在Spring IoC容器中仅存在一个Bean实例 (默认的scope)
prototype(多例)每次从容器中调用Bean时,都返回一个新的实例,即每次调用getBean()时 ,相当于执行new XxxBean():不会在容器启动时创建对象
request(请求)用于web开发,将Bean放入request范围 ,request.setAttribute("xxx") , 在同一个request 获得同一个Bean
session(会话)用于web开发,将Bean 放入Session范围,在同一个Session 获得同一个Bean
globalSession(全局会话)一般用于 Porlet 应用环境 , 分布式系统存在全局 session 概念(单点登录),如果不是 porlet 环境,globalSession 等同于 Session

参考资料

  • 《Spring实战(第四版)》
  • 网上的博客

 

libero烧录信号抓取 提示:如果改了东西需要重新烧录,需要把这两个界面都关闭再libero打开。两个红色的要关闭掉。然后返回libero开始烧录,观测信号(如果只烧录观测从这一步开始就行)等到下面的messige出现以下信息表示run好了。在下图中右侧可以自己设置,设置完之后记得保存一下。run一下,耐心等待,有警告就ok,run完之后。run成功会变绿色,然后点下面的这个看波形。设置抓取信号:在libero打开。打开的就是烧录界面,直接run。 阅读详情

相关推荐

Python连接高斯数据库踩坑实录:从SASL报错到SSL安全连接的完整指南

本文详细记录了Python连接高斯数据库时遇到的SASL authentication报错及其解决方法。通过剖析SASL认证机制,对比了修改数据库配置、使用官方驱动等方案的利弊,并重点提供了通过自动化脚本生成SSL证书,实现安全、免密连接的完整指南,帮助开发者彻底解决连接难题。

weixin_28340315的博客 438

Spring IoC(控制反转)和依赖注入(DI)详解

Spring IOC详解

codedot 1280

PCB布局规范及其注意事项(纯干货)

这样做的好处是信号1,3层不会有串扰,4和5作为电源有紧密的耦合,3个信号层都有GND平面可以参考,且不会互相产生串扰,唯一的缺点是布线的层面只有3个信号层(信号03的是最适合来传输高速信号,因为该层的二面都有屏蔽,防止干扰传出,也防止干扰传入)33、影响阻抗匹配的参数(ER介电常数(1GHZ以下默认为4.2,以上的话问板厂),H介质厚度(就是内层压合的PP片厚度),W走线的线宽,T走线的厚度(铜厚/减小线的厚度可以增大阻抗))我这里使用的是CITS25来计算阻抗。

qq_42379138的博客 8849

什么是Spring?什么是IOC?什么是DI?IOC和DI的关系? —— 零基础可无压力学习,带源码

工具"通常指的是Spring框架提供的各种辅助类、库、模块、和功能,这些帮助开发人员更轻松地构建、维护和扩展Java应用程序。这些工具是Spring框架的一部分,用于解决不同方面的开发任务和问题比如Spring提供的依赖注入、事务管理、数据访问工具等都属于工具的范畴容器是用来容纳某种物品的(基本)装置Spring这个容器存取的是对象生活中的水杯,垃圾桶,冰箱等等这些都是容器包括在Spring前学习的List/Map是数据存储容器,Tomcat是Web容器既然Spring是一个IOC(控制反转)容器存。

dream_ready的博客 363

用Python进行GEO数据挖掘(学习笔记四):富集分析

该笔记详细解释了富集分析的工作原理,并简要地利用gseapy在python中进行富集分析的操作。

m0_64111502的博客 5649

eNSP网络构建—建立小型局域网

企业私有网络构建运维 实战案例——使用模拟器构建局域网络 案例分析 1.架构分析 (1)需求分析 本实验的目的在于建立小型局域网。由于公司由不同部门组成,并分布在不同地点,因此需要划分不同网络实现互联互通。设计以下网络:两个部门各使用一台交换机连接,然后连接到总交换机,再通过路由器与外网以及其他部门网络相连。为了控制网络上的广播风暴,增加网络的安全性,在交换机上需要设置VLAN,在路由器与交换机之...

_ 4万+

Spring 中什么是IoC和DI?有哪些应用场景

IoC和DI是Spring框架的核心概念,它们可以帮助开发人员解耦组件之间的依赖关系,从而使应用程序更加灵活和可扩展。Spring提供了多种实现方式,例如XML配置文件、注解等,开发人员可以根据自己的需要选择合适的实现方式。

徐师兄的博客 1147

智能车图像处理0-图像处理整体框架思路

1.总体框架如上所示,具体代码请查看后续文章。2.因为参与竞赛时间是大二,所以在编程中有许多不规范的地方(如变量的命名),大家见谅。3.原创文章,请勿侵权=-=

taiyuezyh的博客 1万+

Spring中的Ioc、DI到底是啥

我们都知道,Spring是一款轻量级的IOC框架,Spring的核心就是Ioc和DI,并通过俩者解耦。 那么,Ioc、DI呢? Ioc 控制反转 Ioc(Inversion of control)控制反转,这里的控制指把控制权从应用程序中剥离出来。ioc它可以把创建对象和查找依赖对象的权限交给Ioc容器控制,而不是传统的由这些对象的使用方(消费者)进行创建初始化操作。IoC是一种让服务消费者不直接依赖于服务提供者的组件设计方式,是一种减少类与类之间依赖的设计原则。 为什么Ioc叫控制反转呢,反转了什么呢?.

m0_67402914的博客 582

Unity 编辑器篇|(四)编辑器拓展GUI类 (全面总结 | 建议收藏)

GUI 类是 Unity GUI 的接口,并且具有手动定位功能。“即时模式”GUI 系统(也称为 IMGUI)是一个完全独立的功能系统,不同于 Unity 基于游戏对象的主 UI 系统。IMGUI 是一个代码驱动的 GUI 系统,主要用作程序员的工具。为了驱动该系统,需在实现脚本上调用 OnGUI 函数即时模式 GUI 系统常用于:创建游戏内调试显示和工具。为脚本组件创建自定义检视面板。创建新的编辑器窗口和工具以扩展 Unity 本身。

游戏开发小Y的博客 12万+

基于DPCNN实现电商情感分析任务

下载链接项目中使用的模型是DPCNN,在模型中我们定义了三个组件,分别是embedding层,卷积层和全连接层。Embedding层:将每个词生成对应的嵌入向量,就是利用一个连续型向量来表示每个词卷积层:提取语句中的语义信息Linear层:将结果映射成2大小用于二分类,即正反面的概率。

优快云 精品推荐 1629

Spring和Hibernate整合操作day-04

Spring提供了对Hibernate整合支持,支持包spring-orm.jar,提供的主要组件如下: 1.LocalSessionFactoryBean 在Spring容器中创建一个SessionFactory对象。 2.HibernateTemplate 类似于JdbcTemplate,封装了session使用过程。 3.OpenSessionInVi...

qq_35206389的博客 514

Python爬虫实战:东方财富股吧与雪球舆情数据实时爬取与情绪指标挖掘

本文详细介绍如何使用Python爬虫技术实时爬取东方财富股吧和雪球平台的讨论数据,结合股价波动构建情绪分析指标。我们将使用最新的异步爬虫技术、自然语言处理方法和可视化工具,为量化交易提供数据支持。文章包含完整的代码实现和技术细节,适合有一定Python基础的读者学习。

2201_76125261的博客 1224

【Spring笔记】IOC、DI、注解、bean的自动装配

一、优点 1、轻量级、非入侵式的框架; 2、控制反转(IOC),面向切面编程(AOP) 3、支持事务的处理,对框架整合的支持 总结:Spring就是一个轻量级的控制反转(IOC)和面向切面编程(AOP)的框架。 二、组成 参考链接:Spring的七大模块,以及每个模块的作用 每个模块的作用如下: 核心容器(Spring Core):核心容器提供 Spring 框架的基本功能。核心容器的主要组件是 BeanFactory,它是工厂模式的实现。BeanFactory 使用控制反转 (IOC) 模式将应用程序

历乱的日记簿 284

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

Spring IoC、DI、Bean和自动装配的理解

我们都知道IoC是控制反转的,也就是我们只需要把类注册到Spring容器中,他可以帮助我们创建对象,该创建的思想也就是走的构造器 通过XML 例如我们创建一个People对象,默认有一个无参构造 然后我们通过XML将该类注册到Spring中,这样他就是一个bean了,并且被Spring管理 我们进行创建对象的时候,不用new了,而是在Spring容器中拿 通过注解 在用注解之前,我们需要先打开注解的支持和注解要扫描的包 然后创建类,通过@Component注入到Spring,与此作用一样的还有@Servi

1669

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

Spring之IOC(DI)基于XML装配bean(二)

Spring之IOC(DI)基于XML装配bean(2) 当A对象中需要实例化B对象时,有两种方式可以注入对象B 下面由Service层和Dao层举例,Service层调用Dao层方法,需实例化对象时: 一、外部bean注入属性 Dao实现类: public class UserDaoImpl implements UserDao{ @Override public void print() { System.out.println("Dao....."); } }

半山腰太挤了,你要去山顶看看 1520

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

spring学习总结(五):IOC & DI 配置 Bean 之自动装配及bean之间的关系

IOC & DI 配置 Bean 之自动装配 XML 配置里的 Bean 自动装配 Spring IOC 容器可以自动装配 Bean. 需要做的仅仅是在 的 autowire 属性里指定自动装配的模式byType(根据类型自动装配): 若 IOC 容器中有多个与目标 Bean 类型一致的 Bean. 在这种情况下, Spring 将无法判定哪个 Bean 最合适该属性, 所以

邢宇超的博客 792

Spring之IOC(DI)基于XML装配bean

Spring之IOC(DI)基于XML装配bean Spring概述 Spring是以一个IoC(控制反转)和AOP和AOP为内核的框架。IoC是Spring的基础。IoC实现的是一种控制,简单的说,就是以前调用new构造方法来创建对象,现在变成了使用Spring来创建对象。DI(依赖注入)与IoC的含义相同,从两个角度描述同一概念。简单的说,DI就是对象的属性,已经被注入好相关值,直接使用即可。 什么是控制反转(IoC) IoC译为控制反转 Ioc理论是借助第三方实现具有依赖关系之间的解耦,如上图所示。

半山腰太挤了,你要去山顶看看 1699

Spring之IOC(DI)基于注解装配bean(三)

Spring之IOC(DI)基于注解装配bean(三) 这里我们回顾一下什么是注解 Java 注解(Annotation)又称 Java 标注,是 JDK5.0 引入的一种注释机制。 Java 语言中的类、方法、变量、参数和包等都可以被标注。和 Javadoc 不同,Java 标注可以通过反射获取标注内容。在编译器生成类文件时,标注可以被嵌入到字节码中。Java 虚拟机可以保留标注内容,在运行时可以获取到标注内容 。 当然它也支持自定义 Java 标注。 通过注解注入属性 一、引入context名称空间 x

半山腰太挤了,你要去山顶看看 1586

Spring中的IOC、DI、 aop以及bean的装配

1.1 控制反转Ioc 1.2 DI IoC的一个重点是在系统运行中,动态的向某个对象提供它所需要的其他对象。这一点是通过DI(Dependency Injection,依赖注入)来实现的。 通俗点解释就是,当对象a需要一个对象b,或者需要b的一个方法,spring就会在系统运行到一定的时候,将需要的东西注入到a中,因此就形成了a依赖于b的依赖关系。1.3 aop AOP(Aspect Oriented Programming)意为:面向切面编程,通过预编译方式和运

Y200219的博客 249

spring框架(一)IOC、DI、装配Bean

spring框架概述 什么是spring Spring是一个开源框架,Spring是于2003 年兴起的一个轻量级的Java 开发框架,由Rod Johnson 在其著作Expert One-On-One J2EE Development and Design中阐述的部分理念和原型衍生而来。它是为了解决企业应用开发的复杂性而创建的。框架的主要优势之一就是其分层架构,分层架构允许使用者选择使用哪...

ChihkAnchor的博客 245

Spring Bean介绍(被Spring IoC容器创建、装配、管理的Java对象)IoC容器、控制反转(IoC)、依赖注入(DI)、循环依赖

Spring Bean = 被Spring IoC容器创建、装配、管理的Java对象。IoC容器(Inversion of Control Container)是Spring框架的核心引擎,负责创建、组装、管理所有Bean,并将“控制权”从开发者手中“反转”交给框架。它不一定是“JavaBean”(无参构造+getter/setter),而是一个生命周期由Spring全权负责的对象。你可以把Spring容器想象成一个“智能对象工厂”——你只需声明“我需要什么”,容器负责“造出来并送上门”。

Dontla的博客 813

请简述什么是spring的ioc和di_理解Spring中的IoC和DI

什么是IoC和DIIoC(Inversion of Control 控制反转):是一种面向对象编程中的一种设计原则,用来减低计算机代码之间的耦合度。其基本思想是:借助于“第三方”实现具有依赖关系的对象之间的解耦。DI(Dependence Injection 依赖注入):将实例变量传入到一个对象中去(Dependency injection means giving an object its i...

weixin_42497593的博客 3395

【JavaWeb-23】spring、IoC控制反转和DI依赖注入入门、基于XML的Bean装配、基于注解的Bean装配

1、spring是一个轻量级的容器(工厂),主要管理对象的(bean)。spring它比较重要,是因为它涉及的范围比较多,甚至可取代struts2来管理web层(springMVC),也甚至可以取代Hibernate管理DAO层(jdbcTemplate),但是我们这里说的spring还是主要集中在service层的管理上。——spring目前已经不仅仅是一个JavaEE管理框架了,它有很多proj

小小的客栈 大大的江湖 1375

spring 学习01--IOC控制反转--DI依赖注入--bean自动装配autowire

Spring学习01 IOC 控制翻转,之前的对象的创建,管理是由程序来控制的,现在对象由Spring来创建、管理和装配 hellospring 编写类 public class User { String str; public String getStr() { return str; } public void setStr(String str) { this.str = str; } @Override

xpc1998的博客 173

《Spring实战(第四版)》——第二章:Bean的装配(IOC、DI)

IOC:中文翻译为控制反转,意思就是把创建对象的权利交给spring.它去帮你创建对象,根据默认的或者我们预先设定好的规则去创建   对象.并把创建好的对象放在IOC容器中. DI: 中文翻译为依赖注入,可以理解为把IOC容器中的散乱这的对象之间建立联系.把一个创建好的对象注入到另一个需要这个对象实例的对象中.产生关系,使其完整. Bean的装配方式分为三类:自动装配、JavaConfig装配...

BeanModel的博客 242
上一篇: Java基础之——反射
下一篇: SpringAOP详解
GL60708
博客等级 码龄10年 5粉丝 13原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值