Spring5【四】依赖注入(DI)

6、依赖注入(DI)

依赖注入(Dependency Injection,DI)

  • 依赖 : 指 bean 对象的创建依赖于容器,bean 对象的依赖资源。
  • 注入 : 指 bean 对象中的所有属性由容器来注入

6.1 构造器注入

之前的案例已经使用

6.2 set 方式注入【重点】

6.2.0 环境搭建

  1. 复杂类型

    public class Address {
        private String address;
    
        getXxx()/setXxx()/toString()
    }
    
  2. 真实测试对象

    public class Student {
    
        private String name;
        private Address address;
        private String[] books;
        private List<String> hobbies;
        private Map<String,String> card;
        private Set<String> games;
        private String wife;
        private Properties info;
        
        getXxx()/setXxx()/toString()
    }
    
  3. 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
            https://www.springframework.org/schema/beans/spring-beans.xsd">
    
        <bean id="student" class="com.song.pojo.Student">
            <!--第一种:普通值注入,value -->
            <property name="name" value="张三"/>
        </bean>
    
    </beans>
    
  4. 测试类

    public class MyTest {
    	public static void main(String[] args) {
        	ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        	Student student = (Student)context.getBean("student");
        	System.out.println(student.getName());
    	}
    }
    

6.2.1 普通值(常量)注入

<bean id="student" class="com.song.pojo.Student">
    <!--普通值注入,value -->
    <property name="name" value="张三"/>
</bean>

6.2.2 Bean 注入,引用

<bean id="address" class="com.song.pojo.Address">
    <property name="address" value="北京"/>
</bean>

<bean id="student" class="com.song.pojo.Student">
    <!--Bean 注入,ref-->
    <property name="address" ref="address"/>
</bean>

6.2.3 数组注入

<!--数组注入-->
<property name="books">
    <array>
        <value>红楼梦</value>
        <value>西游记</value>
        <value>水浒传</value>
        <value>三国演义</value>
    </array>
</property>

6.2.4 list 注入

<!-- list 注入-->
<property name="hobbies">
    <list>
        <value>打球</value>
        <value>唱歌</value>
        <value>跳舞</value>
    </list>
</property>

6.2.5 map 注入

<!-- map 注入-->
<property name="card">
    <map>
        <entry key="身份证" value="123456"/>
        <entry key="银行卡" value="456789"/>
    </map>
</property>

6.2.6 set 注入

<!-- set 注入-->
<property name="games">
    <set>
        <value>LOL</value>
        <value>COC</value>
        <value>BOB</value>
    </set>
</property>

6.2.7 null 注入

<!-- null 注入-->
<!--<property name="wife" value=""/>-->
<property name="wife">
    <null/>
</property>

6.2.8 properties 注入

<!-- properties 注入-->
<property name="info">
    <props>
        <prop key="driver">2018020202</prop>
        <prop key="url">男</prop>
        <prop key="username">张三</prop>
        <prop key="password">123456</prop>
    </props>
</property>

测试:

public static void main(String[] args) {
    ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
    Student student = (Student)context.getBean("student");
    System.out.println(student.toString());
}

测试结果:

Student{
     name='张三',
     address=Address{address='北京'},
     books=[红楼梦, 西游记, 水浒传, 三国演义],
     hobbies=[打球, 唱歌, 跳舞],
     card={身份证=123456,银行卡=456789},
     games=[LOL, COC, BOB],
     wife='null',
     info={password=123456,url=男,driver=2018020202,userme=张三}
}

6.3 拓展方式注入(p 命名空间和 c 命名空间)

实体类:

public class User {

    private String name;
    private int age;

    有参构造/无参构造/get/set/toString……
}

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"
       xmlns:p="http://www.springframework.org/schema/p"
       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">

    <!-- p 命名空间注入,可以直接注入属性的值:property -->
    <bean id="user" class="com.song.pojo.User" p:name="张三" p:age="18"/>

    <!-- c 命名空间注入,通过构造器注入:construct-arg -->
    <bean id="user2" class="com.song.pojo.User" c:age="18" c:name="李四"/>

</beans>

测试:

@Test
    public void test2(){
        ApplicationContext context = new ClassPathXmlApplicationContext("userbeans.xml");
//        User user = (User) context.getBean("user");
//        User user = context.getBean("user", User.class); // 第二个参数写上,就不用强转了
        User user = context.getBean("user2", User.class);
        System.out.println(user);

    }

结果:

//User{name='张三', age=18}
User{name='李四', age=18}

注意:不能直接使用,必须先在头文件中加入约束文件。

  • p 命名空间约束文件:xmlns:p="http://www.springframework.org/schema/p"

  • p 命名空间类似于 set 方法注入,bean 实体类中必须有无参构造

  • c 命名空间约束文件:xmlns:c="http://www.springframework.org/schema/c"

  • c 命名空间注入类似于构造器注入,bean 实体类中必须有有参构造

6.4 bean 的作用域(Bean scopes)

在 Spring 中,那些组成应用程序的主体及由 Spring IoC 容器所管理的对象,被称之为 bean。简单地讲,bean 就是由 IoC 容器初始化、装配及管理的对象。

官方文档:

Scope Description
singleton (Default) Scopes a single bean definition to a single object instance for each Spring IoC container.
prototype Scopes a single bean definition to any number of object instances.
request Scopes a single bean definition to the lifecycle of a single HTTP request. That is, each HTTP request has its own instance of a bean created off the back of a single bean definition. Only valid in the context of a web-aware Spring ApplicationContext.
session Scopes a single bean definition to the lifecycle of an HTTP Session. Only valid in the context of a web-aware Spring ApplicationContext.
application Scopes a single bean definition to the lifecycle of a ServletContext. Only valid in the context of a web-aware Spring ApplicationContext.
websocket Scopes a single bean definition to the lifecycle of a WebSocket. Only valid in the context of a web-aware Spring ApplicationContext.
  1. 单例模式(Spring 默认机制)

    当一个 bean 的作用域为 Singleton,那么 Spring IoC 容器中只会存在一个共享的 bean 实例,并且所有对 bean 的请求,只要 id 与该 bean 定义相匹配,则只会返回 bean 的同一实例。

    Singleton 是单例类型,就是在创建起容器时就同时自动创建了一个 bean 的对象,不管你是否使用,他都存在了,每次获取到的对象都是同一个对象。

    注意:Singleton 作用域是 Spring 中的缺省作用域。显式表示为:

    <bean id="user" class="com.song.pojo.User" scope="singleton"/>
    
    @Test
    public void test2(){
        ApplicationContext context = new ClassPathXmlApplicationContext("userbeans.xml");
    
        User user = context.getBean("user", User.class);
        User user2 = context.getBean("user", User.class);
        System.out.println(user == user2); // true
    }
    
  2. 原型模式

    每次从容器中 get 时,都会产生一个新对象。

    当一个 bean 的作用域为 Prototype,表示一个 bean 定义对应多个对象实例。Prototype 作用域的 bean 会导致在每次对该 bean 请求(将其注入到另一个 bean 中,或者以程序的方式调用容器的 getBean() 方法)时都会创建一个新的 bean 实例。

    Prototype 是原型类型,它在我们创建容器的时候并没有实例化,而是当我们获取bean的时候才会去创建一个对象,而且我们每次获取到的对象都不是同一个对象

    根据经验,对有状态的 bean 应该使用 prototype 作用域,而对无状态的 bean 则应该使用 singleton 作用域。

    <bean id="user" class="com.song.pojo.User" scope="prototype"/>
    
    @Test
    public void test2(){
        ApplicationContext context = new ClassPathXmlApplicationContext("userbeans.xml");
    
        User user = context.getBean("user", User.class);
        User user2 = context.getBean("user", User.class);
        System.out.println(user == user2); // false
    }
    
  3. 其余的 request、session、application 这些只能在 web 开发中使用,只能用在基于 web 的 Spring ApplicationContext 环境。

posted @ 2020-06-20 19:29  Song-zw  阅读(145)  评论(0编辑  收藏  举报