1.为什么@Resource出错
2.注解@Autowired和@Resource的源码区别总结
3.å¦ä½ç解@Resourceå@Referenceçåºå«
为什么@Resource出错
看spring2.0源码中的 InputStreamResource类中的isOpen() 方法:
/
*** This implementation always returns <code>true</code>.
*/
public boolean isOpen() {
return true;
}
这个方法永远返回true。
再看这个方法:
/
*** Detects which kind of validation to perform on the XML file identified
* by the supplied { @link Resource}. If the
* file has a <code>DOCTYPE</code> definition then DTD validation is 源码used
* otherwise XSD validation is assumed.
*/
protected int detectValidationMode(Resource resource) {
if (resource.isOpen()) {
throw new BeanDefinitionStoreException(
"Passed-in Resource [" + resource + "] contains an open stream: " +
"cannot determine validation mode automatically. Either pass in a Resource " +
"that is able to create fresh streams, or explicitly specify the validationMode " +
"on your XmlBeanDefinitionReader instance.");
}
... ...
}
由于resource.isOpen()永远返回true,所以这里会抛出异常。源码我的源码理解是:InputStreamResource是直指向输入流InputStream的,在构造InputStreamResource时,源码我们要加载的源码主力吃货指标源码源码副图资源第一次被打开后, 即InputStreamResource的源码getInputStream()方法调用后, 不允许再次读取资源对应的源码InputStream。下面是源码getInputStream()方法,可以看到,源码InputStreamResource用私有的源码属性 read来标记输入流是否被读取过, 若读取过一次,源码 再次读取会抛异常的源码网易新闻源码。
/
*** This 源码implementation throws IllegalStateException if attempting to
* read the underlying stream multiple times.
*/
public InputStream getInputStream() throws IOException, IllegalStateException {
if (this.read) {
throw new IllegalStateException("InputStream has already been read - " +
"do not use InputStreamResource if a stream needs to be read multiple times");
}
this.read = true;
return this.inputStream;
}
然而从spring2.0开始,为了支持xml schema,源码需要再次读取资源以检查配置文件是否遵循了DTD 和 xml schema, 又由于当前被打开的资源不能被多次读取, 以致异常抛出。从下面spring源码中关于InputStreamResource类的源码生成app说明中可以看到,作者强烈建议不要使用InputStreamResource, 而是尽量使用替代者ByteArrayResource、ClassPathResource、FileSystemResource、UrlResource等来加载xml等资源。
InputStreamResource类是获取php源码为给定的InputStream而准备的Resource接口的实现。它只有在没有其它合适的Resource接口实现类可用时才使用。而且,只要有可能就尽量使用ByteArrayResource或者其它基于文件的Resource实现。与其它Resource实现不同的是,这是个已经打开资源的描述符(因此isOpen()函数返回 true)。如果你需要在其它位置保持这个资源的企业号 源码描述符或者多次读取一个流,请不要使用它。
/
*** { @link Resource} implementation for a given InputStream. Should only
* be used if no specific Resource implementation is applicable.
* In particular, prefer { @link ByteArrayResource} or any of the
* file-based Resource implementations where possible.
*
* <p>In contrast to other Resource implementations, this is a descriptor
* for an <i>already opened</i> resource - therefore returning "true" from
* <code>isOpen()</code>. Do not use it if you need to keep the resource
* descriptor somewhere, or if you need to read a stream multiple times.
*
* @author Juergen Hoeller
* @since ..
* @see ByteArrayResource
* @see ClassPathResource
* @see FileSystemResource
* @see UrlResource
*/
public class InputStreamResource extends AbstractResource { ...}
引一段springsource站网友的解释, 供参考:
This is caused by Spring 2.0's new support for XML schema: We need to sneak into the file to find out whether it's based on our DTD or our schema now. Simply assuming the DTD as default in that case could cause strange exceptions in the XML parser that would only arise with such an InputStream specified.
The recommended solution is the same as the general resource loading recommendation of the past two years:Do not use InputStreamResource unless explicitly necessary.
注解@Autowired和@Resource的区别总结
@Autowired和@Resource是Spring框架中常见的依赖注入注解,但它们的注入机制和处理略有不同。接下来,我们将从源码角度深入剖析它们的注入过程。
@Autowired总结:
- 注入流程涉及AutowiredAnnotationBeanPostProcessor,首先检查属性或方法上的@Autowired,构建AutowiredFieldElement或AutowiredMethodElement。
- 如果未启用懒加载,AutowiredFieldElement会通过DefaultListableBeanFactory的resolveDependency方法寻找并注入bean,包括候选bean的查找和确定。
@Resource总结:
- CommonAnnotationBeanPostProcessor的buildResourceMetadata方法是切入点,只对非静态、非忽略类型的字段创建ResourceElement对象。
- ResourceElement对象的getResourceToInject方法负责获取bean,通过autowireResource方法调用。
源码分析:
1. @Autowired的注入过程涉及AutowiredAnnotationBeanPostProcessor的多个内部方法,如doResolveDependency和findAutowireCandidates,处理了候选bean的选择和懒加载机制。
2. @Resource的流程在CommonAnnotationBeanPostProcessor中更为直接,主要通过ResourceElement类的getResourceToInject方法获取bean。
学习更多关于Java和Spring的深入知识,如MyBatis、ZooKeeper等,持续关注博主的更新。
å¦ä½ç解@Resourceå@Referenceçåºå«
1ï¼å®ä¹ï¼
@Resourceï¼springç注解ï¼ä½ç¨ï¼springä¸è·åå·²ç»æ³¨å ¥å°springä¸çBean
@Reference: dubboç注解ï¼ä½ç¨ï¼æ³¨å ¥dubooæå¡ç对象
2ï¼éå°é®é¢ï¼
æ¬å°é ç½®ï¼
æ¥éï¼No provider available from registry **** for service ------------
åï¼ç»å ¸æ¥éï¼ä¸çé误就以为æ¯ç产è 没æå¯å¨å½ï¼å»zkä¸é¢çdubboç产è æ åµï¼çç没æï¼é®é¢å¥½åå·²ç»æ¾å°äºï¼ï¼ççï¼å¿½ç¶åç°ä»ä¸ºä»ä¹å»çæ¯ registry 1å¢ï¼ä¸åºè¯¥å»1å2é½æ¾åï¼ å¯¹äºï¼@Reference 注ådubboä¸ç®¡æ¯ä»ä¹æ¹å¼ï¼æ éæ¯registry å versionçæå®ï¼ç±äºæ没ææå®ï¼é£æç §springçç解è¯å®æ¯èµ°èªå¨è£ é å½ï¼é£æè¿è¾¹é ç½®äºä¸¤ä¸ªæ³¨åä¸å¿ï¼æ¯ä¸æ¯ä»ä¼æºè½çé½æ¾æ¾å¢ï¼ï¼ä¸æ¯çï¼dubboç产è å¦ææå®å¤ä¸ªregistryï¼ç¶å<dubbo:service/>声æçæå¡ä¼æ³¨åå°å¤ä¸ªæ³¨åä¸å¿ï¼<dubbo:reference/>æ¶è´¹ç«¯å¤æ³¨åä¸å¿æ¶æ¯éè¦æå®å»åªä¸ªæ³¨åä¸å¿çï¼æä¸æ³å¨@Referenceåé¢åä¸å¤§å ï¼å°±æ³èµ°èªå¨åè£ é ï¼æåæ¾å°å¯ä»¥å¨registry声ææ¶ default çå±æ§çï¼
æ ¹æ®ä¸ç³»åççæµãææé ç½®æ¹ä¸ºäºï¼
èªæ¤é®é¢è§£å³äºï¼ï¼ï¼ï¼ï¼
æåç°æ°çé®é¢ï¼ä½¿ç¨@Referenceæ¥æ³¨å ¥dubboæå¡ï¼é£å¦ææ项ç®ä¸å¤ä¸ªå°æ¹æ³ä½¿ç¨ï¼æå¨å¤ä¸ªç±»ä¸ä½¿ç¨@Reference ï¼å²ä¸æ¯æ³¨å ¥å¤ä¸ªbeanäºï¼è¿ä¸ªç解æ¯æé®é¢çï¼è¿æ¶æªæè¯å°ï¼ãè¿æ¾ç¶æ¯æé®é¢çï¼å æ¤ææ³å°dubboæå¡ä»¥åä¾æ³¨å ¥å°springä¸ï¼æ¢æ springèªå·±ç@Resourceæ ç¾æ¥è·åï¼å æ¤æå°é ç½®æ¹æäºä¸ä¸ï¼
æµè¯ä¸ä¸ï¼ç¡®å®å¥½ä½¿ï¼ï¼èªæ¤é 置使ç¨æ¹é¢æ²¡ä»ä¹é®é¢äºï¼ç¬¦åä¸ä¸ªäººçæ£å¸¸é»è¾äºï¼
ä½æ¯è¿æä¸ä¸ªé®é¢ï¼å°±æ¯ï¼
âæåç°æ°çé®é¢ï¼ä½¿ç¨@Referenceæ¥æ³¨å ¥dubboæå¡ï¼é£å¦ææ项ç®ä¸å¤ä¸ªå°æ¹æ³ä½¿ç¨ï¼æå¨å¤ä¸ªç±»ä¸ä½¿ç¨@Reference ï¼å²ä¸æ¯æ³¨å ¥å¤ä¸ªbeanäº â è¿ä¸ªé®é¢ççåå¨åï¼
ä¸é¢æ¥è§£çè¿ä¸ªé®é¢ï¼
springçé ç½® ä½¿ç¨ xml æè 注解 åªæ¯ 使ç¨æ¹å¼çä¸åï¼@Reference å <dubbo:reference/> çææåºè¯¥æ¯æ¯ä¸æ ·ç, springé»è®¤æ³¨å ¥Bean,scopeåºè¯¥æ¯singleton , é£æå¨å¤ä¸ªç±»ä¸ä½¿ç¨@Reference æ³¨å ¥åä¸ä¸ªdubboæå¡åºè¯¥æ¯å¨springä¸åªåå¨ä¸ä¸ªäºï¼ï¼äºå®ä¸çæ¯çï¼
å¤ä¸ª@Reference æ ç¾ æ³¨å ¥é 置信æ¯å®å ¨ç¸åç æå¡ ï¼æ¯ä¼ææå¡Beanç¼åçï¼ä¿è¯åªä¼æä¸ä¸ª æå¡Bean ,æºç å¦ä¸ï¼ è¿ä¸ªæ¹æ³ generateReferenceBeanCacheKey æ¯ç¼åkeyçè·åãã
private ReferenceBean<?> buildReferenceBean(Reference reference, Class<?> referenceClass) throws Exception { // è·åæå¡å¼ç¨å¯¹è±¡çç¼åkey String referenceBeanCacheKey = generateReferenceBeanCacheKey(reference, referenceClass); // ä»ç¼åmapä¸è·åæå¡å¼ç¨å¯¹è±¡ ReferenceBean<?> referenceBean = referenceBeansCache.get(referenceBeanCacheKey); if (referenceBean == null) { // å¦æå¼ç¨å¯¹è±¡ä¸ºç©ºï¼åéè¦å½åºå建ä¸ä¸ª ReferenceBeanBuilder beanBuilder = ReferenceBeanBuilder .create(reference, classLoader, applicationContext) .interfaceClass(referenceClass); referenceBean = beanBuilder.build(); //并ä¸æ¾å ¥å°ç¼åmapä¸ã referenceBeansCache.putIfAbsent(referenceBeanCacheKey, referenceBean); } return referenceBean; } private String generateReferenceBeanCacheKey(Reference reference, Class<?> beanClass) { // è·åæ¥å£å称 String interfaceName = resolveInterfaceName(reference, beanClass); // éè¿å¼ç¨çURl+æ¥å£å+æ¥å£çæ¬å·+æ¥å£åç»ï¼ç¨æ¥åç¼åkey String key = reference.url() + "/" + interfaceName + "/" + reference.version() + "/" + reference.group(); Environment environment = applicationContext.getEnvironment(); key = environment.resolvePlaceholders(key); return key; }
èªæ¤é®é¢è¯´æå®æ¯ãã
é®é¢æ´çï¼
1ï¼å¤æ³¨åä¸å¿æ¶ï¼spring èªå¨åè£ é æ¶ï¼éè¦èªå·±æå® æä¸ä¸ªæ³¨åä¸å¿ æè å°æ个注åä¸å¿ default设置为true.
2, @Resource å @Reference é½å¯ æ³¨å ¥ dubboæå¡ä½æ¯ æ¦å¿µæ¯ä¸ä¸æ ·çã
3ï¼@Reference 注解å¯ä»¥å¨å¤ä¸ªç±»ä¸æ³¨å ¥ ç¸åæå¡Bean ä¸ä¼é ææå¡Bean åå¨å¤ä¸ªãã
注ï¼æºç åè æç« /article/