Spring Bean 的装配方式以及Autowired与Resource的使用及区别

1.Spring的自动装配

在Spring的使用中,如果要将一个bean实例化,可以通过配置文件,也可以通过在java代码里面的注解来实现,Spring能够根据自动协作这些bean之间的关系,这种自动协作的过程,也称之为自动装配。
自动装配模式有如下四种模式:

模式 说明
no no表示关闭自动装配选项,必须通过显示的设置才能确认依赖关系。这也是采用xml配置的默认选项。
byname 基于bean的名称name进行注入,在进行Bean的自动装配时,将属性的name在配置文件中搜索匹配的Bean,如果找到name一致的bean,则进行注入,如果找不打到,则会抛出异常。
byType 基于bean的类型进行注入,在bean中自动装配属性的时候,将定义的属性类型与配置文件中定义的bean进行匹配,如果类型一致,就在属性中注入,如果没有找到这样的bean,就抛出异常。
constructor 通过构造函数自动装配bean,这个操作与ByType是一致的,在自动装配的过程中,将查找构造函数的参数类型,然后对所有构造函数参数执行自动装配。

有三种方式可以实现spring Bean的装配过程:

  • xml配置
  • @Autowired
  • @Resource

2.xml配置实现装配

首先定义了三个类, 分别为:

表示用户关系的User类 :

package com.dhb.gts.javacourse.week5.springbean.v1;

import lombok.Data;

@Data
public class User {
    //编号
    private int id;
    //姓名
    private String name;
    //年龄
    private int age;

    public User(int id, String name, int age) {
        this.id = id;
        this.name = name;
        this.age = age;
    }
}

表示角色的Role类:

package com.dhb.gts.javacourse.week5.springbean.v1;

import lombok.Data;

@Data
public class Role {
    //角色ID
    private int roleId;
    //角色名称
    private String roleName;
}

以及表示用户角色关联关系的UserRole类:

package com.dhb.gts.javacourse.week5.springbean.v1;

import lombok.Data;

@Data
public class UserRole {
    //用户
    private User user;
    //角色
    private Role role;

    public UserRole() {
    }

    public UserRole(User user, Role role) {
        this.user = user;
        this.role = role;
    }
}

2.1 xml实现基本的装配

配置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 http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="user" class="com.dhb.gts.javacourse.week5.springbean.v1.User">
        <constructor-arg name="id" value="001"/>
        <constructor-arg name="name" value="张三"/>
        <constructor-arg name="age" value="22"/>
    </bean>
    
    <bean id="role" class="com.dhb.gts.javacourse.week5.springbean.v1.Role">
        <property name="roleId" value="1"/>
        <property name="roleName" value="管理员"/>
    </bean>
    
    <bean id="userRole" class="com.dhb.gts.javacourse.week5.springbean.v1.UserRole" >
        <property name="role" ref="role"/>
        <property name="user" ref="user"/>
    </bean>
    
</beans>

测试类:

package com.dhb.gts.javacourse.week5.springbean.v1;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class XmlTest1 {

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("app-v1-1.xml");
        UserRole userRole = (UserRole) context.getBean("userRole");
        System.out.println(userRole.toString());
    }

}


这种方式需要在xml中对每一个属性进行配置,首先通过property装配了User和Role,UserRole对象的两个属性role和user通过property进行关联。这样就能实现spring中最基本的一种装配方式。
可以通过XmlTest1类进行测试,确认装配的正确性。

UserRole(user=User(id=1, name=张三, age=22), role=Role(roleId=1, roleName=管理员))

2.2 xml通过byName实现自动装配

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 http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="user" class="com.dhb.gts.javacourse.week5.springbean.v1.User">
        <constructor-arg name="id" value="001"/>
        <constructor-arg name="name" value="张三"/>
        <constructor-arg name="age" value="22"/>
    </bean>
    
    <bean id="role" class="com.dhb.gts.javacourse.week5.springbean.v1.Role">
        <property name="roleId" value="1"/>
        <property name="roleName" value="管理员"/>
    </bean>

    <bean id="userRole" class="com.dhb.gts.javacourse.week5.springbean.v1.UserRole" autowire="byName"/>
    
</beans>

测试代码:

package com.dhb.gts.javacourse.week5.springbean.v1;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class XmlTest2 {

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("app-v1-2.xml");
        UserRole userRole = (UserRole) context.getBean("userRole");
        System.out.println(userRole.toString());
    }

}


这种装配方式不用在UserRole中指定user和role对应的具体类,只需要增加一个属性:autowire="byName",就能在自动装配的过程中,将根据UserRole的属性的name查找context中name与之对应的bean进行装配。
测试结果如下:

UserRole(user=User(id=1, name=张三, age=22), role=Role(roleId=1, roleName=管理员))

2.3 xml通过byType实现自动装配

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 http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="user" class="com.dhb.gts.javacourse.week5.springbean.v1.User">
        <constructor-arg name="id" value="001"/>
        <constructor-arg name="name" value="张三"/>
        <constructor-arg name="age" value="22"/>
    </bean>
    
    <bean id="role" class="com.dhb.gts.javacourse.week5.springbean.v1.Role">
        <property name="roleId" value="1"/>
        <property name="roleName" value="管理员"/>
    </bean>

    <bean id="userRole" class="com.dhb.gts.javacourse.week5.springbean.v1.UserRole" autowire="byType"/>
    
</beans>

测试代码:

package com.dhb.gts.javacourse.week5.springbean.v1;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class XmlTest3 {

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("app-v1-3.xml");
        UserRole userRole = (UserRole) context.getBean("userRole");
        System.out.println(userRole.toString());
    }

}


这种装配方式同样不用在UserRole中指定user和role对应的具体类,只需要增加一个属性:autowire="byType",就能在自动装配的过程中,将根据UserRole成员变量的类型查找context中类型与之对应的bean进行装配。
需要注意的是,byName方式可以确保bean的唯一性,但是byType方式,无法确保bean的唯一性,如果出现多个bean的类型相同,则会报错。
测试结果如下:

UserRole(user=User(id=1, name=张三, age=22), role=Role(roleId=1, roleName=管理员))

2.4 xml通过constructor实现自动装配

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 http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="user" class="com.dhb.gts.javacourse.week5.springbean.v1.User">
        <constructor-arg name="id" value="001"/>
        <constructor-arg name="name" value="张三"/>
        <constructor-arg name="age" value="22"/>
    </bean>
    
    <bean id="role" class="com.dhb.gts.javacourse.week5.springbean.v1.Role">
        <property name="roleId" value="1"/>
        <property name="roleName" value="管理员"/>
    </bean>

    <bean id="userRole" class="com.dhb.gts.javacourse.week5.springbean.v1.UserRole" autowire="constructor">
        <constructor-arg name="user" ref="user"/>
        <constructor-arg name="role" ref="role"/>
    </bean>
</beans>

测试代码:

package com.dhb.gts.javacourse.week5.springbean.v1;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class XmlTest4 {

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("app-v1-4.xml");
        UserRole userRole = (UserRole) context.getBean("userRole");
        System.out.println(userRole.toString());
    }

}


这种装配方式同样不用在UserRole中指定user和role对应的具体类,只需要增加一个属性:autowire="constructor",就能在自动装配的过程中,将根据UserRole构造函数参数表constructor-arg配置的name查找context中name与之对应的bean进行装配。
测试结果如下:

UserRole(user=User(id=1, name=张三, age=22), role=Role(roleId=1, roleName=管理员))

2.@Autowired实现装配

@Autowired是采用byType实现的自动装配,在装配的过程中,通过类型进行匹配。
同样,定义了Role

package com.dhb.gts.javacourse.week5.springbean.v2;

import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component
@Data
public class Role {
    //角色ID
    @Value("2")
    private Integer roleId;
    //角色名称
    @Value("用户")
    private String roleName;
}

以及User

package com.dhb.gts.javacourse.week5.springbean.v2;

import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component
@Data
public class User {
    //编号
    private Integer id;
    //姓名
    private String name;
    //年龄
    private Integer age;

    @Autowired
    public User(@Value("1") int id, @Value("用户") String name,@Value("22")  int age) {
        this.id = id;
        this.name = name;
        this.age = age;
    }
}

2.1 注解在属性上

UserRole代码如下:

package com.dhb.gts.javacourse.week5.springbean.v2;

import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
@Data
public class UserRole {
    //用户
    @Autowired
    private User user;
    //角色
    @Autowired
    private Role role;

    public UserRole() {
    }

    public UserRole(User user, Role role) {
        this.user = user;
        this.role = role;
    }
}   

如上所示,只需要在UserRole的属性上增加@Autpwired,在context中查找与属性类型一致的bean,就可以实现UserRole的自动装配。

2.2 注解在构造函数上

UserRole代码如下:

package com.dhb.gts.javacourse.week5.springbean.v2;

import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
@Data
public class UserRole1 {
    //用户
    private User user;
    //角色
    private Role role;

    public UserRole1() {
    }

    @Autowired
    public UserRole1(User user, Role role) {
        this.user = user;
        this.role = role;
    }
}

注解在构造函数上,等价于xml配置中的constructor配置。通过构造函数的属性值的类型去查找context中的bean。

2.3 注解在Set方法上

UserRole代码如下:

package com.dhb.gts.javacourse.week5.springbean.v2;

import lombok.ToString;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
@ToString
public class UserRole2 {
   //用户
   private User user;
   //角色
   private Role role;


   public User getUser() {
       return user;
   }

   @Autowired
   public void setUser(User user) {
       this.user = user;
   }

   public Role getRole() {
       return role;
   }

   @Autowired
   public void setRole(Role role) {
       this.role = role;
   }

   public UserRole2() {
   }
   
   public UserRole2(User user, Role role) {
       this.user = user;
       this.role = role;
   }
}

AutoWired也可以注解在set方法上来实现自动装配。根据set方法的参数,从context中选择type与之一致的bean实现装配。

2.4 测试

测试代码如下:

public class AutowiredTest {

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("app-v2.xml");
        UserRole userRole = (UserRole) context.getBean("userRole");
        System.out.println(userRole.toString());
        UserRole1 userRole1 = (UserRole1) context.getBean("userRole1");
        System.out.println(userRole1.toString());
        UserRole2 userRole2 = (UserRole2) context.getBean("userRole2");
        System.out.println(userRole2.toString());
    }
}

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: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">

    <context:component-scan base-package="com.dhb.gts.javacourse.week5.springbean.v2">
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>
    
</beans>

测试结果:

UserRole(user=User(id=1, name=用户, age=22), role=Role(roleId=2, roleName=用户))
UserRole1(user=User(id=1, name=用户, age=22), role=Role(roleId=2, roleName=用户))
UserRole2(user=User(id=1, name=用户, age=22), role=Role(roleId=2, roleName=用户))

3.@Resource实现装配

同样,通过J2EE的@Resource标签也能实现Bean的装配,但是需要注意的是,这个注解不支持构造函数,只支持属性或者set方法。需要注意的是,@Resource默认是采用byName的方式从contect中查找bean.
角色类:

package com.dhb.gts.javacourse.week5.springbean.v3;

import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component
@Data
public class Role {
    //角色ID
    @Value("2")
    private Integer roleId;
    //角色名称
    @Value("用户")
    private String roleName;
}

用户类:

package com.dhb.gts.javacourse.week5.springbean.v3;

import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component
@Data
public class User {
    //编号
    private Integer id;
    //姓名
    private String name;
    //年龄
    private Integer age;

    @Autowired
    public User(@Value("1") int id, @Value("用户") String name,@Value("22")  int age) {
        this.id = id;
        this.name = name;
        this.age = age;
    }
}

3.1 注解在属性上

代码如下:

package com.dhb.gts.javacourse.week5.springbean.v3;

import lombok.Data;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

@Component
@Data
public class UserRole {
    //用户
    @Resource(type = User.class)
    private User user;
    //角色
    @Resource(name = "role")
    private Role role;

    public UserRole() {
    }

    public UserRole(User user, Role role) {
        this.user = user;
        this.role = role;
    }
}

3.2 注解在set方法上

代码如下:

package com.dhb.gts.javacourse.week5.springbean.v3;

import lombok.ToString;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

@Component
@ToString
public class UserRole1 {
    //用户
    private User user;
    //角色
    private Role role;

    public UserRole1() {
    }

    public User getUser() {
        return user;
    }

    @Resource
    public void setUser(User user) {
        this.user = user;
    }

    public Role getRole() {
        return role;
    }

    @Resource
    public void setRole(Role role) {
        this.role = role;
    }
    
    public UserRole1(User user, Role role) {
        this.user = user;
        this.role = role;
    }
}

3.3 @Resource测试:

测试类:

public class ResourceTest {

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("app-v3.xml");
        UserRole userRole = (UserRole) context.getBean("userRole");
        System.out.println(userRole.toString());
        UserRole1 userRole1 = (UserRole1) context.getBean("userRole1");
        System.out.println(userRole1.toString());
    }
}

测试配置:

<?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">

    <context:component-scan base-package="com.dhb.gts.javacourse.week5.springbean.v3">
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>
    
</beans>

测试结果:

UserRole(user=User(id=1, name=用户, age=22), role=Role(roleId=2, roleName=用户))
UserRole1(user=User(id=1, name=用户, age=22), role=Role(roleId=2, roleName=用户))

4.@Autowired与@Resource的比较

二者对比如下:

  • @Autowired与@Resource都可以用来装配bean. 都可以写在字段上,或者在setter方法上。 但是@Resource不支持在构造函数上装配。
  • @Autowired默认按类型装配(这个注解是属业spring的),默认情况下必须要求依赖对象必须存在,如果要允许null 值,可以设置它的required属性为false,如:@Autowired(required=false) 。如果我们想使用名称装配可以结合@Qualifier注解进行使用。
  • @Resource(这个注解属于J2EE的),默认安照名称进行装配,名称可以通过name属性进行指定, 如果没有指定name属性,当注解写在字段上时,默认取字段名进行按照名称查找,如果注解写在setter方法上默认取属性名进行装配。 当找不到与名称匹配的bean时才按照类型进行装配。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,530评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,403评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,120评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,770评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,758评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,649评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,021评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,675评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,931评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,751评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,410评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,004评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,969评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,042评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,493评论 2 343

推荐阅读更多精彩内容