自动装配 @Autowired @Resource

自动装配 @Autowired @Resource

基于注解配置bean,也可以实现自动装配,使用的注解是@Autowired @Resource

  • @Component 标识该类是一个组件, 是一个通用的注解
  • @Controller 标识该类是一个控制器Controller, 通常这个类是一个Servlet
  • @Repository 标识该类是一个Repository是一个持久化层的类/对象
  • @Service 标识该类是一个Service类/对象

@Autowired
1)在IOC容器中查找待装配的组件的类型,如果有唯一的bean匹配(按照类型),则使用该bean装配
2)如待装配的类型对应的bean在IOC容器中有多个,则使用待装配的属性的属性名作为id值再进行查找, 找到就装配,找不到就抛异常

@Resource

  1. @Resource有两个属性是比较重要的,分是name和type,
    <1>Spring将@Resource注解的name属性解析为bean的名字,所以如果使用name属性,@Resource(name = “userService”) 表示装配 id=userService对象.

    <2> >type属性则解析为bean的类型.使用type属性时则使用byType自动注 入策略.比如 @Resource(type = UserService.class) 表示按照UserService.class类型进行装配, 这时要求容器中,只能有一个这样类型的对象

  2. 如果@Resource 没有指定 name 和 type ,则先使用byName注入策略, 如果匹配不上, 再使用byType策略, 如果都不成功,就会报错

1.src目录下写配置文件beans.xml,
此时此刻在beans.xml 这个配置文件对应的容器中有3个userService,一个是基于注解扫描的形式加进去的,(也就是userService.java里注解@Service). userService200, userService300

<?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
        https://www.springframework.org/schema/context/spring-context.xsd">
    
    <context:component-scan
            base-package="com.elf.spring.component"/>

    <!--配置两个UserService对象-->
    <bean class="com.elf.spring.component.UserService" id="userService200"/>
    <bean class="com.elf.spring.component.UserService" id="userService300"/>
</beans>

2.UserService类

package com.elf.spring.component;
import org.springframework.stereotype.Service;
/**
 * @author 90
 * @version 1.0
 * @Service 标识该类是一个Service类/对象
 */
@Service
public class UserService {
    //方法..
    public void hi(){
        System.out.println("UserService hi()~");
    }
}

3.UserDao类

package com.elf.spring.component;
import org.springframework.stereotype.Repository;
/**
 * @author 45
 * @version 1.0
 * 使用 @Repository 标识该类是一个Repository是一个持久化层的类/对象
 * 1. 标记注解后,类名首字母小写作为id的值(默认)
 * 2. value = "elfUserDao" 使用指定的 elfUserDao作为UserDao对象的id
 */
@Repository/*(value = "elfUserDao")*/
public class UserDao {
}

4.MyComponent类

package com.elf.spring.component;
import org.springframework.stereotype.Component;
/**
 * @author 45
 * @version 1.0
 * @Component 标识该类是一个组件, 是一个通用的注解
 */
@Component(value = "elf1")
public class MyComponent {
}

5.AutoTest 测试类

package com.elf.spring.test;
import com.elf.spring.component.UserAction;
import com.elf.spring.component.UserService;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
 * @author 45~
 * @version 1.0
 */
public class AutoTest {
    //通过注解来配置Bean
    @Test
    public void setProByAutowired() {

        ApplicationContext ioc =
                new ClassPathXmlApplicationContext("beans06.xml");

        UserService userService = ioc.getBean("userService", UserService.class);
        System.out.println("ioc容器中的userService=" + userService);
        userService.hi();

        UserService userService200 = ioc.getBean("userService200", UserService.class);
        System.out.println("ioc容器中的userService200=" + userService200);

        UserAction userAction = ioc.getBean("userAction", UserAction.class);
//        //System.out.println("userAction=" + userAction);
       userAction.sayOk();
//
//        UserService userService300 = ioc.getBean("userService300", UserService.class);
//        System.out.println("ioc容器中的userService300=" + userService300);
//
//        System.out.println("userService=" + userService);
//        System.out.println("userService200=" + userService200);
//        System.out.println("userService300=" + userService300);
    }
}


  1. UserAction 类
package com.elf.spring.component;

import org.springframework.stereotype.Controller;

import javax.annotation.Resource;

/**
 * @author 45
 * @version 1.0
 * @Controller 标识该类是一个控制器Controller, 通常这个类是一个Servlet
 */
@Controller
public class UserAction {
    //xml配置 ref
    //@Autowired

    //说明: @Autowired + @Qualifier(value = "userService02") 组合也可以完成指定 name/id 来进行自动装配
    //指定id进行组装, 也可以使用@Autowired 和 @Qualifier(value = "userService02")
    // 这时,是装配的 id=userService02 , 需要两个注解都需要写上


    /** @Autowired 若这里注解为 @Autowired,属性名写userService400:
    需要注销配置文件里200和300,只留注解扫描包那个就会成功
    此时是按唯一bean,类型来做的,至于名字叫什么无所谓!!!
    此时唯一能注入的就是通过注解默认到类名首字母小写的bean
     **/

    /**
     * @Resource(name = "userService200")
     * /**这里由于@Resource已经指定了id,把名字为userService的对象注入/装配到属性上
     * 至于下面的属性名称为userService600或者别的什么已经没有意义了不考虑
     */
    @Resource(name = "userService200")
    //@Resource(type = UserService.class)//这是要求容器中只能由一个这样的类型,如果多个则报错

    //@Resource  //先按名字匹配没有,再按类型.而按类型的前提是只有一个此类型的bean
    private UserService userService600;

    public void sayOk() {
        System.out.println("UserAction 的sayOk()");

        //这里会输出userService的哈希值
        System.out.println("userAction 装配的 userService600属性=" + userService600);
        userService600.hi();
    }
}

自动装配 @Autowired @Resource_第1张图片
自动装配 @Autowired @Resource_第2张图片
发现一个有趣的事情:
配置文件中只保留userService200,userAction文件中如下:

@Resource  //先按名字匹配没有,再按类型.而按类型的前提是只有一个此类型的bean
    private UserService userService600;

    public void sayOk() {
        System.out.println("UserAction 的sayOk()");

        //这里会输出userService的哈希值
        System.out.println("userAction 装配的 userService600属性=" + userService600);
        userService600.hi();

按名字匹配没有,按类型原来不像第一种写不行哦~~~
后面写法直接写bean的全类名和id的,只能按名字查找.
自动装配 @Autowired @Resource_第3张图片
会报错:
自动装配 @Autowired @Resource_第4张图片
反思:

  1. 其实在Test文件中逐个ioc.getBean()是可以获取到每一个bean的哈希值的,值不同,各是各的.
  2. 而Action文件中看注入的是哪个,主要看@Resource 有没带type和name,有则按Resource配置的找,没有就先按名字后按类型.
  3. @Autowired 要看bean唯一与否,唯一就装配完事(按类型),不唯一就按名字装配,名字找不到就报错.
  4. 还要注意一点,注入的Resource的name肯定是容器中有的,写一个不存在的编译的时候直接就报错了,如图:
    自动装配 @Autowired @Resource_第5张图片而写了容器中有的bean的名称,不管下边属性名怎么样,有没有/是什么都无所谓,通通按照指定的容器名称的bean对象进行注入.例如:
    自动装配 @Autowired @Resource_第6张图片自动装配 @Autowired @Resource_第7张图片

补充用法:

使用@Autowired也可以指定id进行组装,需要和@Qualifier两个注解都一起写上
@Autowired 单独用是先按类型,单个直接注入. 多例就按名字,多例的话名字就一定要有.
@Qualifier(value = “userService300”)//这时装配的是id= userService300,指定id=userService300的userService对象进行装配
//如果不写 @Qualifier(value = “userService300”),默认是按照下面的id,即userService600来进行组装的

自动装配 @Autowired @Resource_第8张图片

package com.elf.spring.component;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;

/**
 * @author 45
 * @version 1.0
 * @Controller 标识该类是一个控制器Controller, 通常这个类是一个Servlet
 */
@Controller
public class UserAction {
    //xml配置 ref
    //@Autowired

    //说明: @Autowired + @Qualifier(value = "userService02") 组合也可以完成指定 name/id 来进行自动装配
    //指定id进行组装, 也可以使用@Autowired 和 @Qualifier(value = "userService02")
    // 这时,是装配的 id=userService02 , 需要两个注解都需要写上


    /** @Autowired 若这里注解为 @Autowired,属性名写userService400:
    需要注销配置文件里200和300,只留注解扫描包那个就会成功
    此时是按唯一bean,类型来做的,至于名字叫什么无所谓!!!
    此时唯一能注入的就是通过注解默认到类名首字母小写的bean
     **/

    /**
     * @Resource(name = "userService200")
     * /**这里由于@Resource已经指定了id,把名字为userService的对象注入/装配到属性上
     * 至于下面的属性名称为userService600或者别的什么已经没有意义了不考虑
     */
    //@Resource(name = "userService200")
    //@Resource(type = UserService.class)//这是要求容器中只能由一个这样的类型,如果多个则报错

    //@Resource  //先按名字匹配没有,再按类型.而按类型的前提是只有一个此类型的bean

    //补充:使用@Autowired也可以指定id进行组装,需要和@Qualifier两个注解都一起写上
    @Autowired //单独用是先按类型,单个直接注入. 多例就按名字,多例的话名字就一定要有
    @Qualifier(value = "userService300")//这时装配的是id= userService300,指定id=userService300的userService对象进行装配
    //如果不写 @Qualifier(value = "userService300"),默认是按照下面的id,即userService600来进行组装的
    private UserService userService600;

    public void sayOk() {
        System.out.println("UserAction 的sayOk()");

        //这里会输出userService的哈希值
        System.out.println("userAction 装配的 userService600属性=" + userService600);
        userService600.hi();
    }
}

测试类

package com.elf.spring.test;
import com.elf.spring.component.UserAction;
import com.elf.spring.component.UserService;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
 * @author 45~
 * @version 1.0
 */
public class AutoTest {
    //通过注解来配置Bean
    @Test
    public void setProByAutowired() {

        ApplicationContext ioc =
                new ClassPathXmlApplicationContext("beans06.xml");

        UserService userService = ioc.getBean("userService", UserService.class);
        System.out.println("ioc容器中的userService=" + userService);
        userService.hi();

        UserService userService200 = ioc.getBean("userService200", UserService.class);
        System.out.println("ioc容器中的userService200=" + userService200);

        UserAction userAction = ioc.getBean("userAction", UserAction.class);
//        //System.out.println("userAction=" + userAction);
       userAction.sayOk();
//
        UserService userService300 = ioc.getBean("userService300", UserService.class);
        System.out.println("ioc容器中的userService300=" + userService300);
//
//        System.out.println("userService=" + userService);
//        System.out.println("userService200=" + userService200);
//        System.out.println("userService300=" + userService300);
    }
}


虽然写的属性id是userService600,但实际上装配的是userService300.

@Autowired + @Qualifier(value = “userService300”) 组合也可以完成指定 name/id 来进行自动装配.

可以直接由@Resource(name=“userService300”)一条指令代劳.

总结: 就是反着来,先按名字后按类型是@Resource. 但是其实也没那么多要求,@Autowired可以理解为按名字的,因为要先看是不是一个bean,类型不行还是走名字,只有一个bean我管你走什么?

不管哪种注解, 规范地按照类名首字母小写写id(属性名),就可以注入!!!

一般情况下用@Resource,不过泛型依赖注入还得用@Autowired.

你可能感兴趣的:(Spring,spring)