欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Spring自動裝配之方法、構(gòu)造器位置的自動注入操作

 更新時間:2021年08月09日 14:30:50   作者:金一白  
這篇文章主要介紹了Spring自動裝配之方法、構(gòu)造器位置的自動注入操作,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教

Spring自動裝配之方法、構(gòu)造器位置的自動注入

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注解可以定義在構(gòu)造器上,方法上,方法參數(shù)上,字段上,還有自定義注解上;

2. 注解使用

2.1 定義在造器上

@Autowired //定義在構(gòu)造器方法上
public UserService(UserDao userDao) {
 this.userDao = userDao;
}

或者

// 定義在構(gòu)造器參數(shù)上
public UserService(@Autowired UserDao userDao) {
 this.userDao = userDao;
}

特別注意,當一個類只有一個有參構(gòu)造器,且該構(gòu)造器不一定需要是public修飾的, 組件注入的時候不需要指定在構(gòu)造器方法上或者構(gòu)造器參數(shù)上指定@Autowired,只需要聲明構(gòu)造器即可;

2.2 定義在方法和參數(shù)上

定義在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作為方法參數(shù)傳入,這里@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. 注入位置推薦

一般推薦注入位置放在構(gòu)造器上,因為不管字段還是方法的方式注入,都是先創(chuàng)建組件,再注入依賴的組件,如果在構(gòu)造方法上就需要使用依賴的組件,那么只有在構(gòu)造器上注入才是可以實現(xiàn)的,因為執(zhí)行順序的問題;

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方式上,在構(gòu)造器上無法獲取到依賴的組件
  System.out.println(userDao); // null
 }
 
 public void setUserDao(UserDao userDao) {
  this.userDao = userDao;
 }
}

Spring 自動注入的幾種方式

Spring 中實現(xiàn)自動裝配的注解有以下幾個:

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

一、@Autowired

Spring 中最常用的一個注解,當一個組件需要另一個組件作為屬性的時候,我們可以通過兩種方式對屬性進行賦值,一種是通過構(gòu)造方法,一種是通過 set 方法(類比),而這個注解使用的方法就是后者。

下面介紹該注解的特點:

首先是 按照類型 自動注入,適用于容器中只有一種該類型的組件;

如果存在多個相同類型的組件,則將屬性名作為 id 查詢?nèi)萜髦械慕M件并注入;

默認屬性對應(yīng)的組件在容器中必須是存在的,如果想無論存在與否都注入可以令屬性 required = false;

可以在該注解的基礎(chǔ)之上使用 @Qualifier("bookDao") 注解指定要注入組件的 id,這時屬性名的 id 已失效;

如果不使用上述注解指定 id ,存在多個相同類型的組件時也可以使用 @Primary 注解設(shè)置 Bean 的優(yōu)先級為最優(yōu)。

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

上面注入的組件的 id 值為 bookDao2;

二、@Resource

與 @Autowired 不同,@Resource 注解是 按照屬性名 自動注入,它屬于 JSR250 規(guī)范;

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

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

上面注入的組件的 id 值為 bookDao3;

三、@Inject

要使用 @Inject 注解必須要先導包,它屬于 JSR330 規(guī)范 :

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

導包之后就可以使用了,該注解的效果和 @Autowired 的效果一樣,只不過沒有任何屬性,所以功能有些欠缺,但是可以和另外兩個注解配合使用。

@Inject
private BookDao bookDao;

上面注入的組件的 id 值為 bookDao;

四、@Autowired 的使用方式

該注解主要是通過 BeanPostProcessor 的實現(xiàn)類 AutowiredAnnotationBeanPostProcessor 實現(xiàn)的。

該類及其父類重寫了 postProcessBeforeInitialization 方法,在初始化 Bean 之前,先對屬性進行賦值,從而實現(xiàn)自動注入。

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 容器中找方法中的參數(shù),這里的參數(shù)是 car ,所以他會去容器中找 car 這個類,然后創(chuàng)建一個對象完成賦值。

官方 3.X 建議使用該方式注入。

2、構(gòu)造器

對于加在 IOC 容器中的組件,容器啟動后會調(diào)用 無參構(gòu)造器 創(chuàng)建對象進行初始化賦值操作。

我們也可以不使用默認的,我們提供一個有參構(gòu)造器:

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

構(gòu)造器要使用的組件,也都是從容器中獲取。

所以也可以這么寫:

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

同時如果該類只有一個有參構(gòu)造器,那么 @Autowired 注解 可以省略。

官方 4.X 開始建議使用該方式注入。

3、@Bean + 方法參數(shù)

我們可以不改變 Boss 這個類,即不在 Boss 中注入 Car,而是在將 Boss 放入容器的時候注入它需要的參數(shù) Car。

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

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

五、使用 Spring 底層的組件

如果自己寫的組件想要使用 Spring 底層的組件可以使用另一種方式 :比如想要使用 Spring 的 ApplicationContext。

Spring 為我們提供了相關(guān)的接口,他們都是 xxxAware,比如 ApplicationContextAware。

每一個接口都對應(yīng)一個方法,我們可以在方法中獲取 Spring 底層的組件,然后給成員變量賦值以獲取相關(guān)組件。

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

關(guān)于 Aware 的原理:

其實它還是使用了我們之前說過的 BeanPostProcessor ,每一個 Aware 都對應(yīng)一個 AwareProcessor,這個 processor 正是BeanPostProcessor 的實現(xiàn)類,所以肯定會有一個 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 中的一個,如果是就賦值,我們能看到的就是在 初始化 的時候利用 后置處理器 完成賦值。

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

最新評論