Spring自动装配之方法、构造器位置的自动注入操作

Spring自动装配之方法、构造器位置的自动注入

1. 注解定义

@Autowired的定义信息如下:

@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {

 /**
  * Declares whether the annotated dependency is required.
  * <p>Defaults to {@code true}.
  */
 boolean required() default true;

}

可以看出,@Autowired注解可以定义在构造器上,方法上,方法参数上,字段上,还有自定义注解上;

2. 注解使用

2.1 定义在造器上

@Autowired //定义在构造器方法上
public UserService(UserDao userDao) {
 this.userDao = userDao;
}

或者

// 定义在构造器参数上
public UserService(@Autowired UserDao userDao) {
 this.userDao = userDao;
}

特别注意,当一个类只有一个有参构造器,且该构造器不一定需要是public修饰的, 组件注入的时候不需要指定在构造器方法上或者构造器参数上指定@Autowired,只需要声明构造器即可;

2.2 定义在方法和参数上

定义在Set方法上

@Autowired //定义在set方法上
public void setUserDao(UserDao userDao) {
 this.userDao = userDao;
}

定义在配置Bean的方法上

package com.yibai.spring.annotation.main.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Service;

import com.yibai.spring.annotation.service.UserDao;
import com.yibai.spring.annotation.service.UserService;

//@ComponentScan("com.yibai.spring.annotation.service")
@Service
public class MainConfigForAutowired {

 // Spring自动从IOC容器中找出UserDao作为方法参数传入,这里@Autowired可有可无
 @Bean
 public UserService userService(@Autowired UserDao userDao) {
  UserService userService = new UserService();
  userService.setUserDao(userDao);
  return userService;
 }

 @Bean
 public UserDao userDao() {
  return new UserDao();
 }
}

2.3 定义在字段上

package com.yibai.spring.annotation.service;

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

import lombok.Getter;

@Getter
@Service
public class UserService {

 @Qualifier(value = "userDao")
 @Autowired(required = true)
 private UserDao userDao;

 public void setUserDao(UserDao userDao) {
  this.userDao = userDao;
 }

}

3. 注入位置推荐

一般推荐注入位置放在构造器上,因为不管字段还是方法的方式注入,都是先创建组件,再注入依赖的组件,如果在构造方法上就需要使用依赖的组件,那么只有在构造器上注入才是可以实现的,因为执行顺序的问题;

package com.yibai.spring.annotation.service;

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

import lombok.Getter;

@Getter
@Service
public class UserService {

 @Qualifier(value = "userDao")
 @Autowired(required = true)
 private UserDao userDao;

 public UserService() {
  //@Autowired定义在字段或者set方式上,在构造器上无法获取到依赖的组件
  System.out.println(userDao); // null
 }

 public void setUserDao(UserDao userDao) {
  this.userDao = userDao;
 }
}

Spring 自动注入的几种方式

Spring 中实现自动装配的注解有以下几个:

  • @Autowired
  • @Qualifier
  • @Primary
  • @Resource
  • @Inject

一、@Autowired

Spring 中最常用的一个注解,当一个组件需要另一个组件作为属性的时候,我们可以通过两种方式对属性进行赋值,一种是通过构造方法,一种是通过 set 方法(类比),而这个注解使用的方法就是后者。

下面介绍该注解的特点:

首先是 按照类型 自动注入,适用于容器中只有一种该类型的组件;

如果存在多个相同类型的组件,则将属性名作为 id 查询容器中的组件并注入;

默认属性对应的组件在容器中必须是存在的,如果想无论存在与否都注入可以令属性 required = false;

可以在该注解的基础之上使用 @Qualifier("bookDao") 注解指定要注入组件的 id,这时属性名的 id 已失效;

如果不使用上述注解指定 id ,存在多个相同类型的组件时也可以使用 @Primary 注解设置 Bean 的优先级为最优。

@Autowired(required = false)
@Qualifier("bookDao2")
private BookDao bookDao;

上面注入的组件的 id 值为 bookDao2;

二、@Resource

与 @Autowired 不同,@Resource 注解是 按照属性名 自动注入,它属于 JSR250 规范;

该注解不支持 @Qualifier、@Primary 的使用,但是可以使用它的 name 属性指定要注入组件的 id 值。

@Resource(name = "bookDao3")
private BookDao bookDao;

上面注入的组件的 id 值为 bookDao3;

三、@Inject

要使用 @Inject 注解必须要先导包,它属于 JSR330 规范 :

<!--    inject 注解    -->
<dependency>
    <groupId>javax.inject</groupId>
    <artifactId>javax.inject</artifactId>
    <version>1</version>
</dependency>

导包之后就可以使用了,该注解的效果和 @Autowired 的效果一样,只不过没有任何属性,所以功能有些欠缺,但是可以和另外两个注解配合使用。

@Inject
private BookDao bookDao;

上面注入的组件的 id 值为 bookDao;

四、@Autowired 的使用方式

该注解主要是通过 BeanPostProcessor 的实现类 AutowiredAnnotationBeanPostProcessor 实现的。

该类及其父类重写了 postProcessBeforeInitialization 方法,在初始化 Bean 之前,先对属性进行赋值,从而实现自动注入。

1、Set 方法

该注解除了可以放在属性上面,还可以放在方法上面:

@Component
public class Boss {
    private Car car;
    public Car getCar() {
        return car;
    }
    @Autowired
    public void setCar(Car car) {
        this.car = car;
    }
}

可以放在 set 方法上面,他会自动的去 IOC 容器中找方法中的参数,这里的参数是 car ,所以他会去容器中找 car 这个类,然后创建一个对象完成赋值。

官方 3.X 建议使用该方式注入。

2、构造器

对于加在 IOC 容器中的组件,容器启动后会调用 无参构造器 创建对象进行初始化赋值操作。

我们也可以不使用默认的,我们提供一个有参构造器:

@Autowired
public Boss(Car car) {
    this.car = car;
}

构造器要使用的组件,也都是从容器中获取。

所以也可以这么写:

public Boss(@Autowired Car car) {
    this.car = car;
}

同时如果该类只有一个有参构造器,那么 @Autowired 注解 可以省略。

官方 4.X 开始建议使用该方式注入。

3、@Bean + 方法参数

我们可以不改变 Boss 这个类,即不在 Boss 中注入 Car,而是在将 Boss 放入容器的时候注入它需要的参数 Car。

@Bean
public Boss boss(@Autowired Car car) {
    return new Boss();
}

这里的 @Autowired 可以省略,也是用的最多的一种方式。

五、使用 Spring 底层的组件

如果自己写的组件想要使用 Spring 底层的组件可以使用另一种方式 :比如想要使用 Spring 的 ApplicationContext。

Spring 为我们提供了相关的接口,他们都是 xxxAware,比如 ApplicationContextAware。

每一个接口都对应一个方法,我们可以在方法中获取 Spring 底层的组件,然后给成员变量赋值以获取相关组件。

public class Red implements ApplicationContextAware {
    private ApplicationContext context;
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.context = applicationContext;
    }
}

关于 Aware 的原理:

其实它还是使用了我们之前说过的 BeanPostProcessor ,每一个 Aware 都对应一个 AwareProcessor,这个 processor 正是BeanPostProcessor 的实现类,所以肯定会有一个 postProcessBeforeInitialization 方法,我们重点来看一下这个方法。

@Override
@Nullable
public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {
 AccessControlContext acc = null;
 if (System.getSecurityManager() != null && (bean instanceof ApplicationContextAware)) {
  acc = this.applicationContext.getBeanFactory().getAccessControlContext();
 }
 if (acc != null) {
  AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
   invokeAwareInterfaces(bean);
   return null;
  }, acc);
 }
 else {
  invokeAwareInterfaces(bean);
 }
 return bean;
}

在 invokeAwareInterfaces(bean); 方法中主要是下面的逻辑:

if (bean instanceof ApplicationContextAware) {
 ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
}

其实就是先判断是不是那几个 Aware 中的一个,如果是就赋值,我们能看到的就是在 初始化 的时候利用 后置处理器 完成赋值。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • spring通过构造函数注入实现方法分析

    本文实例讲述了spring通过构造函数注入实现方法.分享给大家供大家参考,具体如下: 一 通过构造函数注入 set注入的缺点是无法清晰表达哪些属性是必须的,哪些是可选的,构造注入的优势是通过构造强制依赖关系,不可能实例化不完全的或无法使用的bean. 二 举例 1 Employee package com.hsp.constructor; public class Employee { private String name; private int age; public Employee(S

  • 详解Spring 两种注入的方式(Set和构造)实例

    依赖注入是指对象之间关系的控制权由应用代码中转到外部容器.Spring框架主要提供了Set注入和构造注入两种依赖注入方式. 1:Set注入指的就是在接受注入的类中定义一个要被注入的类型的一个set方法,并在参数中定义需要注入的元素.Set注入式一种装配Bean属性的直接方法,但Set注入的一个缺点就是它假设了所有的可变属性都可以通过set方法访问到,无法清晰地表示哪些属性是必须的,哪些属性是可选的. 2:构造注入是在接收注入的类中定义一个构造方法,并在构造方法中定义需要注入的参数.构造注入方式的

  • Spring的自动装配Bean的三种方式

    spring的自动装配功能的定义:无须在Spring配置文件中描述javaBean之间的依赖关系(如配置<property>.<constructor-arg>).IOC容器会自动建立javabean之间的关联关系. 如果没有采用自动装配的话,手动装配我们通常在配置文件中进行实现:一下代码就是手动装配: <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="ht

  • 通过实例了解java spring使用构造器注入的原因

    这篇文章主要介绍了通过实例了解spring使用构造器注入的原因,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 一.前言 Spring框架对Java开发的重要性不言而喻,其核心特性就是IOC(Inversion of Control, 控制反转)和AOP,平时使用最多的就是其中的IOC,我们通过将组件交由Spring的IOC容器管理,将对象的依赖关系由Spring控制,避免硬编码所造成的过度程序耦合. 二.常见的三种注入方式 2.1 field注

  • Spring自动装配之方法、构造器位置的自动注入操作

    Spring自动装配之方法.构造器位置的自动注入 1. 注解定义 @Autowired的定义信息如下: @Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Autowi

  • 详解Spring Boot自动装配的方法步骤

    在<Spring Boot Hello World>中介绍了一个简单的spring boot例子,体验了spring boot中的诸多特性,其中的自动配置特性极大的简化了程序开发中的工作(不用写一行XML).本文我们就来看一下spring boot是如何做到自动配置的. 首先阐明,spring boot的自动配置是基于spring framework提供的特性实现的,所以在本文中,我们先介绍spring framework的相关特性,在了解了这些基础知识后,我们再来看spring boot的自

  • 彻底搞明白Spring中的自动装配和Autowired注解的使用

    一.自动装配 当Spring装配Bean属性时,有时候非常明确,就是需要将某个Bean的引用装配给指定属性.比如,如果我们的应用上下文中只有一个org.mybatis.spring.SqlSessionFactoryBean类型的Bean,那么任意一个依赖SqlSessionFactoryBean的其他Bean就是需要这个Bean.毕竟这里只有一个SqlSessionFactoryBean的Bean. 为了应对这种明确的装配场景,Spring提供了自动装配(autowiring).与其显式的装配

  • Java注解机制之Spring自动装配实现原理详解

    Java中使用注解的情况主要在SpringMVC(Spring Boot等),注解实际上相当于一种标记语言,它允许你在运行时动态地对拥有该标记的成员进行操作.注意:spring框架默认不支持自动装配的,要想使用自动装配需要修改spring配置文件中<bean>标签的autowire属性. 自动装配属性有6个值可选,分别代表不同的含义: byName ->从Spring环境中获取目标对象时,目标对象中的属性会根据名称在整个Spring环境中查找<bean>标签的id属性值.如果

  • Spring 自动装配的二义性实例解析

    这篇文章主要介绍了Spring 自动装配的二义性实例解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 1.我们知道可以用Spring的自动装配(@Autowired)将Bean应用注入到构造参数和属性中,但是,注意了,仅有一个bean匹配需要的结果时,自动装配才可以生效.如果有多个bean匹配同一个结果,这种歧义性会阻碍Spring自动装配属性,构造参数或方法参数. 大白话说一下,就如我们有一个甜片接口(Dessert)里面有一个好吃的方法(

  • 一篇文章教带你了解Java Spring之自动装配

    目录 在Spring中有三种装配的方式: 1.Bean的自动装配 1.1 autowire="byName" 实现自动装配 1.2 autowire="byType" 实现自动装配 2.注解实现自动装配 2.1 配置注解 2.2 @Autowired注解 2.3 @Resource注解 2.4小结 3.介绍一个idea中做笔记的小技巧 总结 在Spring中有三种装配的方式: 在xml中显示的配置 在java中显示配置 隐式的自动装配bean 1.Bean的自动装配

  • 深入浅析SpringBoot中的自动装配

    SpringBoot的自动装配是拆箱即用的基础,也是微服务化的前提.这次主要的议题是,来看看它是怎么样实现的,我们透过源代码来把握自动装配的来龙去脉. 一.自动装配过程分析 1.1.关于@SpringBootApplication 我们在编写SpringBoot项目时,@SpringBootApplication是最常见的注解了,我们可以看一下源代码: /* * Copyright 2012-2017 the original author or authors. * * Licensed un

  • 基于@Autowierd(自动装配)的使用说明

    目录 @Autowierd(自动装配)的使用 一.介绍@Autowierd自动装配之前我们需要先了解何为装配? 二.@Autowierd自动装配的使用 三.使用注解@Autowierd的"搭档"@Qualifier 四.注意事项 SpringBoot的Autowierd失败 通常是以下几种可能: @Autowierd(自动装配)的使用 @Autowired 是一个注释,它可以对类成员变量.方法及构造函数进行标注,让 spring 完成 bean 自动装配的工作. 一.介绍@Autowi

  • SpringBoot 自动装配的原理详解分析

    目录 前言 自动装配案例 自动装配分析 自动装配总结 前言 关于 ​​SpringBoot​​​ 的自动装配功能,相信是每一个 ​​Java​​ 程序员天天都会用到的一个功能,但是它究竟是如何实现的呢?今天阿粉来带大家看一下. 自动装配案例 首先我们通过一个案例来看一下自动装配的效果,创建一个 ​​SpringBoot​​ 的项目,在 ​​pom​​ 文件中加入下面的依赖. <dependency> <groupId>org.springframework.boot</gro

  • springboot 无法自动装配的问题

    目录 springboot 无法自动装配 @Autowired 报错:无法自动装配 基本上是因为 放到org.example下,问题解决 原因 无法自动装配.未找到“xxxMapper”类型的bean 说明Spring框架没有识别到你的xxxMapper中的类 如果你得类不需要管理或者继承或实现一些规则 springboot 无法自动装配 @Autowired 报错:无法自动装配 基本上是因为 1.项目里有类似mybatis @Mapper这种第三方映射类,需要用到springboot auto

随机推荐