zoukankan      html  css  js  c++  java
  • 【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
  • 相关阅读:
    获得CCNA和CCNP及CCIE认证的必备条件和有效期绍
    Js6利用class创建类
    Js6利用class创建类
    权益证明机制 (PoS):权益决定验证权,谁更有钱谁发言
    关于共识机制的一些想法
    有向无环图 (DAG) 技术:超越区块链的分布式账本
    寻找一种易于理解的一致性算法(扩展版)
    如何使用python语言中的方法对列表进行增删改操作
    如何操作python语言中的元素并计算相应的属性
    如何操作python语言中的列表并获取对应的元素
  • 原文地址:https://www.cnblogs.com/sxdcgaq8080/p/14301929.html
Copyright © 2011-2022 走看看