zoukankan      html  css  js  c++  java
  • Spring框架3:spring的依赖注入

    本系列笔记均是对b站教程https://www.bilibili.com/video/av47952931 的学习笔记,非本人原创

    spring的依赖注入(DI)

    什么是依赖注入:

    作者:Angry Bugs
    链接:https://www.zhihu.com/question/32108444/answer/581948457
    来源:知乎
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
    
    看了几个高赞答案,感觉说得还是太啰嗦了。依赖注入听起来好像很复杂,但是实际上炒鸡简单,一句话说就是:本来我接受各种参数来构造一个对象,现在只接受一个参数——已经实例化的对象。也就是说我对对象的『依赖』是注入进来的,而和它的构造方式解耦了。构造它这个『控制』操作也交给了第三方,也就是控制反转。不举抽象的什么造汽车或者小明玩儿手机的例子了。一个很实际的例子,比如我们要用 redis 实现一个远程列表。耦合成一坨的代码可以是这样写,其中我们需要自己构造需要用的组件:class RedisList:
        def __init__(self, host, port, password):
            self._client = redis.Redis(host, port, password)
    
        def push(self, key, val):
            self._client.lpush(key, val)
    
    l = RedisList(host, port, password)依赖翻转之后是这样的:class RedisList:
        def __init__(self, redis_client)
            self._client = redis_client
    
        def push(self, key, val):
            self._client.lpush(key, val)
    
    redis_client = get_redis_client(...)
    l = RedisList(redis_client)看起来好像也没什么区别,但是考虑下面这些因素:线下线上环境可能不一样,get_redis_client 函数在线上可能要做不少操作来读取到对应的配置,可能并不是不是一个简单的函数。redis 这个类是一个基础组件,可能好多类都需要用到,每个类都去自己实例化吗?如果需要修改的话,每个类都要改。我们想依赖的是 redis 的 lpush 方法,而不是他的构造函数。所以把 redis 这个类的实例化由一个单一的函数来做,而其他函数只调用对应的接口是有意义的。就这么简单啊。。
    
    构造函数注入

    AccountServiceImpl :

    package com.jiading.service.impl;
    
    import com.jiading.service.IAccountService;
    
    import java.util.Date;
    
    /*
    账户的业务层实现类
     */
    public class AccountServiceImpl implements IAccountService {
        //如果是经常变化的数据,并不适用于注入的方式
        private String name;
        private Integer age;//基本类型的包装类
        private Date birthday;
    
        public AccountServiceImpl(String name,Integer age,Date birthday){
            this.name=name;
            this.age=age;
            this.birthday=birthday;
        }
        public void saveAccount() {
            System.out.println("service中的saveAccount方法执行了+"+name+","+age+","+birthday);
        }
    }
    
    <?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">
        <!-- spring的依赖注入
          依赖注入:Dependency Injection
          IOC的作用:
              降低程序间的耦合(依赖关系)
          依赖关系的管理交给了spring来维护
          依赖关系:
            在当前类需要用到其他类的对象,由spring为我们提供,我们在配置文件中说明
          依赖关系的维护:
            称之为依赖注入
          依赖注入:
            能注入的数据类型:
                1. 基本类型和String
                2. 其他的bean类型(在配置文件中或者注解配置过的bean)
                3. 复杂类型/集合类型
            注入方式:
                1. 使用构造函数提供
                2. 使用set方法提供
                3. 使用注解提供
        -->
        <!-- 构造函数注入:
            使用标签constructor-arg
            标签出现的位置:bean标签内部
            标签的属性:
                type:要注入的数据的数据类型,该类型也是构造函数中某个或者某些参数的类型
                index:用于指定要注入的数据给构造函数中指定索引位置的参数赋值
                name:用于指定要注入的数据给构造函数中指定名称的参数赋值
                以上三个用于指定给构造函数中哪个参数赋值
                value:用于提供基本类型和String类型的数据
                ref:用于指定其他bean类型数据,它指的就是在spring的IOC核心容器中出现过的bean对象
        -->
        <bean id="accountService" class="com.jiading.service.impl.AccountServiceImpl">
            <constructor-arg name="name" value="test"></constructor-arg>
            <constructor-arg name="age" value="18"></constructor-arg>
            <!-- 那个18会由框架自动解析为Integer类型-->
            <constructor-arg name="birthday" ref="now"></constructor-arg>
        </bean>
        <!-- 配置一个日期对象-->
        <bean id="now" class="java.util.Date"></bean>
        <!-- 构造函数注入
        优势:
            在获取bean对象时,注入数据是必须的操作,否则对象无法实例化成功,不容易被错误调用
        弊端:
            改变了bean对象的实例化方式,使我们在创建对象时如果用不到这些数据,也必须提供
        实际开发中,由于其不太灵活,一般不采用这种方式
        -->
    </beans>
    
    set方法注入
    package com.jiading.service.impl;
    
    import com.jiading.service.IAccountService;
    
    import java.util.Date;
    
    /*
    账户的业务层实现类
     */
    public class AccountServiceImpl2 implements IAccountService {
        //如果是经常变化的数据,并不适用于注入的方式
        private String name;
        private Integer age;//基本类型的包装类
        private Date birthday;
    
    
        public void saveAccount() {
            System.out.println("service中的saveAccount方法执行了+"+name+","+age+","+birthday);
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public void setAge(Integer age) {
            this.age = age;
        }
    
        public void setBirthday(Date birthday) {
            this.birthday = birthday;
        }
    }
    
        <bean id="accountService2" class="com.jiading.service.impl.AccountServiceImpl2">
            <!-- set方法注入
                涉及到标签:property
                出现的1位置:bean内部
                标签的属性:
                    name:用于指定注入时所调用的set方法名称(不包括set本身,只包括属性名,例如方法叫setName,这里写name就好)
                    value:用于提供基本类型和String类型的数据
                    ref:用于指定其他bean类型数据,它指的就是在spring的IOC核心容器中出现过的bean对象
                优势:创建对象时没有明确的界限,可以直接使用默认构造函数
                弊端:如果有某个成员必须有值,则获取对象时有可能set方法没有被执行(因为和构造函数方式相比,set方法更多的是调用者主动加property,缺少强制性
                相比构造函数注入,是更常用的方式
            -->
            <property name="name" value="Test"></property>
            <property name="age" value="21"></property>
            <property name="birthday" ref="now"></property>
        </bean>
    	```
    	##### 复杂类型的注入
    	```java
    	package com.jiading.service.impl;
    
    import com.jiading.service.IAccountService;
    
    import java.util.*;
    
    /*
    账户的业务层实现类
     */
    public class AccountServiceImpl3 implements IAccountService {
        private String[] myStrs;
        private List<String> myList;
    
        public void setMyStrs(String[] myStrs) {
            this.myStrs = myStrs;
        }
    
        public void setMyList(List<String> myList) {
            this.myList = myList;
        }
    
        public void setMySet(Set<String> mySet) {
            this.mySet = mySet;
        }
    
        public void setMyMap(Map<String, String> myMap) {
            this.myMap = myMap;
        }
    
        public void setMyProps(Properties myProps) {
            this.myProps = myProps;
        }
    
        private Set<String> mySet;
        private Map<String, String> myMap;
        private Properties myProps;
    
        public void saveAccount() {
            System.out.println(Arrays.toString(myStrs));
            System.out.println(myList);
            System.out.println(mySet);
            System.out.println(myMap);
            System.out.println(myProps);
        }
    }
    
    	<!-- 复杂类型的注入/集合类型的注入-->
        <bean id="accountService3" class="com.jiading.service.impl.AccountServiceImpl3">
            <property name="MyStrs">
                <array>
                    <!-- 用于给List结构集合注入的标签有listarrayset。因为结构一样,所以可以互换-->
                    <value>AAA</value>
                    <value>BBB</value>
                    <value>CCC</value>
                </array>
            </property>
            <property name="MyList">
                <list>
                    <value>AAA</value>
                    <value>BBB</value>
                    <value>CCC</value>
                </list>
            </property>
            <property name="MySet">
                <set>
                    <value>AAA</value>
                    <value>BBB</value>
                    <value>CCC</value>
                </set>
            </property>
            <property name="myMap">
                <map>
                    <!-- 用于给map结构集合注入的标签有mapprops。因为结构一样,所以可以互换-->
                    <entry key="testA" value="aaa"></entry>
                    <entry key="testB">
                        <value>bbb</value>
                    </entry>
                </map>
            </property>
            <property name="myProps">
                <props>
                    <prop key="testC">ccc</prop>
                    <prop key="testD">ddd</prop>
                </props>
            </property>
        </bean>
    

    可以看出,通过依赖注入,我们可以直接传入实例化对象,参数可以在配置文件中配置完成,省去了每次传入的麻烦

  • 相关阅读:
    信息技术手册查重错误比对分析程序开发记录04
    信息技术手册查重错误比对分析程序开发记录03
    信息技术手册查重错误比对分析程序开发记录02
    第一周博客01——设计模式原则总结
    react 性能优化
    h5 rem js自动适配
    JavaScript深拷贝实现原理简析
    word,excel,ppt在线预览功能
    react-route4 学习记录
    README 语法记录
  • 原文地址:https://www.cnblogs.com/jiading/p/12368799.html
Copyright © 2011-2022 走看看