Spring Framework学习之DI——依赖注入


Spring 依赖注入(DI Dependency Injection),可以自动帮我们解决类与类之间的各种依赖问题。通常公司中的项目都包含很多的类,而这些类与类之间都有各种依赖关系,比如:组合、聚合、依赖等。通过Spring的DI功能,结合IOC容器, 我们可以把这些复杂的关系交由Spring来管理, 我们在使用时,Spring会自动帮我们把依赖的对象注入进来,大大降低开发难度。
Spring中的依赖注入主要包含两种:通过构造方法中的注入和通过Setter方法注入

setter注入

注入匿名内部bean

内部bean不需要指定id、name属性,如果指定了也无法在外部直接获取,另外内部bean也不支持scope属性,因为内部bean始终是由外部bean创建的,并且只能在外部bean中使用

<!-- 给Student注入一个匿名内部bean -->
第一种:
	<!-- setter注入 -->
	    <bean id="student" class="com.lanou3g.spring.bean.Student">
	        <property name="fruit">
	            <bean class="com.lanou3g.spring.simple.Apple" >
	            	<property name="kind" value="CyanApple"
				</bean>
	        </property>
	    </bean>
第二种:
	<!-- 构造方法注入 -->
		<bean id="student" class="com.lanou3g.spring.bean.Student">
	        <constructor-argname="fruit">
	            <bean class="com.lanou3g.spring.simple.Apple" >
	            	<property name="kind" value="CyanApple"
				</bean>
	        </property>
	    </bean>

注入集合类型属性

<!-- 注入集合、Map类型参数 -->
    <bean id="student" class="com.lanou3g.spring.bean.Student">
        <property name="hobbies">
            <list>
            	<!-- 普通元素 -->
                <value>游泳</value>
                <value type="java.lang.Integer">0034</value>
                <!-- 引用类型元素 -->
                <ref bean="study" />
            </list>
        </property>
        <property name="gameTitles">
            <map>
                <entry key="LOL" value="嘴强王者"></entry>
                <entry key="王者农药" value="甩锅大神"></entry>
                <entry key="和平精英" value="菜鸡"></entry>
            </map>
        </property>
    </bean>

注入null、空字符串类型属性值

<bean id="student" class="com.lanou3g.spring.bean.Student">
        <property name="age" value="" />
</bean>
<bean id="student" class="com.lanou3g.spring.bean.Student">
        <property name="age">
        	<null />
        </property>
</bean>

注入复合属性值

两个关联的java类
@Setter
@Getter
public class People{
	private Student student;
}
@Setter
@Getter
public class Student{
	private Integer age;
}
xml配置注入复合属性
<bean id="people" class="com.lanou3g.spring.bean.People">
	<property name="student" ref="student" />
	<property name="student.age" value="23" />
</bean>
<bean id="student" class="com.lanou3g.spring.bean.Student" />
获取注入复合属性的属性值
public static void main( String[] args ) {
        ApplicationContext cpxac = new AnnotationConfigApplicationContext(App.class);
        People people = cpxac.getBean(People.class);
        System.out.println(people.getStudent().getAge());
}

注入外部properties文件中的属性值

jdbc.properties
jdbc.driver.className=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mydb
jdbc.username=root
jdbc.password=root
jdbc.maxIdle=3
jdbc.minIdle=1
jdbc.maxActive=10
xml配置引入外部的properties文件
    <!-- 方式一 -->
	    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
	        <property name="location" value="classpath:jdbc.properties" />
	    </bean>

    <!-- 方式二 -->
	    <!-- 通过方式二这种方式和方式一等效,推荐使用 -->
	    <context:property-placeholder location="classpath:jdbc.properties"/>
	
		<!-- 无论用方式一还是方式二都需配置下面的节点 -->
	    <!-- 将外部properties文件中的属性注入到bean中 -->
	    <bean id="jdbcConf" class="com.lanou3g.spring.bean.JDBCConf">
	        <property name="url" value="${jdbc.url}" />
	        <property name="driver" value="${jdbc.driver}" />
	        <property name="userName" value="${jdbc.user}" />
	        <property name="password" value="${jdbc.password}" />
	    </bean>

通过p命名空间注入属性

要想使用p命名空间,必须要加相应的p的schema
xmlns:p="http://www.springframework.org/schema/p"
通过p命名空间来注入属性
<!--<bean id="yunjie1" class="com.lanou3g.spring.bean.Student">
	<property name="sname" value="张三" />
</bean>-->
    
<!-- 等效于上面的配置 -->
<bean id="yunjie1" class="com.lanou3g.spring.bean.Student" p:sname="张三" />

构造方法注入

package x.y;

public class ThingOne {
		private int age;
  	private String sname;
  	private int gender;
  	private ThingTwo thingTwo;
    public ThingOne(int age, ThingTwo thingTwo, String sname, int gender) {
        this.age = age;
				this.thingTwo = thingTwo;
      	this.sname = sname;
      	this.gender = gender;
  	    // ...
    }
}


public class ThingTwo {
  // ...
}
<beans>
	<!-- 有参注入 -->
    <bean id="beanOne" class="x.y.ThingOne">
        <!-- 通过此标签注入构造方法中的参数 -->
      	<constructor-arg  name="age" value="18" />
      	<constructor-arg  type="java.lang.String" value="张三" />	
      	<constructor-arg ref="beanTwo"/>
    </bean>
    
	<!-- 无参注入 -->
    <bean id="beanTwo" class="x.y.ThingTwo"/>
</beans>
constructor-arg标签属性
属性名取值含义
name字符串构造参数的名称
value数值、字符串构造参数的属性值,只适用于简单类型
type类的全名构造参数的类型,如果是简单类型,需要指定对应的封装类型
如果构造参数中有多个命中的类型,按照配置的先后顺序注入(可以通过配合index属性改变默认顺序)
index数值构造参数的位置,从0开始
ref其他在Spring容器中配置的bean的name或者id将容器中的其他bean作为构造参数注入

通过c命名空间注入构造参数

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:c="http://www.springframework.org/schema/c"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="beanTwo" class="x.y.ThingTwo"/>
    <bean id="beanThree" class="x.y.ThingThree"/>

    <!-- 传统方式注入构造参数 -->
    <bean id="beanOne" class="x.y.ThingOne">
        <constructor-arg name="thingTwo" ref="beanTwo"/>
        <constructor-arg name="thingThree" ref="beanThree"/>
        <constructor-arg name="email" value="something@somewhere.com"/>
    </bean>

    <!-- c命名空间方式注入构造参数 -->
    <bean id="beanOne" class="x.y.ThingOne" c:thingTwo-ref="beanTwo"
        c:thingThree-ref="beanThree" c:email="something@somewhere.com"/>

</beans>

自动装配

自动装配允许我们不用显示给某个bean注入依赖的属性或者构造参数,而交由Spring自动帮我们注入所需的依赖。

Spring给我们提供了以下四种选项

自动装配模式说明
no(默认值) 禁止Spring帮我们自动装配依赖,所有依赖由开发者显示注入。
byName按照bean的名称注入。比如beanA有一个属性beanB需要注入,如果beanA配置了自动装配模式是byName,那么Spring会在容器中找bean的名称为beanB的bean,找到后自动帮我们注入到beanA中。如果没找到,则不会注入。
byType按照bean的类型注入。byType模式需要保证容器中符合注入的类型的bean只有一个,如果匹配的类型有不止一个bean,那么会直接抛出运行时异常。如果没有一个匹配类型的bean,则不会注入。
constructor类似于byType。但这种模式应用的对象是构造参数。如果构造参数需要注入参数类型的bean有不止一个,同样会抛出运行时异常。

byName和byType方式

java bean类
@Setter
@Getter
public class People {
    private String pname;
    private Student student;
}

@Setter
@Getter
public class Student {
    private int  age;
}
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">

	<!-- 给Student类中的age属性赋值 -->
    <bean id="student" class="com.lanou3g.spring.bean.Student">
        <property name="age" value="25" />
    </bean>
    
	<!-- byName方式 -->
    <bean id="peopleByName" class="com.lanou3g.spring.bean.People"
          autowire="byName">
        <property name="pname" value="张三" />
    </bean>

	<!-- byType方式 -->
    <bean id="peopleByType" class="com.lanou3g.spring.bean.People"
          autowire="byType">
        <property name="pname" value="张三" />
    </bean>

</beans>
程序运行入口
public class App {

    public static void main( String[] args ) {
        ClassPathXmlApplicationContext cpxac = new ClassPathXmlApplicationContext("applicationContext.xml");
        cpxac.registerShutdownHook();

        // 按照名称自动注入属性
        People peopleByName= cpxac.getBean("peopleByName" , People.class);
        System.out.println("byName名字: " + peopleByName.getPname());
        System.out.println("byName学生年龄:" + peopleByName.getStudent().getAge());

        // 按照名称自动注入属性
        People peopleByType= cpxac.getBean("peopleByType" , People.class);
        System.out.println("byType名字: " + peopleByType.getPname());
        System.out.println("byType学生年龄:" + peopleByType.getStudent().getAge());

    }
}

constructor方式

java bean类
@Setter
@Getter
public class People {
    private String pname;
    private Student student;
    
    public People() {}

    public People(Student student) {
        this.student = student;
    }
}

@Setter
@Getter
public class Student {
    private int  age;
}
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">

	<!-- 给Student类中的age属性赋值 -->
    <bean id="student" class="com.lanou3g.spring.bean.Student">
        <property name="age" value="25" />
    </bean>
    
	<!-- byConstructor方式 -->
    <bean id="peopleByConstructor" class="com.lanou3g.spring.bean.People"
          autowire="constructor">
        <property name="pname" value="张三" />
    </bean>

</beans>
程序运行入口
public class App {

    public static void main( String[] args ) {
        ClassPathXmlApplicationContext cpxac = new ClassPathXmlApplicationContext("applicationContext.xml");
        cpxac.registerShutdownHook();

        // 按照名称自动注入属性
        People peopleByConstructor = cpxac.getBean("peopleByConstructor" , People.class);
        System.out.println("ByConstructor名字: " + peopleByConstructor.getPname());
        System.out.println("ByConstructor学生年龄:" + peopleByConstructor.getStudent().getAge());
    }
}

将某个bean从自动装配候选中排除

我们可以通过给bean添加autowire-candidate属性,并且设置为false,从而让这个bean不参与自动装配(不会被自动装配到其他bean上)

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值