SpringIOC随笔(六)-依赖注入(DI)

SpringIOC随笔(六)-依赖注入(DI)

  • DI(Dependency Injection)

  • 概念:对象之间的关系的装配交给容器来管理。

  • 注入的方式:

    1. 构造注入:

      1. 顾名思义,构造注入就是使用构造方法注入,所以使用构造注入肯定要写对应的构造方法。下面直接上例子:

      2.  public class User implements Serializable {
            private static final long serialVersionUID = 84601116866236075L;
        
            private String username;
            private String password;
            private Department department;
        
            public User() {
            }
        
            public User(String username, String password) {
                this.username = username;
                this.password = password;
            }
        
            public User(String username, String password, Department department) {
                this.username = username;
                this.password = password;
                this.department = department;
            }
        
            public String getUsername() {
                return username;
            }
        
            public void setUsername(String username) {
                this.username = username;
            }
        
            public String getPassword() {
                return password;
            }
        
            public void setPassword(String password) {
                this.password = password;
            }
        
            public Department getDepartment() {
                return department;
            }
        
            public void setDepartment(Department department) {
                this.department = department;
            }
        
            @Override
            public String toString() {
                return "User{" +
                        "username='" + username + '\'' +
                        ", password='" + password + '\'' +
                        ", department=" + department +
                        '}';
            }
        }
        public class Department implements Serializable {
            private static final long serialVersionUID = -7390074405145933835L;
        
            private Integer id;
        
            private String departmentName;
        
            private String address;
        
            public Department() {
            }
        
            public Department(Integer id, String departmentName, String address) {
                this.id = id;
                this.departmentName = departmentName;
                this.address = address;
            }
        
            public Integer getId() {
                return id;
            }
        
            public void setId(Integer id) {
                this.id = id;
            }
        
            public String getDepartmentName() {
                return departmentName;
            }
        
            public void setDepartmentName(String departmentName) {
                this.departmentName = departmentName;
            }
        
            public String getAddress() {
                return address;
            }
        
            public void setAddress(String address) {
                this.address = address;
            }
        
            @Override
            public String toString() {
                return "Department{" +
                        "id=" + id +
                        ", departmentName='" + departmentName + '\'' +
                        ", address='" + address + '\'' +
                        '}';
            }
        }
        
      3. <?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">
        
            <bean id="user" class="com.fxyh.spring.di.User">
                <constructor-arg index="0" value="zhangsan"/>
                <constructor-arg index="1" value="123456"/>
                <!--ref方式-->
                <!--<constructor-arg index="2" ref="department"/>-->
                <constructor-arg index="2">
                    <!--内部bean方式-->
                    <bean class="com.fxyh.spring.di.Department">
                        <constructor-arg index="0" value="2"/>
                        <constructor-arg index="1" value="Ali"/>
                        <constructor-arg index="2" value="hangzhou"/>
                    </bean>
                </constructor-arg>
            </bean>
        
            <bean id="department" class="com.fxyh.spring.di.Department">
                <constructor-arg index="0" value="1"/>
                <constructor-arg index="1" value="Baidu"/>
                <constructor-arg index="2" value="shengzhen"/>
            </bean>
        
        </beans>
        
      4. @ContextConfiguration("classpath*:applicationContext-di.xml")
        @RunWith(SpringJUnit4ClassRunner.class)
        public class UserTest {
        
            @Autowired
            private User user;
        
            @Test
            public void test() {
                System.out.println(this.user);
            }
        }
        
      5. 这里使用的是Spring-test,然后省去了很多代码。

        • <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>4.3.21.RELEASE</version>
          </dependency>
          <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
          </dependency>
          
    2. setter注入

      1. 使用setXxx方法注入的方式,这里不提了。
    3. 集合注入

      1. array,list,set,map,properties注入。

      2. <bean id="collectionDemo" class="com.fxyh.spring.di.CollectionDemo">
                <property name="arrayValue">
                    <array>
                        <value>zhangsan</value>
                        <value>lisi</value>
                        <value>wangwu</value>
                    </array>
                </property>
                <property name="listValue">
                    <list>
                        <value>beijin</value>
                        <value>shanghai</value>
                        <value>hangzhou</value>
                        <value>shenzhen</value>
                    </list>
                </property>
                <property name="setValue">
                    <set>
                        <value>aaa</value>
                        <value>bbb</value>
                        <value>ccc</value>
                        <value>ddd</value>
                    </set>
                </property>
                <property name="mapValue">
                    <map>
                        <entry key="key1" value="111"/>
                        <entry key="key2" value="222"/>
                        <entry key="key3" value="333"/>
                        <entry key="key4" value="444"/>
                    </map>
                </property>
                <property name="properties">
                    <props>
                        <prop key="driverClassName">com.mysql.jdbc.Driver</prop>
                        <prop key="url">jdbc:mysql:///fxyh</prop>
                        <prop key="username">root</prop>
                        <prop key="password">root</prop>
                    </props>
                </property>
            </bean>
        
      3. public class CollectionDemo implements Serializable {
            private static final long serialVersionUID = -4477381744799533624L;
        
            private String[] arrayValue;
            private List<String> listValue;
            private Set<String> setValue;
            private Map<String, Object> mapValue;
            private Properties properties;
        
            public String[] getArrayValue() {
                return arrayValue;
            }
        
            public void setArrayValue(String[] arrayValue) {
                this.arrayValue = arrayValue;
            }
        
            public List<String> getListValue() {
                return listValue;
            }
        
            public void setListValue(List<String> listValue) {
                this.listValue = listValue;
            }
        
            public Set<String> getSetValue() {
                return setValue;
            }
        
            public void setSetValue(Set<String> setValue) {
                this.setValue = setValue;
            }
        
            public Map<String, Object> getMapValue() {
                return mapValue;
            }
        
            public void setMapValue(Map<String, Object> mapValue) {
                this.mapValue = mapValue;
            }
        
            public Properties getProperties() {
                return properties;
            }
        
            public void setProperties(Properties properties) {
                this.properties = properties;
            }
        
            @Override
            public String toString() {
                return "CollectionDemo{" +
                        "arrayValue=" + Arrays.toString(arrayValue) +
                        ", listValue=" + listValue +
                        ", setValue=" + setValue +
                        ", mapValue=" + mapValue +
                        ", properties=" + properties +
                        '}';
            }
        }
        
    4. 抽象Bean

      1. 把公共的东西抽象出来,然后需要用到的使用parent。

      2. <bean id="abstractDemo" abstract="true">
          <property name="id" value="1"/>
          <property name="username" value="zhangsan"/>
        </bean>
        <bean id="abstractDemo1" class="com.fxyh.spring.di.AbstractDemo1" parent="abstractDemo">
          <property name="password" value="123456"/>
        </bean>
        <bean id="abstractDemo2" class="com.fxyh.spring.di.AbstractDemo2" parent="abstractDemo">
          <property name="age" value="22"/>
        </bean>
        <bean id="abstractDemo3" class="com.fxyh.spring.di.AbstractDemo3" parent="abstractDemo">
          <property name="address" value="jiangxi"/>
          <property name="id" value="2"/>
        </bean>
        
      3. 这里abstractDemo是抽象Bean,然后使用parent对应这个则对应的属性就会被赋值,并且在自己的bean中重新给这个属性赋值了,那么这个属性将会把抽象bean中的属性的值给覆盖掉。

    5. 自定义属性编辑器

      1. no matching editors or conversion strategy found

      2. 比如我注入的时候注入时间,我直接写字符串的时间,然后这肯定是会报错的,就上面说的那个错误,无法注入。

      3. 所以我们需要自定义属性编辑器。

      4. import org.apache.commons.lang3.time.DateUtils;
        
        import java.beans.PropertyEditorSupport;
        import java.text.ParseException;
        import java.util.Date;
        
        public class CustomDatePropertyEditor extends PropertyEditorSupport {
            @Override
            public void setAsText(String text) throws IllegalArgumentException {
                Date date = null;
                try {
                    date = DateUtils.parseDate(text, "yyyy-MM-dd");
                } catch (ParseException e) {
                    e.printStackTrace();
                }
        
                this.setValue(date);
            }
        }
        
      5. <bean id="person" class="com.fxyh.spring.di.Person">
                <property name="id" value="1"/>
                <property name="username" value="zhangsan"/>
                <property name="salary" value="#{10*new java.util.Random().nextInt(10)}"/>
                <property name="createDate" value="2019-06-30"/>
            </bean>
        
            <bean id="customEditorConfigurer" class="org.springframework.beans.factory.config.CustomEditorConfigurer">
                <property name="customEditors">
                    <map>
                        <entry key="java.util.Date" value="com.fxyh.spring.di.CustomDatePropertyEditor"/>
                    </map>
                </property>
            </bean>
        
      6. 自定义属性编辑器我们需要继承PropertyEditorSupport类,然后重写它的setAsText方法。现在已经不推荐使用了,推荐使用自定义转换器。

    6. 自定义转换器

      1. 实现Converter接口,注意:org.springframework.core.convert.converter.Converter包路径。

      2. 然后实现convert方法,在里面写对应的逻辑。

      3. import org.apache.commons.lang3.StringUtils;
        import org.apache.commons.lang3.time.DateUtils;
        import org.springframework.core.convert.converter.Converter;
        
        import java.text.ParseException;
        import java.util.Date;
        
        public class CustomDateConverter implements Converter<String, Date> {
        
            private String[] parsePatterns;
        
            public void setParsePatterns(String[] parsePatterns) {
                this.parsePatterns = parsePatterns;
            }
        
            @Override
            public Date convert(String source) {
                Date date = null;
                if (StringUtils.isBlank(source)){
                    throw new IllegalArgumentException("");
                }
                try {
                    date = DateUtils.parseDate(source, this.parsePatterns);
                } catch (ParseException e) {
                    e.printStackTrace();
                }
                return date;
            }
        }
        
      4. <bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
                <property name="converters">
                    <set>
                        <bean class="com.fxyh.spring.di.CustomDateConverter">
                            <property name="parsePatterns">
                                <array>
                                    <value>yyyy-MM-dd</value>
                                    <value>yyyy/MM/dd</value>
                                </array>
                            </property>
                        </bean>
                    </set>
                </property>
            </bean>
        
      5. 这里注意这个转换器bean的id,我用其他的试都是没用,只有把id改成conversionService才能使用。

  • ByName&ByType

    • ByName:根据名称匹配

    • ByType:根据类型匹配

    • 这里有个比较经典的异常Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.fxyh.spring.dao.UserDao' available: expected single matching bean but found 2: userDao111111,userDao

    • 这个接口有两个实现类,然后现在spring不知道选择哪个实现类注入就报这个异常了。

    • <?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"
             default-autowire="byType">
      
          <bean id="userService" class="com.fxyh.spring.service.impl.UserServiceImpl" autowire="byName"/>
      
          <bean id="userDao111111" class="com.fxyh.spring.dao.impl.UserDaoMyBatisImpl"/>
          <bean id="userDao" class="com.fxyh.spring.dao.impl.UserDaoHibernateImpl"/>
      </beans>
      
    • 这里在beans上使用了default-autowire为byType,所以这个beans下的bean都会根据类型自动注入,而此时有userDao和userDao111111都是实现了UserDao接口,所以两个都符合要求,然后bean就不知道要注入哪一个了,而这里我们又在userService配置了autowire为byName,此时userService是根据名称来匹配的,则只有userDao一个匹配成功。(这里提供setter方法,然后把setter方法set去掉,然后第一个字母小写,就是名称)

    • 同时在配置中局部配置优先于全局配置!

  • 注解编程

    • @Autowired

      • 属于Spring框架的注解
      • 先按类型匹配,如果匹配不到再按名称匹配
    • @Resource

      • 属于JavaEE规范的注解
      • 先按名称匹配,如果匹配不到再按类型匹配
    • @Qualifier

      • 和@Autowired结合使用的时候,按照名称匹配,不按类型匹配。
      • @Resource原本就是按名称所以在它按名称找不到的时候,使用@Qualifier设置的名称匹配。
    • @Component

      • 把这个类注解为一个组件
    • @Repository

      • 数据库交互层使用的注解(Dao)
    • @Service

      • 服务层使用的注解
    • @Controller

      • 控制层使用的注解
    • @Configuration

      • 配置类注解
    • @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"
             xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="
              http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
              http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- bean definitions here -->
        
          <!--<context:annotation-config/>-->
          <context:component-scan base-package="com.fxyh.spring"/>
        </beans>
        
    • 这里不贴测试用例了,自己写写测试用例测一测就ok了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值