为什么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

 

Spring自动装配(二)的更多相关文章

  1. spring 自动装配 default-autowire=&quot;byName/byType&quot;

    <PRE class=html name="code">spring 自动装配 default-autowire="byName/byType"   ...

  2. Spring 自动装配 Bean

    Spring3系列8- Spring 自动装配 Bean 1.      Auto-Wiring ‘no’ 2.      Auto-Wiring ‘byName’ 3.      Auto-Wiri ...

  3. Spring自动装配Bean详解

    1.      Auto-Wiring ‘no’ 2.      Auto-Wiring ‘byName’ 3.      Auto-Wiring ‘byType 4.      Auto-Wirin ...

  4. Spring自动装配----注解装配----Spring自带的@Autowired注解

    Spring自动装配----注解装配----Spring自带的@Autowired注解 父类 package cn.ychx; public interface Person { public voi ...

  5. Spring系列七:Spring 自动装配

    相思相见知何日?此时此夜难为情. 概述 在Spring框架中,在配置文件中声明bean的依赖关系是一个很好的做法,因为Spring容器能够自动装配协作bean之间的关系.这称为spring自动装配. ...

  6. Spring自动装配歧义性笔记

    Spring自动装配歧义性笔记 如果系统中存在两个都实现了同一接口的类,Spring在进行@Autowired自动装配的时候,会选择哪一个?如下: // 一下两个类均被标记为bean @Compone ...

  7. Spring 自动装配及其注解

    一.属性自动装配 首先,准备三个类,分别是User,Cat,Dog.其中User属性拥有Cat和Dog对象. package com.hdu.autowire; public class User { ...

  8. 峰Spring4学习(4)spring自动装配

    一.自动装配: Model类: People.java: package com.cy.entity; public class People { private int id; private St ...

  9. Spring——自动装配(@Autowired/@Profile/底层组件)

    本文介绍Spring中关于自动装配的方法和规则,以及@Profile动态激活的用法和一个例子. 一.@Autowired自动装配 @Autowired注解可以加在构造器.属性.方法.方法参数上. 自动 ...

随机推荐

  1. 3,java数据结构和算法:约瑟夫环出队顺序, 单向环形链表的应用

    什么是约瑟夫环? 就是数小孩游戏: 直接上代码: 要实现这个,只需要理清思路就好了 孩子节点: class Boy{ int no;//当前孩子的编码 Boy next; // 下一节点 public ...

  2. 狂神说Mybatis笔记

    环境说明: jdk 8 + MySQL 5.7.19 maven-3.6.1 IDEA 学习前需要掌握: JDBC MySQL Java 基础 Maven Junit 第一节:入门 什么是MyBati ...

  3. 总结springboot开启mybatis驼峰命名自动映射的三种方式

    方式一:通过springboot的配置文件application.yml mybatis: configuration: map-underscore-to-camel-case: true 此方式是 ...

  4. P1522 [USACO2.4]牛的旅行 Cow Tours(Floyd)

    题目描述 Farmer John 的农场里有很多牧区.有的路径连接一些特定的牧区.一片所有连通的牧区称为一个牧场.但是就目前而言,你能看到至少有两个牧区通过任何路径都不连通.这样,Farmer Joh ...

  5. 日常Bug排查-Nginx重复请求?

    日常Bug排查-Nginx重复请求? 前言 日常Bug排查系列都是一些简单Bug排查,笔者将在这里介绍一些排查Bug的简单技巧,其中不乏一些看起来很低级但很容易犯的问题. 问题现场 有一天运维突然找到 ...

  6. 【VBA】模块更新方法

    删除模块,重新导入 1 Sub 更新模块() 2 With ThisWorkbook.VBProject 3 .VBComponents.Remove .VBComponents("模块1& ...

  7. Django基础之路由层

    内容概要 路由匹配 无名有名分组 反向解析 无名有名分组反向解析(难理解) 路由分发 名称空间 伪静态 内容详细 1 路由匹配 urls.py url()方法第一个参数其实是一个正则表达式 第一个参数 ...

  8. Spring Reactor 入门与实践

    适合阅读的人群:本文适合对 Spring.Netty 等框架,以及 Java 8 的 Lambda.Stream 等特性有基本认识,希望了解 Spring 5 的反应式编程特性的技术人员阅读. 一.前 ...

  9. Shiro-JWT SpringBoot前后端分离权限认证的一种思路

    JWT-Shiro 整合 JWT-与Shiro整合进行授权认证的大致思路 图示 大致思路 将登录验证从shiro中分离,自己结合JWT实现 用户登陆后请求认证服务器进行密码等身份信息确认,确认成功后 ...

  10. 乘风破浪,Windows11预览版升级和安装,积极准备中的大跃进

    安装Windows11 暂时官方还没出可靠的ISO 升级到Windows11 预览版 关于一些限制 目前DEV预览通道对从老系统升级到Windows11暂时没有什么限制,只是会提示你可能不太好,但是安 ...