Sprint framework Day08:Spring的@Autowired注解

前言

当使用注解和 XML 配置结合时,可以使用注解 @Autowired@Qualifier@Primary 来实现自动装配并进行依赖注入。

一、了解 @Autowired@Qualifier@Primary 注解

  1. @Autowired 注解:用于自动装配依赖。在需要进行依赖注入的地方,添加 @Autowired 注解即可。Spring 容器会根据类型找到对应的 Bean,并将其注入到目标对象中。

  2. @Qualifier 注解:用于指定具体的 Bean 进行装配。当存在多个相同类型的 Bean 时,使用 @Autowired 没法区分哪个 Bean 要注入。此时,可以结合 @Qualifier 注解来指定要注入的具体 Bean。

  3. @Primary 注解:用于标记首选的 Bean。当存在多个相同类型的 Bean,但想要优先使用其中的一个 Bean 进行注入时,可以在该 Bean 上添加 @Primary 注解。

 了解了这三个注解是干嘛用的,我们就来写个案例实现一下吧。

二、开始学习 @Autowired

1、新建项目,结构如下

Sprint framework Day08:Spring的@Autowired注解_第1张图片

2、导入 spring 依赖 
 
    
    
        
        
            org.springframework
            spring-context
            5.3.23
        
 
        
            ch.qos.logback
            logback-classic
            1.4.5
        
 
 
    
3、在 service 包下新建一个 Userservice 接口,在 impl 包下新建一个 UserServiceImpl 实现类

UserService 接口

public interface UserService {

    void add();

}

UserServiceImpl 实现类


@Slf4j
@Service("userService")
public class UserServiceImpl implements UserService {
    @Override
    public void add() {
        log.info("添加用户.....");
    }
}
4、在 controller 包下新建一个 UserController 类

@Controller
public class UserController {

    /**
     * 字段注入 (spring 不推荐从字段注入)
     * 不推荐使用字段注入,不安全
     */
    private UserService userService;


    @Autowired
    public UserController(UserService userService) {
        this.userService = userService;
    }


    public void add() {
        userService.add();
    }

}
5、在 resources 下新建一个 spring 的 xml 文件 application.xml



    
    

6、测试
public class Main {

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
        UserController bean = context.getBean(UserController.class);
        bean.add();
    }

}

运行结果

Sprint framework Day08:Spring的@Autowired注解_第2张图片

这个案例是一个基于 Spring 框架的示例,展示了使用依赖注入和组件扫描来管理对象和实现控制反转(IoC)的过程。

  • 首先,在 UserServiceImpl 类中使用 @Slf4j 注解引入了一个日志记录器,并使用 @Service("userService") 注解将该类标记为一个服务组件。UserServiceImpl 实现了 UserService 接口,并实现了其中的 add() 方法用于添加用户。
  • UserController 类中,它使用 @Autowired 注解将 UserService 依赖注入到 private UserService userService 字段中。通过构造方法注入,将 UserService 实例传递给 UserController 的构造函数,从而实现了依赖注入。
  • Main 类中,它使用 ApplicationContext 加载了一个应用程序上下文,并通过 context.getBean(UserController.class) 获取了 UserController 的实例。这是通过组件扫描和类路径上的 application.xml 文件中的配置 实现的。
  • 组件扫描是 Spring 框架的一项功能,它会自动扫描指定包中的类,并将带有特定注解(例如 @Service@Controller)的类识别为组件,并进行实例化和管理。这样,就无需手动创建对象和处理对象之间的依赖关系,Spring 框架会自动完成这些工作。

总的来说,这段代码展示了使用 Spring 框架进行对象管理和依赖注入的基本流程,通过组件扫描和注解来简化配置和提高开发效率。

三、开始学习 @Qualifier、@Primary注解

上面的案例是只有一个实现类的情况下使用@Autowired 注解自动装配的,那么如果是有两个或多个实现类的时候该怎么办呢?如果只使用 @Autowired 它是否会成功运行调用方法呢?那我们就继续来完成下面的案例。

1、在上面的基础上在 service 包下的 impl 包下新建一个StudentServiceImpl 实现类

@Slf4j
@Service("studentService")
public class StudentServiceImpl implements UserService {
    @Override
    public void add() {
        log.info("添加学生.....");
    }
}
2、测试
public class Main {

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
        UserController bean = context.getBean(UserController.class);
        bean.add();
    }

}

运行结果

Sprint framework Day08:Spring的@Autowired注解_第3张图片

 大家可以发现,我们现在有两个是实现类,并且都装配为 bean,在 UserController 中调用 add()方法,为什么有两个 add() 方法,调用的是添加用户的而不是添加学生的呢?

在这段代码中,Main 类通过应用程序上下文获取了 UserController 类的实例对象,并调用了它的 add() 方法。但是,没有明确指定要使用哪个实现类的实例。因此,在这里执行的方法将由 @Autowired 注解注入的 UserService 实例决定。

  • 如果在 application.xml 配置文件中将 userService 注册为组件,则将注入 UserServiceImpl 的实例,并执行 UserServiceImpl 类中的 add() 方法。
  • 如果将 studentService 注册为组件,则注入 StudentServiceImpl 的实例,并执行 StudentServiceImpl 类中的 add() 方法。

如果既没有注册 userService 也没有注册 studentService,则代码将无法正常工作并抛出异常。

因此,要确定执行哪个方法,需要在 application.xml 文件中明确指定要使用哪个实现类的实例,例如通过 元素或 @Component 注解来注册 UserServiceStudentService

如果我们要调用添加学生的add()方法要怎么做呢?

3、使用注解 @Qualifier

有三种方法实现,分别是字段注入、setter方法注入、构造方法注入,不推荐使用字段注入,不安全。

1)字段注入

@Controller
public class UserController {

    /**
     * 字段注入 (spring 不推荐从字段注入)
     * 不推荐使用字段注入,不安全
     */
    @Autowired
    @Qualifier("studentService")
    private UserService userService;


    public void add() {
        userService.add();
    }

}

在这段代码中,UserController 类的 userService 字段上使用了 @Autowired 注解进行依赖注入。但是,为了明确指定要注入的实现类,还使用了 @Qualifier("studentService") 注解。

@Qualifier 注解用于指定要注入的 Bean 的名称或标识,以区分同一接口有多个实现类的情况。在这里,@Qualifier("studentService") 指定了要注入的是名为 "studentService" 的 Bean。

因此,在执行 UserController 类的 add() 方法时,将使用通过 @Autowired@Qualifier("studentService") 注入的 UserService 实例,即 StudentServiceImpl 类的实例。然后,调用该实例的 add() 方法。

测试 
public class Main {

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
        UserController bean = context.getBean(UserController.class);
        bean.add();
    }

}

运行结果

 通过使用 @Qualifier 注解,并且指定 bean 为 studentService,就成功的调用到添加学生的方法,那么如果需要使用添加用户的方法怎么办呢?只需要把 studentService 改为 userService 即可。

2)setter 方法注入
@Controller
public class UserController {

    /**
     * 字段注入 (spring 不推荐从字段注入)
     * 不推荐使用字段注入,不安全
     */
    private UserService userService;

    /**
     * set 方法注入
     * @param userService
     */
    @Autowired
    @Qualifier("userService")
    public void setUserService(UserService userService) {
        this.userService = userService;
    }

    public void add() {
        userService.add();
    }

}
测试
public class Main {

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
        UserController bean = context.getBean(UserController.class);
        bean.add();
    }

}

运行结果

Sprint framework Day08:Spring的@Autowired注解_第4张图片

同上.... 

 3) 构造方法注入
@Controller
public class UserController {

    /**
     * 字段注入 (spring 不推荐从字段注入)
     * 不推荐使用字段注入,不安全
     */
    private UserService userService;

    @Autowired
    @Qualifier("studentService")
    public UserController(UserService userService) {
        this.userService = userService;
    }


    public void add() {
        userService.add();
    }

}
测试
public class Main {

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
        UserController bean = context.getBean(UserController.class);
        bean.add();
    }

}

运行结果

4、使用 @Primary 注解注入

 同样也有三种方法实现,字段、setter方法、构造方法注入。

1)、更改 StudentServiceImpl 类
@Slf4j
@Service("studentService")
@Primary
public class StudentServiceImpl implements UserService {
    @Override
    public void add() {
        log.info("添加学生.....");
    }
}

在这段代码中,StudentServiceImpl 类上使用了 @Service("studentService") 注解将它标记为组件,并且实现了 UserService 接口。同时,还使用了 @Primary 注解,将该类标记为默认的 Bean 实现。

当有多个实现了相同接口的 Bean 时,通过 @Autowired 注解注入时,默认将注入带有 @Primary 注解的 Bean 实现,如果有多个带有 @Primary 注解的 Bean 实现,则会抛出异常。

因此,在执行 UserController 类的 add() 方法时,由于没有显示地指定要注入哪个实现类,应用程序框架将使用默认的 Bean 实现对 UserService 进行依赖注入,即通过 @Autowired@Primary 注解注入的 UserService 实例,即 StudentServiceImpl 类的实例。然后,调用该实例的 add() 方法。

需要注意的是,如果存在多个 UserService 的实现类都使用了 @Primary 注解,则会抛出异常。确保只有一个实现了 UserService 接口的类被标记为 @Primary

2)通过构造方法注入
@Controller
public class UserController {

    /**
     * 字段注入 (spring 不推荐从字段注入)
     * 不推荐使用字段注入,不安全
     */
    private UserService userService;


    @Autowired
    public UserController(UserService userService) {
        this.userService = userService;
    }


    public void add() {
        userService.add();
    }

}
测试
public class Main {

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
        UserController bean = context.getBean(UserController.class);
        bean.add();
    }

}

运行结果

那么如果想要使用 UserServiceImpl 的 add() 方法呢?

只需要把 StudentServiceImpl 的 @Primary 注解删掉,在 UserServiceImpl 类上加上 @Primary 注解即可。 

四、总结

@Autowired 注解默认是根据类型注入(只有一个实现类),如果存在多个实现类的时候,则是根据参数名称进行注入,如果存在多个实现类并且参数名称不匹配,则会引发异常此时应该结合 @Qualifier 来指定来注入的 bean,但是这个注解只能用在普通的方法上也可以使用 @Primary 注解声明在某个类上实现,这样 spring 就会优先注入这个实现类
从 spring4.2 版本开始,如果使用的是构造方法注入,可以不需要任何的注入注解,默认就按照类型注入

五、gitee 案例

案例完整地址:https://gitee.com/qiu-feng1/spring-framework.git

你可能感兴趣的:(spring,framework,sprint,xml,java)