11.17Spring 注入部分

11.17Spring 注入部分

本章内容

  • Spring 依赖注入

  • Spring 注入内部Bean

  • Spring 注入集合


Spring 依赖注入

什么是依赖注入?

  • 依赖注入(Dependency Injection, DI),便于管理和测试应用程序

实现原理:

  • Java程序中当一个Java示例需要调用另一个Java实例的方法的时候需要手动new一个对象,通过对象去调用它的方法。

  • Spring框架中,被调用者实例由Spring容器创建,不再是调用者创建。这一过程被称为控制反转

Spring实现过程:

  • Spring容器在创建被调用者的实例时会自动将调用者需要的对象实例注入给调用者。

  • 调用者通过Spring容器获得被调用者实例

依赖注入的实现方式
  • 设值注入(setter)

  • 构造函数注入


构造函数注入:

概念:

IoC容器使用构造函数注意被依赖的实例。每一个参数代表一个依赖

setter注入:

概念:

IoC容器使用setter方法注入被依赖实例。

实现原理:

调用无参构造器或无参static工厂方法实例化Bean后,调用该Beansetter方法

Spring实例化Bean的过程:

  1. 调用默认的(无参)构造方法实例化Bean

  2. 通过Java反射机制调用对应的setXxx()方法为属性注入值

由上述可知setter注入的条件:

  • 提供一个默认的无参构造方法

  • 为需要注入的属性提供对应的set方法

Spring配置文件中的使用:

  • 为属性注入值:使用<bean>的子元素<property>

  • 构造注入值:使用<constructor-arg>标签定义构造方法。使用value设置该参数的值

构造函数注入

实现:

  • 使用<constructor-age>标签实现构造函数注入

标签包含refvaluetypeindex等属性。value属性用于注入基本数据类型以及字符串类型的值;ref属性用于注入已经定义好的 Beantype属性用来指定对应的构造函数,当构造函数有多个参数时,使用index属性指定参数的位置,index属性值从 0 开始。

示例:

  • 重构MainApp类,新增PersonMain

Man

package com.bean;

/**
* @description:Man类作为一个基类也是一个Bean对象
* @data: 2021/11/17 16:02
* @author: Lucfier
*/
public class Man {
   private String name;
   private int age;

   /* 提供set和get方法 */
   public void setName(String name) {
       this.name = name;
  }

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

   public String getName() {
       return name;
  }

   public int getAge() {
       return age;
  }

   /* 提供show方法 */
   public void show() {
       System.out.println("名称 :" + name + "\n年龄 :" + age);
  }

   /* 提供空参和带参构造方法 */
   public Man(){
       System.out.println("在Man的构造函数内!");
  }

   public Man(String name, int age) {
       System.out.println("在Man的带参构造函数内!");
       this.name = name;
       this.age = age;
  }
}

Person

package com.bean;

/**
* @description:创建Person类作为一个新增的Bean类
* @data: 2021/11/17 16:00
* @author: Lucifer
*/
public class Person {
   private Man man;

   public Person(Man man) {
       System.out.println("在Person的有参构造器内!");
       this.man = man;
  }

   public void man() {
       man.show();
  }
}

MainApp

package com.junkingboy;

import com.bean.Person;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
* @description:获取Spring当中的Bean.xml配置文件下的类和属性信息
* @data: 2021/11/15 11:20
* @author: Lucifer
*/
public class MainApp {
   public static void main(String[] args) {
       ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
       Person person = (Person) context.getBean("person");
       person.man();
  }
}

Beans.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-3.0.xsd">

   <bean id="man" class="com.bean.Man">
       <!-- 使用constructor-age 标签注入值 -->
       <constructor-arg value="bean" />
       <constructor-arg value="12" type="int" />
   </bean>

   <bean id="person" class="com.bean.Person">
       <!-- 使用constructor-age 标签注入值 -->
       <constructor-arg ref="man" type="com.bean.Man" />
   </bean>
</beans>

结论:

  • 出现的顺序是会先初始化ManBean对象,因为在PersonBean对象里面引用了ManBean配置。

  • <constructor-age>标签设置的值相当于定义了两个形参去实例化Man类,通过Man类的带参构造器。

  • 构造好了Man类的对象以后由于Person person会将Man对象作为参数带到Person类的带参构造器中。

  • 在使用Person构造器返回的Man类对象调用Man下的Show()方法

setter注入

实现:

  • 使用<property>标签

标签包含namerefvalue等属性。name用于指定参数名称;value属性用于注入基本数据类型以及字符串类型的值;ref属性用于注入已经定义好的Bean

示例:

  • 修改Person

package com.bean;

/**
* @description:创建Person类作为一个新增的Bean类
* @data: 2021/11/17 16:00
* @author: Lucifer
*/
public class Person {
   private Man man;

   /* 提供get和set方法 */
   public Man getMan() {
       return man;
  }

   public void setMan(Man man) {
       System.out.println("在setMan方法内!");
       this.man = man;
  }

   public void man() {
       man.show();
  }
}

结论:

  • 该写法实际在Bean的初始化顺序和上一个写法没区别

  • Spring Bean处使用的标签和上一个有所不同

Spring注入内部Bean

什么是Spring内部Bean

  • Java类内部定义的类称为内部类,在SpringBean内部定义的Bean称为Spring内部Bean

特点:

  • 不需要指定idname。如果指定了,容器不会将其作为区分Bean的标识符,会无视内部Beanscope属性。所以内部Bean总是匿名的,而且总是随着外部Bean创建。

在实际开发中很少注入内部 Bean,因为开发者无法将内部的 Bean 注入外部 Bean 以外的其它 Bean。

实现:

  • 注入内部Bean使用<property><constructor-arg>中的<bean>标签。

示例:

<?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-3.0.xsd">
   <bean id="outerBean" class="...">
       <property name="target">
           <!-- 定义内部Bean -->
           <bean class="..." />
       </property>
   </bean>
</beans>

Spring注入集合

概念:

Spring注入集合的意思是需要传递Java Collection类型的值

方式:

使用Spring提供的集合配置标签

标签说明
<list> 用于注入 list 类型的值,允许重复
<set> 用于注入 set 类型的值,不允许重复
<map> 用于注入 key-value 的集合,其中 key-value 可以是任意类型
<props> 用于注入 key-value 的集合,其中 key-value 都是字符串类型

示例:

  • 新建JavaCollection

package com.junkingboy;

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

/**
* @description:该类主要是java的list等属性
* @data: 2021/11/17 18:24
* @author: Lucifer
*/
public class JavaCollection {
   List manList;
   Set manSet;
   Map manMap;
   Properties manProp;

   /* 提供get和set方法 */
   public List getManList() {
       System.out.println("List Elements :" + manList);
       return manList;
  }

   public Set getManSet() {
       System.out.println("Set Elements :" + manSet);
       return manSet;
  }

   public Map getManMap() {
       System.out.println("Map Elements :" + manMap);
       return manMap;
  }

   public Properties getManProp() {
       System.out.println("Properties Elements :" + manProp);
       return manProp;
  }

   public void setManList(List manList) {
       this.manList = manList;
  }

   public void setManSet(Set manSet) {
       this.manSet = manSet;
  }

   public void setManMap(Map manMap) {
       this.manMap = manMap;
  }

   public void setManProp(Properties manProp) {
       this.manProp = manProp;
  }
}

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
  http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

<!--   &lt;!&ndash; 针对修改后的HelloWorld类的方法进行配置 &ndash;&gt;-->
<!--   <bean id="helloWorld" class="com.junkingboy.HelloWorld" scope="singleton" init-method="init" destroy-method="destroy">-->
<!--       <property name="message" value="Hello New World!" />-->
<!--   </bean>-->

<!--   &lt;!&ndash; 设置init-method指定的初始化方法对User类下的方法进行初始化 &ndash;&gt;-->
<!--   <bean id="init" class="com.bean.User" init-method="init" />-->

<!--   &lt;!&ndash; 设置destroy-method指定需要销毁的Spring Bean对象使用的销毁方法 &ndash;&gt;-->
<!--   <bean id="destroy" class="com.bean.ExampleBean" destroy-method="init" />-->

<!--   &lt;!&ndash; 使用parent属性将hellochina定义为helloworld的子类 &ndash;&gt;-->
<!--   <bean id="helloWorld" class="com.junkingboy.HelloWorld">-->
<!--       &lt;!&ndash; 定义类当中的属性 &ndash;&gt;-->
<!--       <property name="message1" value="HelloWorld!" />-->
<!--       <property name="message2" value="HelloWorld2!" />-->
<!--   </bean>-->

<!--   <bean id="helloChina" class="com.junkingboy.HelloChina" parent="helloWorld">-->
<!--       &lt;!&ndash; 定义类当中的属性并且将类设置成helloWorld的子类 &ndash;&gt;-->
<!--       <property name="message1" value="HelloChinaNo1" />-->
<!--       <property name="message3" value="HelloChinaNo3" />-->
<!--   </bean>-->
<!--   &lt;!&ndash; 针对新构建的HelloWorld以及新添加进来的类进行bean.xml文件的配置 &ndash;&gt;-->
<!--   <bean id="helloWorld" class="com.junkingboy.HelloWorld"-->
<!--         init-method="init" destroy-method="destroy">-->
<!--       &lt;!&ndash; 定义类当中的属性的值 &ndash;&gt;-->
<!--       <property name="message" value="New World!" />-->
<!--   </bean>-->

<!--   &lt;!&ndash; 注册处理器 &ndash;&gt;-->
<!--   <bean class="com.junkingboy.InitHelloWorld" />-->
<!--   <bean class="com.junkingboy.InitHelloWorld2" />-->
<!--   <bean id="man" class="com.bean.Man">-->
<!--       &lt;!&ndash; 使用constructor-age 标签注入值 &ndash;&gt;-->
<!--       <constructor-arg value="bean" />-->
<!--       <constructor-arg value="12" type="int" />-->
<!--   </bean>-->

<!--   <bean id="person" class="com.bean.Person">-->
<!--       &lt;!&ndash; 使用constructor-age 标签注入值 &ndash;&gt;-->
<!--       <constructor-arg ref="man" type="com.bean.Man" />-->
<!--   </bean>-->
<!--   &lt;!&ndash; 使用setter方法进行属性注入 &ndash;&gt;-->
<!--   <bean id="person" class="com.bean.Person">-->
<!--       &lt;!&ndash; 使用property标签进行注入 &ndash;&gt;-->
<!--       <property name="man" ref="man" />-->
<!--   </bean>-->
   <bean id="javaCollection" class="com.junkingboy.JavaCollection">
       <!-- 使用property设置每一个java Collection属性 -->
       <property name="manList">
           <list>
               <value>JunkingBoy</value>
               <value>百度</value>
               <value>Byte Dance</value>
               <value>Tencent</value>
               <value>网易</value>
           </list>
       </property>

       <property name="manSet">
           <set>
               <value>JunkingBoy</value>
               <value>百度</value>
               <value>Byte Dance</value>
               <value>Tencent</value>
               <value>网易</value>
           </set>
       </property>

       <!--
       由于map是key-value的形式,所以需要创建key和value。用属性表示
       -->
       <property name="manMap">
           <map>
               <entry key="1" value="JunkingBoy" />
               <entry key="2" value="百度" />
               <entry key="3" value="ByteDance" />
               <entry key="4" value="Tencent" />
               <entry key="5" value="网易" />
           </map>
       </property>

       <property name="manProp">
           <props>
               <prop key="one">JunkingBoy</prop>
               <prop key="one">JunkingBoy</prop>
               <prop key="two">百度</prop>
               <prop key="three">ByteDance</prop>
           </props>
       </property>
   </bean>
</beans>

MainApp:调用get方法获取值

package com.junkingboy;

import com.bean.Person;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
* @description:获取Spring当中的Bean.xml配置文件下的类和属性信息
* @data: 2021/11/15 11:20
* @author: Lucifer
*/
public class MainApp {
   public static void main(String[] args) {
       ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
       JavaCollection jc = (JavaCollection) context.getBean("javaCollection");

       /* 调用相对于属性的get方法 */
       jc.getManList();
       jc.getManSet();
       jc.getManMap();
       jc.getManProp();
  }
}
注入Bean引用

概念:

  • 在集合元素中注入Bean

示例:

<?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-3.0.xsd">

   <bean id="javaCollection" class="com.junkingboy.JavaCollection">
       <property name="manList">
           <list>
               <ref bean="javaCollection" />
               <ref bean="propertyResolver" />
               <value>JunkingBoy</value>
           </list>
       </property>

       <property name="manMap">
           <map>
               <entry key="one" value="JunkingBoy" />
               <entry key="two" value-ref="javaCollection" />
               <entry key="three" value-ref="propertyResolver" />
           </map>
       </property>
   </bean>
</beans>
注入null和空字符串的值

区别:

  • 注入null使用标签

  • 注入空字符串则是在值后面设置

注入null

<bean id="..." class="...">
<property name="name"><null /></property>
</bean>

等效于:

xxx.setName(null);

注入空字符串:

<bean id="..." class="...">
<property name="name" value=" " />
</bean>

等效于:

xxx.setName("");
posted @ 2022-01-18 19:04  俊king  阅读(184)  评论(0)    收藏  举报