【spring bean】@Resource注解的自動注入策略 , 以 項目中注入多個線程池的Bean為例 附加自定義SpringBeanSupport


 

 

@Resource和@Autowired注解都是用來實現依賴注入的。只是@AutoWried按by type自動注入,而@Resource默認按byName自動注入。

@Resource有兩個重要屬性,分別是name和type

spring將name屬性解析為bean的名字,而type屬性則被解析為bean的類型。所以如果使用name屬性,則使用byName的自動注入策略,如果使用type屬性則使用byType的自動注入策略。如果都沒有指定,則通過反射機制使用byName自動注入策略。

@Resource依賴注入時查找bean的規則:(以用在field上為例)

1. 既不指定name屬性,也不指定type屬性,則自動按byName方式進行查找。如果沒有找到符合的bean,則回退為一個原始類型進行查找,如果找到就注入。

 

此時name是變量名

 

錯誤示例:

@Resource
    private String bucketName;
    @Resource
    private String styleName;

 

此時的name值是配置bean里的name屬性指定的值,而不是id的值

 

<bean id="bucketName " class="java.lang.String"> 
    <constructor-arg value="${oos.bucketName}"/> 
</bean> 
<!-- 圖片樣式名 --> 
<bean id="styleName " class="java.lang.String"> 
    <constructor-arg value="${oos.styleName}"/> 
</bean>

 

 

這里為什么要重新理解,是因為之前我一直認為對應的是配置文件的id屬性的值,直到在配置上面兩個String類型的bean的時候,居然會報錯,如下: No qualifying bean of type [java.lang.String] is defined: expected single matching bean but found 2: bucketName,styleName 這是因為spring會去找bean元素里name屬性值和變量名一致的bean,但是因為都沒有指定name屬性,所以找不到然后就按照原始類型String去查找,結果一下找到了兩個,所以就報錯。

 

2. 只是指定了@Resource注解的name,則按name后的名字去bean元素里查找有與之相等的name屬性的bean。

正確示例

    @Resource(name="bucket")
    private String bucketName;
    @Resource(name="style")
    private String styleName;

 

 

<bean name="bucket" class="java.lang.String"> 
    <constructor-arg value="${oos.bucketName}"/> 
</bean> 
<!-- 圖片樣式名 --> 
<bean name="style" class="java.lang.String"> 
    <constructor-arg value="${oos.styleName}"/> 
</bean>

 

3. 只指定@Resource注解的type屬性,則從上下文中找到類型匹配的唯一bean進行裝配,找不到或者找到多個,都會拋出異常

4. 既指定了@Resource的name屬性又指定了type,則從Spring上下文中找到唯一匹配的bean進行裝配,找不到則拋出異常

 

 

 

===========================以一份程序中 隔離多個業務線程池為例===================

1.yml文件

# 線程池配置
thread:
  pool:
    core:
      size: 10
    max:
      size: 10
    queue:
      capacity: 10000
    alive:
      seconds: 1000

 

 

2.java文件

線程池注入為Bean交給Spring管理

 

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.ThreadPoolExecutor;



@Configuration
@ConditionalOnProperty(name = "thread.pool.core.size")
public class ThreadPoolConfiguration {

    @Value("${thread.pool.core.size}")
    private Integer coreSize;

    @Value("${thread.pool.max.size}")
    private Integer maxSize;

    @Value("${thread.pool.queue.capacity}")
    private Integer queueCapacity;

    @Value("${thread.pool.alive.seconds}")
    private Integer keepAliveSeconds;


    @Bean(name = "taskExecutor1")
    public ThreadPoolTaskExecutor taskExecutor() {
        ThreadPoolTaskExecutor poolTaskExecutor = new ThreadPoolTaskExecutor();
        poolTaskExecutor.setCorePoolSize(coreSize);
        poolTaskExecutor.setMaxPoolSize(maxSize);
        poolTaskExecutor.setQueueCapacity(queueCapacity);
        poolTaskExecutor.setKeepAliveSeconds(keepAliveSeconds);
        return poolTaskExecutor;
    }

    @Bean(name = "taskExecutor2")
    public ThreadPoolTaskExecutor monitorTaskExecutor() {
        ThreadPoolTaskExecutor poolTaskExecutor = new ThreadPoolTaskExecutor();
        poolTaskExecutor.setCorePoolSize(coreSize);
        poolTaskExecutor.setMaxPoolSize(maxSize);
        poolTaskExecutor.setQueueCapacity(queueCapacity);
        poolTaskExecutor.setKeepAliveSeconds(keepAliveSeconds);
        poolTaskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardOldestPolicy());
        poolTaskExecutor.setThreadNamePrefix("plat-form-monitor-pool-");
        return poolTaskExecutor;
    }

    @Bean(name = "taskExecutor3")
    public ThreadPoolTaskExecutor reportTaskExecutor() {
        ThreadPoolTaskExecutor reportpoolTaskExecutor = new ThreadPoolTaskExecutor();
        reportpoolTaskExecutor.setCorePoolSize(coreSize);
        reportpoolTaskExecutor.setMaxPoolSize(maxSize);
        reportpoolTaskExecutor.setQueueCapacity(queueCapacity);
        reportpoolTaskExecutor.setKeepAliveSeconds(keepAliveSeconds);
        reportpoolTaskExecutor.setThreadNamePrefix("report-export-pool-");
        return reportpoolTaskExecutor;
    }
}
View Code

 

3.使用場景

 

3.1使用的地方[如果都是如下這樣使用,則沒有任何問題]:

A.Class中

@Resource
ThreadPoolTaskExecutor taskExecutor1;



B.Class中

@Resource
ThreadPoolTaskExecutor taskExecutor2;


C.Class中

@Resource
ThreadPoolTaskExecutor taskExecutor3;

如上的方式使用,則沒有任何問題,因為 @Resource是byName自動注入的。

 

 

 

 

 

3.2 但是如果是下面這種byType使用方式,則會出現問題:

A.Class中

@Resource
ThreadPoolTaskExecutor taskExecutor1;




B.Class中

public class B  {
    
    private static final ThreadPoolTaskExecutor taskExecutor;


    static {
        taskExecutor2 = SpringBeanSupport.getBean(ThreadPoolTaskExecutor.class);
    }

}

 

如上使用方式就會有問題,因為 B類中是按照byClass去注入的,而咱們隔離的三個獨立的線程池,都是ThreadPoolTaskExecutor類型的,所以啟動會報錯,因為這個getBean會找到三個。

 

 

 

3.3 但是如果是修改為下面這種byName使用方式,則問題解決:

A.Class中

@Resource
ThreadPoolTaskExecutor taskExecutor1;




public class B  {
    
    private static final ThreadPoolTaskExecutor taskExecutor;


    static {
        taskExecutor2 = SpringBeanSupport.getBean("taskExecutor2"); 
    }

}

 

 

 

 

 

附加  附上SpringBeanSupport源碼:

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

@Component
public class SpringBeanSupport implements ApplicationContextAware {

    /** Spring應用上下文環境 */    
    private static ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        SpringBeanSupport.applicationContext = applicationContext;
    }


    /**   
     * @return ApplicationContext   
     */
    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }

    /**
     * 獲取對象
     * @param name
     * @return Object 一個以所給名字注冊的bean的實例
     * @throws BeansException
     */
    public static <T> T getBean(String name) throws BeansException {
        return (T) applicationContext.getBean(name);
    }


    /**   
     * 獲取類型為requiredType的對象   
     * 如果bean不能被類型轉換,相應的異常將會被拋出(BeanNotOfRequiredTypeException)   
     * @param name       bean注冊名   
     * @param requiredType 返回對象類型   
     * @return Object 返回requiredType類型對象   
     * @throws BeansException
     */
    public static Object getBean(String name, Class<?> requiredType) throws BeansException {
        return applicationContext.getBean(name, requiredType);
    }

    /**
     * 獲取class對應的bean
     * @param tClass
     * @return
     */
    public static <T> T getBean(Class<T> tClass) {
        return applicationContext.getBean(tClass);
    }

    /**   
     * 如果BeanFactory包含一個與所給名稱匹配的bean定義,則返回true    
     * @param name   
     * @return boolean   
     */
    public static boolean containsBean(String name) {
        return applicationContext.containsBean(name);
    }

    /**   
     * 判斷以給定名字注冊的bean定義是一個singleton還是一個prototype。   
     * 如果與給定名字相應的bean定義沒有被找到,將會拋出一個異常(NoSuchBeanDefinitionException)      
     * @param name   
     * @return boolean   
     * @throws NoSuchBeanDefinitionException
     */
    public static boolean isSingleton(String name) throws NoSuchBeanDefinitionException {
        return applicationContext.isSingleton(name);
    }

    /**   
     * @param name   
     * @return Class 注冊對象的類型   
     * @throws NoSuchBeanDefinitionException
     */
    public static Class<?> getType(String name) throws NoSuchBeanDefinitionException {
        return applicationContext.getType(name);
    }

    /**   
     * 如果給定的bean名字在bean定義中有別名,則返回這些別名      
     * @param name   
     * @return   
     * @throws NoSuchBeanDefinitionException
     */
    public static String[] getAliases(String name) throws NoSuchBeanDefinitionException {
        return applicationContext.getAliases(name);
    }

}
View Code

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM