【spring bean】@Resource注解的自动注入策略 , 以 项目中注入多个线程池的Bean为例 附加自定义SpringBeanSupport

2021-03-06 08:27

阅读:379

标签:图片   应用   view   默认   ssi   span   exce   card   返回   

 

 

@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 但是如果是下面这种使用方式,则会出现问题:

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 但是如果是修改为下面这种使用方式,则问题解决:

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 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 getBean(Class 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

 

【spring bean】@Resource注解的自动注入策略 , 以 项目中注入多个线程池的Bean为例 附加自定义SpringBeanSupport

标签:图片   应用   view   默认   ssi   span   exce   card   返回   

原文地址:https://www.cnblogs.com/sxdcgaq8080/p/14301929.html


评论


亲,登录后才可以留言!