Spring基础——XML配置Bean的依赖注入

news2024/11/18 16:46:36

目录

  • 什么是依赖注入
    • 依赖的解析
  • Spring提供的两种注入方式
    • 1. 基于构造器的赖注入
      • 1.1 通过类型注入
      • 1.2 通过索引注入
      • 1.3 通过参数名注入
      • 1.4 通过静态工厂方法参数注入
    • 基于Setter的依赖注入
  • Spring对不同类型的注入方式
    • 1. 字面值(String,基本类型)注入
    • 2. 引用类型注入
    • 3. 集合类型注入
    • 4. 集合合并
    • 5. 内部Bean
  • Spring使用命名空间快捷注入
    • 使用p命名空间的XML
    • 使用c命名空间的XML
  • Spring使用dependes-on
  • 懒加载注入Bean
  • Spring自动注入
    • 自动注入的局限
    • 将Bean排除自动注入的搜索
  • Spring方法注入

什么是依赖注入

  • 依赖指的是对象要完成某种功能方法,需要其他对象或属性一起协作完成,而被需要的其他对象和属性则被称为对象的依赖
  • 依赖注入(DI)是Spring IoC技术实现的关键,其本质是Bean通过调用Class反射的构造函数或使用服务器定位模式来逆向控制依赖的实例化过程。(换句话说Spring使用了服务器定位模式来实现DI)
  • 使用DI技术可以让代码变的更加干净,(有的文章会说IoC完全消除了对象之间的依赖关系,实质上依赖关系是不会被消除的,DI只是让对象之间的依赖从类的内部绑定转变为从外部注入,从而降低代码的耦合度,完全消除的概念是指这两对象就没有任何联系了,互不干涉,也不存在调用),当对象被外部提供依赖时,我们不需要查询其依赖关系,也不需要去关注依赖对象的位置和类别,因此代码会更容易被维护和测试。

依赖的解析

  • 首先通过XML,Java代码或者注解来描述Bean的配置数据
    • 每个Bean的依赖通过属性,构造函数的参数,静态工厂方法参数(需要工厂方法设置的参数能代理正常的构造函数)的形式进行表达
    • 每个配置的属性和构造参数都要被赋予值或引用
    • 作为直接传递数值的属性或参数均以字符串的形式进行配置,在Spring中会自动转换成对应类型
  • 在Spring容器创建时,Spring ApplicationContext会验证每个Bean的配置,并将具有单例作用域的Bean实例化,其他Bean则会在被请求的时候才会被创建

Bean的循环依赖
在遇到BeanA引用BeanB,BeanB里又引用BeanA的时候,如果都通过构造参数进行互相注入,Spring容器会在运行时检测到这种循环引用并抛出异常。

对于Spring来说,Spring会在ApplicationContext加载配置时预先检测对还未被加载Bean的引用和循环依赖,到实际创建Bean的时候Spring会尽可能晚的设置属性和解析依赖关系(不能是构造注入,需要Setter注入),换句话说就是在有存在循环依赖的配置BeanA中,Spring检测到需要BeanB的依赖时,会在调用BeanA的setter方法之前实例化BeanB虽然Setter方法能解决循环依赖的问题,但是归根结底还是业务逻辑划分不清晰的缘故

Spring提供的两种注入方式

1. 基于构造器的赖注入

  • 构造器也被称为构造函数,既然DI是为了通过构造函数进行依赖注入,那么肯定是需要提供有参构造才能进行传参初始化。
  • Spring在进行构造注入的时候不需要明确指定调用哪个构造函数,Spring会根据传入的参数数量以及参数类型和名称自动匹配合适的构造方法
public class ConstructBeanImpl implements ConstructBean {

    private int count;
    private String poolName;
    private String poolPassword;
    private Double money;

    @Override
    public String toString() {
        return "ConstructBeanImpl{" +
                "count=" + count +
                ", poolName='" + poolName + '\'' +
                ", poolPassword='" + poolPassword + '\'' +
                ", money=" + money +
                '}';
    }

    public ConstructBeanImpl(int count, String poolName, String poolPassword, Double money) {
        this.count = count;
        this.poolName = poolName;
        this.poolPassword = poolPassword;
        this.money = money;
    }

    public ConstructBeanImpl(int count, String poolName, String poolPassword) {
        this.count = count;
        this.poolName = poolName;
        this.poolPassword = poolPassword;
    }

    public ConstructBeanImpl(int count, String poolName) {
        this.count = count;
        this.poolName = poolName;
    }

    @Override
    public void printHello() {
        System.out.println("construct hello world");

    }
}

1.1 通过类型注入

  • 在constructor-arg里配置type属性来通知Spring注入类型
 <!-- 基于构造器注入使用construct-arg标签进行标记 -->
 <!-- 注入的数据可以是通过type类型进行匹配,也可以是通过构造参数的序列进行注入 -->
 <!-- 请注意务必要确保有与注入属性数量相同的构造参数 -->
 <bean id="constructBean" class="com.nobugnolife.bean.impl.ConstructBeanImpl">
     <constructor-arg type="int" value="114"/>
     <constructor-arg type="java.lang.String" value="mysql.driver"/>
 </bean>

1.2 通过索引注入

  • 在constructor-arg里配置index来确定注入构造参数的位置,从左往右,下标从0开始
 <!-- 使用类型注入的构造注入方法在遇到参数类型相同的构造参数时容易出现歧义,可以通过按照索引的方式进行定位注入 -->
 <!-- 索引下标从0开始,从左往右的参数顺序 -->
 <bean id="constructBean01" class="com.nobugnolife.bean.impl.ConstructBeanImpl">
     <constructor-arg index="0" value="11145"/>
     <constructor-arg index="1" value="mysql.driver"/>
     <constructor-arg index="2" value="123321"/>
 </bean>

1.3 通过参数名注入

  • 在constructor-arg中通过name提供对应参数名
<!-- 如果遇到同类型,同等数量的构造参数的构造方法,还可以使用构造参数名来消除歧义 -->
<bean id="constructBean02" class="com.nobugnolife.bean.impl.ConstructBeanImpl">
    <constructor-arg name="count" value="114514"/>
    <constructor-arg name="poolName" value="mysql.driver"/>
    <constructor-arg name="poolPassword" value="123321"/>
    <constructor-arg name="money" value="10000.11111"/>
</bean>
  • 这里的参数名可以使用注解@ConstructorProperties来重命名构造参数
@ConstructorProperties({"count","name","password","money"})
public ConstructBeanImpl(int count, String poolName, String poolPassword, Double money) {
    this.count = count;
    this.poolName = poolName;
    this.poolPassword = poolPassword;
    this.money = money;
}
  • XML配置的为注解所标记的构造参数名
<bean id="constructBean02" class="com.nobugnolife.bean.impl.ConstructBeanImpl">
    <constructor-arg name="count" value="114514"/>
    <constructor-arg name="name" value="mysql.driver"/>
    <constructor-arg name="password" value="123321"/>
    <constructor-arg name="money" value="10000.11111"/>
</bean>

1.4 通过静态工厂方法参数注入

  • 上文提到过,如果静态工厂方法能代理构造函数返回对象实例的话,同样也可以使用静态工厂参数进行构造注入
  • 首先创建静态工厂类(实例工厂的方法以此类推即可
public class ConstructFactory {
    private ConstructFactory() {}
    public static ConstructBean createConstructBean(int count, String poolName, String poolPassword, Double money){
        return new ConstructBeanImpl(count,poolName,poolPassword,money);
    }
}
  • 然后将对应配置的class替换成静态工厂的类路径即可,还有添加factory-method
 <bean id="constructBean03" class="com.nobugnolife.factory.ConstructFactory" factory-method="createConstructBean">
     <constructor-arg name="count" value="114514"/>
     <constructor-arg name="poolName" value="mysql.driver"/>
     <constructor-arg name="poolPassword" value="14444"/>
     <constructor-arg name="money" value="1002.221"/>
 </bean>

基于Setter的依赖注入

  • 使用setter注入的话是Spring容器在调用无参构造实例化Bean之后调用setter方法进行注入,因此请确保类能正常调用无参构造。
  • 通过property标签实现Setter的依赖注入
 <bean id="setterBean" class="com.nobugnolife.bean.impl.SetterBeanImpl">
     <property name="beanOne" ref="beanOne"/>
     <property name="id" value="10"/>
     <property name="name" value="mybean"/>
 </bean>

Spring对不同类型的注入方式

1. 字面值(String,基本类型)注入

  • Spring对可以直接传值的属性统一使用value进行注入,并且均使用字符串形式注入(在Spring加载ApplicationContext的时候会自动将这些配置转化成对应属性的类型
  • 构造器和Setter均适用,这里就不分开举例了
<bean id="simpleTypeDao" class="com.nobugnolife.dao.impl.SimpleTypeDaoImpl">
    <!-- num对应在类里的int属性名num -->
    <property name="num" value="10"/>
    <!-- point对应float属性 -->
    <property name="point" value="1.1"/>
    <!-- flag对应boolean -->
    <property name="flag" value="true"/>
    <!-- bt对应byte -->
    <property name="bt" value="127"/>
    <!-- ch对应char -->
    <property name="ch" value="c"/>
    <!-- lg对应long -->
    <property name="lg" value="114514134"/>
    <!-- money对应double -->
    <property name="money" value="3.14159"/>
    <!-- str对应String -->
    <property name="str" value="hello world"/>
</bean>

2. 引用类型注入

  • 引用类型注入使用ref进行表述,可以是独立的ref标签,也可以是内部ref属性
<bean id="constructRefBean" class="com.nobugnolife.bean.impl.ConstructRefBeanImpl">
    <constructor-arg ref="beanOne"/>
    <constructor-arg>
        <ref bean="beanTwo"/>
    </constructor-arg>
</bean>
  • 在配置引用类型注入的时候如果传入的引用找不到id或者name的话则会返回空指针
  • 在Spring中,如果遇到具备重复配置信息或者是相似重复属性的配置Bean时,可以通过抽象出父Bean(可以是类继承的方式,或者是子Bean对应的类包含父Bean中所有的属性父Bean的配置只能是abstract或者是lazy-init,不能让工厂实例化Bean)来进行parent继承
  • Parent类
public class ParentBean {
    private String name;
    private String password;

    public void setName(String name) {
        this.name = name;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getName() {
        return name;
    }

    @Override
    public String toString() {
        return "ParentBean{" +
                "name='" + name + '\'' +
                ", password='" + password + '\'' +
                '}';
    }

    public String getPassword() {
        return password;
    }
}
  • 子类A通过继承的方式传递parent中的属性
public class SonBeanA extends ParentBean {
    private int connectNum;
    private int timeout;
    private int poolMax;

    public void setConnectNum(int connectNum) {
        this.connectNum = connectNum;
    }

    public void setTimeout(int timeout) {
        this.timeout = timeout;
    }

    public void setPoolMax(int poolMax) {
        this.poolMax = poolMax;
    }

    @Override
    public String toString() {
        return "SonBean{" +
                "name=" + getName() +
                ", password" + getPassword() +
                ", connectNum=" + connectNum +
                ", timeout=" + timeout +
                ", poolMax=" + poolMax +
                '}';
    }
}
  • 子类B中包含parent中所有的属性
public class SonBeanB {
    //    private ParentBean parentBean;
    private String tools;

    private String password;

    @Override
    public String toString() {
        return "SonBeanB{" +
                "tools='" + tools + '\'' +
                ", password='" + password + '\'' +
                ", name='" + name + '\'' +
                '}';
    }

    public void setPassword(String password) {
        this.password = password;
    }

    private String name;

    public void setName(String name) {
        this.name = name;
    }


    public void setTools(String tools) {
        this.tools = tools;
    }

}
  • XML配置
<!-- 设置abstract为true后,容器将不会实例化Bean对象,但会保留配置属性 -->
<bean id="parentBean" abstract="true">
    <property name="name" value="msyql"/>
    <property name="password" value="123"/>
</bean>


<!-- 通过parent可以继承父bean的属性配置,同时也可以覆盖父bean的配置,子bean的类需要继承或包含父bean中所有的属性 -->
<bean id="sonBeanA" class="com.nobugnolife.bean.impl.SonBeanA" parent="parentBean">
    <property name="poolMax" value="100"/>
    <property name="timeout" value="1000"/>
    <property name="connectNum" value="30"/>
</bean>


<!-- spring提供的parent不只是可以通过继承,也可以是当前类所包含的属性,确保父Bean中有的属性,子Bean对应的类也有,注意是类,不是bean -->
<bean id="sonBeanB" class="com.nobugnolife.bean.impl.SonBeanB" parent="parentBean">
    <property name="tools" value="rock and stone"/>
    <!-- 同样也可以覆盖父bean中的属性,如果对应类而不是Bean是非继承关系的话,需要确保类中有相同的属性 -->
    <property name="name" value="MongoDB"/>
</bean>

在Spring Framework4.0之后ref就不再支持local属性,可以替换成ref bean

3. 集合类型注入

  • List注入
<!-- List注入 -->
<property name="idList">
    <list>
        <value>1</value>
        <value>2</value>
        <value>3</value>
    </list>
</property>
  • set注入
<!-- Set注入 -->
<property name="nameSet">
    <set>
        <value>xiaoming</value>
        <value>lisi</value>
        <!-- 在集合注入中同样可以使用引用注入,只要有配置的引用bean -->
        <idref bean="myString"/>
    </set>
</property>
  • property注入
<!-- property注入 -->
<property name="properties">
    <props>
        <prop key="adminstrator">admin@go.org</prop>
        <prop key="password">admin</prop>
        <prop key="phone">114514</prop>
    </props>
</property>
  • map注入
<!-- map注入 -->
<property name="map">
    <map>
        <entry key="1" value-ref="beanOne01"/>
        <entry key="2" value-ref="beanOne02"/>
    </map>
</property>
  • Spring会通过集合中定义的泛型类型,自动将字符串转化为对应类型的数值如:
 private Map<String, Float> accounts;
<property name="accounts">
    <map>
        <entry key="one" value="9.99"/>
        <entry key="two" value="2.75"/>
        <entry key="six" value="3.99"/>
    </map>
</property>
  • 如果value设定为""空字符串,则默认数值为空或者Null

4. 集合合并

  • Spring支持让子集合(list,map,set,props)元素继承父集合的值,并且子集合的元素能覆盖父集合中的值。
  • 如果不知道什么是Bean继承的话可以参考Bean定义的继承
  • 父集合
<bean id="parentBean03" abstract="true">
    <property name="props">
        <props>
            <prop key="username">
                administrator
            </prop>
            <prop key="password">admin</prop>
        </props>
    </property>
</bean>
  • 子集合
<bean id="childBean" class="com.nobugnolife.bean.impl.ChildBean" parent="parentBean03">
    <property name="props">
        <!-- 子集合重写密码并新增email配置 -->
        <props>
            <prop key="password">123</prop>
            <prop key="email">example@gmail.com</prop>
        </props>
    </property>
</bean>

list,map,set等用法基本和上述结构差不多,不过对于有序集合List,父列表的值会被排在子列表的值前面。
并且集合合并只能对同类型的集合合并,无法混合不同类型集合进行合并

5. 内部Bean

  • 当某个类只是作为当前类的属性而并没有其他引用的时候,可以通过创建内部Bean的方式进行注入,这样就不需要配置新的Bean,内部Bean不需要定义ID和Name,并且也会忽略创建的作用域
  • 内部Bean
public class InnerBean {
    private String name;
    private int age;

    public void setName(String name) {
        this.name = name;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "InnerBean{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
  • 需要内部bean的类
public class HumanBeanImpl implements HumanBean {
    @Override
    public void printHello() {
        System.out.println("human hello world");
    }

    private InnerBean innerBean;

    @Override
    public String toString() {
        return "HumanBeanImpl{" +
                "innerBean=" + innerBean +
                '}';
    }

    public void setInnerBean(InnerBean innerBean) {
        this.innerBean = innerBean;
    }
}

  • 配置xml
<bean id="humanBean" class="com.nobugnolife.bean.impl.HumanBeanImpl">
    <property name="innerBean">
        <bean class="com.nobugnolife.bean.impl.InnerBean">
            <property name="name" value="Sham"/>
            <property name="age" value="28"/>
        </bean>
    </property>
</bean>

Spring使用命名空间快捷注入

使用p命名空间的XML

  • p-namespace可以简化bean中property元素来配置Bean属性注入
  • p命命名空间是Spring基于XML Schema定义的可扩展配置格式的命名空间,因此需要先导入p命名空间配置
xmlns:p="http://www.springframework.org/schema/p"
  • 使用p命名空间只需要在bean的属性前添加p:即可,对引用类型的配置属性需在属性后加-ref
<!-- 使用p命名空间对bean进行setter注入,对于引用类型需在属性名后加-ref -->
<bean id="setterBean02" class="com.nobugnolife.bean.impl.SetterBeanImpl"
      p:beanOne-ref="beanOne"
      p:id="11"
      p:name="pBean"/>

p命名空间不像标准的XML格式那样灵活。例如,声明属性引用的格式与以 Ref 结尾的属性发生冲突,而标准的XML格式则不会

使用c命名空间的XML

  • 与p命名空间相似,c命名空间是对构造注入的constructor-arg标签进行的简化
  • 首先导入c命名空间
xmlns:c="http://www.springframework.org/schema/c"
  • 通过参数名进行c命名空间的构造注入
<!-- 利用c命名空间进行构造注入 -->
<bean id="constructBean04" class="com.nobugnolife.bean.impl.ConstructBeanImpl"
      c:count="12"
      c:money="22.3"
      c:poolName="mysql"
      c:poolPassword="123321"/>
  • c命名空间通过索引形式进行的构造注入,引用类型的注入方式与p命名空间一样
<!-- c命名空间通过序列索引形式的构造注入 -->
<bean id="constructBean05" class="com.nobugnolife.bean.impl.ConstructRefBeanImpl"
      c:_0-ref="beanOne"
      c:_1-ref="beanTwo"/>

Spring使用dependes-on

  • 对于Bean的直接依赖来说,可以通过配置属性中的ref进行引用,而对于一个类在初始化之前需要先初始化类中的静态变量时,可以使用depends-on属性来指定Bean之间的初始化时间依赖关系。
public class ManagerBean {
    private String driver;
    private String url;
    private String userName;
    private String password;

    public ManagerBean() {
        System.out.println("manager bean以被实例化");
    }

    public String getDriver() {
        return driver;
    }

    public String getUrl() {
        return url;
    }

    public String getUserName() {
        return userName;
    }

    public String getPassword() {
        return password;
    }

    public void setDriver(String driver) {
        this.driver = driver;
    }

    @Override
    public String toString() {
        return "ManagerBean{" +
                "driver='" + driver + '\'' +
                ", url='" + url + '\'' +
                ", userName='" + userName + '\'' +
                ", password='" + password + '\'' +
                '}';
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}

  • 依赖ManagerBean的DependBean
public class DependBeanImpl implements DependBean {
    private ManagerBean manager;

    public DependBeanImpl() {
        System.out.println("depend bean已被实例化");
    }

    public void setManager(ManagerBean manager) {
        this.manager = manager;
    }

    @Override
    public void printHello() {
        System.out.println("depend bean hello world");
    }

    @Override
    public void registDataSourct() {
        System.out.println("创建数据库连接对象:" +
                "数据库驱动:" + manager.getDriver() +
                "\n数据库连接地址: " + manager.getUrl() +
                "\n连接用户名:" + manager.getUserName() +
                "\n连接密码:" + manager.getPassword());
    }
}
  • XML配置dependes-on,如果有多个依赖,使用逗号,空格或分号在字符串中进行分割即可
<bean id="dependBean" class="com.nobugnolife.bean.impl.DependBeanImpl" depends-on="managerBean">
    <property name="manager" ref="managerBean"/>
</bean>

<bean id="managerBean" class="com.nobugnolife.bean.impl.ManagerBean">
    <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
    <property name="url" value="jdbc:mysql://localhost:3306"/>
    <property name="userName" value="root"/>
    <property name="password" value="123"/>
</bean>

depends-on

  • 如果不配置depends-on的话,depend bean会在manager bean之前被实例化,这样是不符合逻辑的
    depends-off
    depends-on可以指定Bean的初始化时间以来关系,而在单例模式的Bean中,也可以指定小伙时间的依赖关系,在Bean中如过定义了depends-on的依赖,则依赖的Bean会在本体被销毁前销毁

懒加载注入Bean

  • 在默认的单例模式Bean中Spring容器加载ApplicationContext的时候会非常急切的创建和配置所有的单例模式Bean(这样会尽可能早的发现环境中的错误,而不是等到被调用的时候再报错),如果不想要Bean立即被创建,可以使用懒加载模式阻止Bean的实例化,懒加载模式下的Bean只有当在第一次被请求创建的时候才会实例化对象,而不是在启动容器的时候。
  • Bean属性中配置lazy-init=true即可开启懒加载
<bean id="lazyBean" class="com.nobugnolife.bean.impl.LazyBean" lazy-init="true"/>
<bean id="activeBean" class="com.nobugnolife.bean.impl.ActiveBean"/>
  • 测试是否在被加载时调用,优先实例化lazyBean,然后再在activeBean后调用lazyBean的方法,如果不是懒加载,那么activeBean的创建会和lazyBean的方法挨在一起
@Test
public void testDependBean() throws Exception {
    ApplicationContext ctx = new ClassPathXmlApplicationContext("dependBean.xml");
    DependBean dependBean = ctx.getBean(DependBean.class);
    dependBean.registDataSourct();
    System.out.println(dependBean);
}

lazy-init

Spring自动注入

  • Spring容器可以自动建立与依赖Bean之间的联系,可以省去手动配置属性或构造参数的过程。自动注入可以极大减少对指定属性或构造参数的配置,可以随着对象的变化而更新配置,因此在开发过程中,自动注入是主流用法,能极大提升开发效率。
  • Spring基于XML的自动注入通过在bean标签的属性中autowire属性来定义,自动注入的形式一共有4种
模式说明
no默认关闭自动注入模式
byName通过属性名称进行自动注入,Spring会自动匹配一个与需要自动注入属性同名的bean
byType通过属性类型注入,如果容器中只有一个与当前被注入类的类型相同或者为其配置的实现类的类型,则会进行自动注入,
如果存在多个会报错,如果没有匹配的Bean则不会发生任何事
constructor通过被注入Bean的构造器参数类型查找同类型或配置的实现类型的Bean进行注入,与byType类似
<!-- 创建需要注入依赖的Bean -->
<bean id="bean" class="com.nobugnolife.bean.impl.BeanImpl">
</bean>

<!-- 通过命名自动注入bean,Spring容器会在Bean中查询与autoWire中属性bean命名相同的Bean对象 -->
<bean id="autoWireBean" class="com.nobugnolife.bean.impl.AutoWireBeanImpl" autowire="byName"/>

<!-- 通过属性类型进行注入,Spring会自动在容器中查询与属性类型相匹配的配置Bean -->
<bean id="autoWireBean02" class="com.nobugnolife.bean.impl.AutoWireBeanImpl" autowire="byType"/>

<!-- 通过构造参数类型进行自动注入,Spring会自动在容器中查询符合类提供的构造器参数的类型相匹配的Bean,最好提供全参数构造 -->
<bean id="autoWireBean03" class="com.nobugnolife.bean.impl.AutoWireBeanImpl" autowire="constructor"/>
  • 注意使用construct注入的话要提供全参构造否则会报错
public class AutoWireBeanImpl implements AutoWireBean {
    private Bean bean;

    @Override
    public String toString() {
        return "AutoWireBeanImpl{" +
                "bean=" + bean +
                '}';
    }

    public AutoWireBeanImpl() {
    }

    public AutoWireBeanImpl(Bean bean) {
        this.bean = bean;
    }

    public void setBean(Bean bean) {
        this.bean = bean;
    }

    @Override
    public void printHello() {
        bean.printHello();
        System.out.println("autowire bean hello world");
    }
}

自动注入的局限

  • 自动注入的优先级是在setter与构造器注入之后,因此如果存在构造注入或setter注入,那么自动注入的效果会被覆盖
  • 自动注入无法注入简单的属性,如基本数据类型和String
  • 自动注入的效果不一定准确,虽然Spring在尽可能的避免对模糊情况下的猜测,但总可能会发生意外
  • 自动注入如果在项目中统一被使用,效果会很好,但如果大量使用配置的情况下混合使用自动注入则会带来误解。

将Bean排除自动注入的搜索

  • 在bean标签中通过设置autowire-candidate=false属性可以将当前Bean排除自动注入的搜索。

Spring方法注入

  • 正在修建中。。。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1492248.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

android开发文档下载,你的技术真的到天花板了吗

Android 基础 1.Activity 1、 什么是 Activity&#xff1f; 2、 请描述一下 Activity 生命周期 …… 2.Service 3.Broadcast Receiver32 4.ContentProvider 5.ListView 6.Intent 7.Fragment 1.Fragment 跟 Activity 之间是如何传值的 2.描述一下 Fragment 的生命周期 3.Fragme…

Cesium实战三:飞行航线动画

飞行航线追踪 可视化从旧金山到哥本哈根的真实航班。 1、获取点位数据&#xff1a;构建飞行跟踪器 – Cesium (cesium.com) 2、在地图上添加飞行点位&#xff1a;循环遍历点位数据&#xff0c;利用Entity直接添加点至地图上。 //添加飞行点位 const addFlightPoint () >…

计算机网络(2)-----数据链路层

目录 一.数据链路层的基本概念 二.数据链路层的功能概述 功能一:为网络层提供服务。无确认无连接服务&#xff0c;有确认无连接服务&#xff0c;有确认面向连接服务。 功能二:链路管理&#xff0c;即连接的建立、维持、释放(用于面向连接的服务)。 功能三:组帧 透明传输:…

基于Django的携程网Top热门景点数据可视化分析

前言&#xff1a; 今天给大家分享一个基于Django的携程网Top热门景点数据可视化分析项目&#xff0c;以下是该项目大大概内容 项目名称&#xff1a;基于Python&#xff08;django&#xff09;的携程Top热门景点数据可视化分析 涉及技术&#xff1a;Python&#xff0c;Djang…

为什么有了HTTP协议,还要有WebSocket协议?

文章目录 使HTTP不断轮询长轮询WebSocket是什么&#xff1f;怎么建立WebSocket连接WebSocket抓包WebSocket的消息格式WebSocket的使用场景总结 平时我们打开网页&#xff0c;比如购物网站某宝。都是点一下列表商品&#xff0c;跳转一下网页就到了商品详情。 从HTTP协议的角度来…

[C语言]——scanf和printf介绍

目录 一.printf 1.基本用法 2.占位符 3.占位符列举 4.输出格式 4.1限定宽度 4.2总是显示正负号 4.3限定小数位数 4.4输出部分字符串 二.scanf 1.基本用法 2.scanf的返回值 3.占位符 4.赋值忽略符 一.printf 1.基本用法 printf() 的作⽤是将参数⽂本输出到屏幕。…

winui开发笔记(五)应用程序图标

应用程序图标、发布者、显示名称大部分都在package.appxmanifest清单文件中&#xff0c;可以正常打开&#xff0c;也可以使用xml文本编辑器打开。 以下是一个正常的应用程序中所有的与图标相关的图片&#xff1a; 但是设置之后会有一圈白&#xff0c;包括在电脑最下边一行&…

chrome插件extensions获取所有窗口tab页和windows页

获取windows页&#xff1a;https://developer.chrome.com/docs/extensions/reference/api/windows?hlzh-cn 获取所有tabs页&#xff1a;https://developer.chrome.com/docs/extensions/reference/api/tabs?hlzh-cnchrome.tabshttps://developer.chrome.com/docs/extensions/…

MYSQL C++链接接口编程

使用MYSQL 提供的C接口来访问数据库,官网比较零碎,又不想全部精读一下,百度CSDN都是乱七八糟的,大部分不可用 官网教程地址 https://dev.mysql.com/doc/connector-cpp/1.1/en/connector-cpp-examples-connecting.html 网上之所以乱七八糟,主要是MYSQL提供了3个接口两个包,使用…

打家劫舍(java版)

&#x1f4d1;前言 本文主要是【动态规划】——打家劫舍(java版)的文章&#xff0c;如果有什么需要改进的地方还请大佬指出⛺️ &#x1f3ac;作者简介&#xff1a;大家好&#xff0c;我是听风与他&#x1f947; ☁️博客首页&#xff1a;CSDN主页听风与他 &#x1f304;每日一…

QT对象树 | 内存泄漏

使用 Qt 框架构建 GUI 界面的程序 //widget.cpp #include "widget.h" #include "ui_widget.h" #include <QLabel>Widget::Widget(QWidget *parent) //这里的parent的意思是父级指针: QWidget(parent) //调用父类的构造函数, ui(new Ui::Widget) …

外包干了3个月,技术倒退明显

先说情况&#xff0c;大专毕业&#xff0c;18年通过校招进入湖南某软件公司&#xff0c;干了接近6年的功能测试&#xff0c;今年年初&#xff0c;感觉自己不能够在这样下去了&#xff0c;长时间呆在一个舒适的环境会让一个人堕落!而我已经在一个企业干了四年的功能测试&#xf…

主备DNS服务器搭建并验证

目录 1. 配置静态网络 2. 配置主备DNS 2.1 DNS备服务器&#xff08;第二个虚拟机&#xff09; 2.2 两个虚拟机操作 2.3 备用服务器&#xff08;第二个虚拟机&#xff09;执行 2.4 两个虚拟机都添加DNS: 3. 验证 3.1 主DNS服务验证: 3.2 备用DNS服务器验证&am…

基于Springboot的足球俱乐部管理系统(有报告)。Javaee项目,springboot项目。

演示视频&#xff1a; 基于Springboot的足球俱乐部管理系统&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot项目。 项目介绍: 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&#xff…

C语言指针的初步认识--学习笔记(3)

1. 字符指针变量 在C语言中&#xff0c;字符串通常被视为字符数组&#xff0c;但它们可以有不同的表示方式。字符指针变量存储的是字符串的地址。这意味着&#xff0c;当你有一个字符串时&#xff0c;你可以通过改变字符指针的值来改变这个字符串&#xff0c;因为你实际上改变的…

22.欧拉方法、刚体模拟、流体模拟

一、一个粒子的模拟 规定一个物体在某一个时刻的速度和位置&#xff0c;如何解出某个时间之后它会出现在哪里 下图要求模拟一个粒子在速度场中要如何运动 速度场中&#xff0c;在任何一个位置&#xff0c;我们都有它的速度 写出来相当于是常微分方程 我们知道速度&#xff0c;…

find函数-秒了道题

秒了 笑死 还是规规矩矩做吧 string类的find()函数用于在字符串中查找字符或子串&#xff0c;返回第一个匹配的位置。 class Solution { public:int strStr(string haystack, string needle) {return haystack.find(needle);} };

基于灰狼算法GWO的城市三维无人机路径规划(复杂地形三维航迹路径规划)

摘要 本文提出了一种利用灰狼算法GWO来解决城市环境下无人机三维路径规划问题的方法。这种方法将复杂的无人机航迹规划任务转化为一个优化问题&#xff0c;然后运用灰狼算法GWO来解决这个优化问题。灰狼算法GWO是一种模拟灰狼种群捕猎行为的优化算法&#xff0c;它具备强大的全…

【TEE】内存完整性保护

Hash Functions&Merkle Tree 对读操作进行完整性检查&#xff0c;通过在加载的块上重新计算一个哈希&#xff0c;然后根据片外地址将得到的哈希与片上哈希比较。 缺点&#xff1a;不可承受的片上存储开销&#xff0c;并假设128位哈希和512位cache line&#xff0c;其开销为…

C++基于多设计模式下的同步异步日志系统day6

C基于多设计模式下的同步&异步日志系统day6 &#x1f4df;作者主页&#xff1a;慢热的陕西人 &#x1f334;专栏链接&#xff1a;C基于多设计模式下的同步&异步日志系统 &#x1f4e3;欢迎各位大佬&#x1f44d;点赞&#x1f525;关注&#x1f693;收藏&#xff0c;&am…