标签:图片 应用 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; } }
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> 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); } }
【spring bean】@Resource注解的自动注入策略 , 以 项目中注入多个线程池的Bean为例 附加自定义SpringBeanSupport
标签:图片 应用 view 默认 ssi span exce card 返回
原文地址:https://www.cnblogs.com/sxdcgaq8080/p/14301929.html