zoukankan      html  css  js  c++  java
  • Spring自动装配(二)

    为什么Spring要支持Autowire(自动装配)

    先写几个类,首先定义一个Animal接口表示动物:

     1 public interface Animal {
     2 
     3     public void eat();
     4     
     5 }

    写一个Animal接口的实现Tiger类:

    复制代码
     1 public class Tiger implements Animal {
     2 
     3     @Override
     4     public void eat() {
     5         System.out.println("Tiger.eat()");
     6     }
     7     
     8     @Override
     9     public String toString() {
    10         return "I'm a tiger";
    11     }
    12 }
    复制代码

    写一个动物园类Zoo,持有Animal接口,表示动物园中有动物:

    复制代码
     1 public class Zoo {
     2     
     3     private Animal animal;
     4     
     5     public Animal getAnimal() {
     6         return animal;
     7     }
     8 
     9     public void setAnimal(Animal animal) {
    10         this.animal = animal;
    11     }
    12 
    13     @Override
    14     public String toString() {
    15         if (animal == null) {
    16             return null;
    17         }
    18         return animal.toString();
    19     }
    20     
    21 }
    复制代码

    配置一下spring文件,由于这个功能研究的是Autowire,因此我命名为autowire.xml:

    复制代码
     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <beans xmlns="http://www.springframework.org/schema/beans"
     3     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     4     xsi:schemaLocation="http://www.springframework.org/schema/beans
     5     http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
     6     
     7     <bean id="tiger" class="org.xrq.action.by.Tiger" />
     8     
     9     <bean id="zoo" class="org.xrq.action.by.Zoo">
    10         <property name="animal" ref="tiger" />
    11     </bean>
    12         
    13 </beans>
    复制代码

    Spring引入Autowire(自动装配)机制就是为了解决<bean>标签下<property>标签过多的问题,<property>标签过多会引发两个问题:

    • 如果一个Bean中要注入的对象过多,比如十几二十个(这是很正常的),那将导致Spring配置文件非常冗长,可读性与维护性差
    • 如果一个Bean中要注入的对象过多,配置麻烦且一不小心就容易出错

    因此,为了解决使用<property>标签注入对象过多的问题,Spring引入自动装配机制,简化开发者配置难度,降低xml文件配置大小。

    使用Autowire去除<property>标签

    下面来看一下使用Autowire去除<property>,autowire有两处点:

    • 可以配置在<beans>根标签下,表示对全局<bean>起作用,属性名为default-autowire
    • 可以配置在<bean>标签下,表示对当前<bean>起作用,属性名为autowire

    通常都是在<beans>根标签下配置自动装配比较多,default-autowire有四种取值:

    • no:默认,即不进行自动装配,每一个对象的注入比如依赖一个<property>标签
    • byName:按照beanName进行自动装配,使用setter注入
    • byType:按照bean类型进行自动装配,使用setter注入
    • constructor:与byType差不多,不过最终属性通过构造函数进行注入

    这里研究的是去除<property>标签,因此第一种不管;constructor装配不太常用,因此这里也不管,重点看最常用的byName与byType,至于具体使用哪种根据自己的业务特点进行相应的设置。

    首先看一下byName,byName意为在spring配置文件中查询beanName与属性名一致的bean并进行装配,若类型不匹配则报错,autowire.xml如果使用byName进行属性装配,那么将改成以下的形式:

    复制代码
     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <beans xmlns="http://www.springframework.org/schema/beans"
     3     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     4     xsi:schemaLocation="http://www.springframework.org/schema/beans
     5     http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"
     6     default-autowire="byName">
     7     
     8     <bean id="animal" class="org.xrq.action.by.Tiger" />
     9     
    10     <bean id="zoo" class="org.xrq.action.by.Zoo" />
    11         
    12 </beans>
    复制代码

    看到Zoo中有一个名为animal的属性,我将Tiger这个bean也命名为animal,由于Tiger是Animal接口的实现类,因此Spring可以找到beanName为animal的bean并自动装配到Zoo的animal属性中,这就是byName的自动装配形式。

    接着看一下byType的自动装配形式,byType意为在spring配置文件中查询与属性类型一致的bean并进行装配,若有多个相同类型则报错(下一部分讲),autowire.xml如果使用byType进行属性装配,那么将改成以下的形式:

    复制代码
     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <beans xmlns="http://www.springframework.org/schema/beans"
     3     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     4     xsi:schemaLocation="http://www.springframework.org/schema/beans
     5     http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"
     6     default-autowire="byType">
     7     
     8     <bean id="tiger" class="org.xrq.action.by.Tiger" />
     9     
    10     <bean id="zoo" class="org.xrq.action.by.Zoo" />
    11         
    12 </beans>
    复制代码

    将Tiger命名为tiger(将bean命名为类名首字母小写也比较符合规范),由于Tiger是Animal接口的实现类,因此Spring找到了Tiger并自动装配到Zoo的animal属性中,这就是byType的自动装配形式。

    byType装配出现多个相同类型的bean及解决方案

    前面演示了,byType的装配方式是在Spring配置文件中寻找属性类型与bean类型一致的bean,那么有一个问题,就是如果属性类型在Spring配置文件中有多个相同类型的bean会出现什么样的情况?为了探究一下这个问题,先定义另外一个Animal接口的实现类,叫做lion:

    复制代码
     1 public class Lion implements Animal {
     2 
     3     @Override
     4     public void eat() {
     5         System.out.println("Lion.eat()");
     6     }
     7 
     8     @Override
     9     public String toString() {
    10         return "I'm a lion";
    11     }
    12 }
    复制代码

    接着,在Spring配置文件中定义一下Lion这个类:

    复制代码
     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <beans xmlns="http://www.springframework.org/schema/beans"
     3     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     4     xsi:schemaLocation="http://www.springframework.org/schema/beans
     5     http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"
     6     default-autowire="byType">
     7     
     8     <bean id="tiger" class="org.xrq.action.by.Tiger" />
     9     <bean id="lion" class="org.xrq.action.by.Lion" />
    10     
    11     <bean id="zoo" class="org.xrq.action.by.Zoo" />
    12         
    13 </beans>
    复制代码

    运行一个测试类,结果为:

    复制代码
    org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'zoo' defined in class path resource [spring/autowire.xml]: 
    Unsatisfied dependency expressed through bean property 'animal': : No unique bean of type [org.xrq.action.by.Animal] is defined: expected single matching bean but
    found 2: [tiger, lion]; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [org.xrq.action.by.Animal] is
    defined: expected single matching bean but found 2: [tiger, lion] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireByType(AbstractAutowireCapableBeanFactory.java:1166) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1058) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:516) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:455) at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:293)
    复制代码

    意思很明显:想要通过byType方式为animal进行装配却找到了两个符合要求的bean,分别为tiger与lion,这导致了没有唯一的bean可以对animal进行装配。

    这个问题有两种解决方案,假如现在我要装配的是lion这个bean,第一种解决方案是将不需要进行自动装配的bean进行排除,对不需要进行自动装配的bean设置属性autowire-candidate="false"即可

    复制代码
     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <beans xmlns="http://www.springframework.org/schema/beans"
     3     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     4     xsi:schemaLocation="http://www.springframework.org/schema/beans
     5     http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"
     6     default-autowire="byType">
     7     
     8     <bean id="tiger" class="org.xrq.action.by.Tiger" autowire-candidate="false" />
     9     <bean id="lion" class="org.xrq.action.by.Lion" />
    10     
    11     <bean id="zoo" class="org.xrq.action.by.Zoo" />
    12         
    13 </beans>
    复制代码

    candidate顾名思义,即候选人的意思,autowire-candidate="false"即这个bean我不想让它作为自动装配的候选者,既然tiger不是自动装配的候选者,那么animal类型在Spring容器中能自动装配的也就只有一个lion了,Spring自动装配lion,不会有问题。

    第一种思路是排除那些不需要作为自动装配候选者的bean,第二种思路就从相反逻辑出发,设置当发现有多个候选者的时候优先使用其中的哪个候选者,对要作为自动装配候选者的bean设置primary="true"即可

    复制代码
     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <beans xmlns="http://www.springframework.org/schema/beans"
     3     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     4     xsi:schemaLocation="http://www.springframework.org/schema/beans
     5     http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"
     6     default-autowire="byType">
     7     
     8     <bean id="tiger" class="org.xrq.action.by.Tiger" />
     9     <bean id="lion" class="org.xrq.action.by.Lion" primary="true" />
    10     
    11     <bean id="zoo" class="org.xrq.action.by.Zoo" />
    12         
    13 </beans>
    复制代码

    这种方式同样也可以将lion装配到animal属性中而不会报错。

    参看链接:

    https://www.cnblogs.com/PengChengLi/p/10516939.html

    https://www.cnblogs.com/xrq730/p/6706128.html

     
  • 相关阅读:
    《大话数据结构》第1章 数据结构绪论 1.2 你数据结构怎么学的?
    伍迷七八月新浪微博集锦
    《大话数据结构》第9章 排序 9.7 堆排序(下)
    《大话数据结构》第3章 线性表 3.8.2 单链表的删除
    《大话数据结构》第9章 排序 9.5 直接插入排序
    《大话数据结构》第9章 排序 9.8 归并排序(上)
    《大话数据结构》第2章 算法基础 2.9 算法的时间复杂度
    《大话数据结构》第1章 数据结构绪论 1.1 开场白
    《大话数据结构》第9章 排序 9.1 开场白
    [AWS] Assign a public IP address to an EC2 instance after launched
  • 原文地址:https://www.cnblogs.com/zhangshuaivole/p/13493299.html
Copyright © 2011-2022 走看看