dubbo之@Reference注解作用說明
目的
看看dubbo是怎么給加了@Reference注解的屬性注入invoker實(shí)例,為什么有時(shí)候加了@Reference注解的屬性會(huì)是null。
ReferenceAnnotationBeanPostProcessor
看到這個(gè)名字,就很容易知道,是專門針對(duì)@Reference注解的后置處理。
ReferenceAnnotationBeanPostProcessor的代碼比較多,下面列一下比較重要的內(nèi)容。
public class ReferenceAnnotationBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter
implements MergedBeanDefinitionPostProcessor, PriorityOrdered, ApplicationContextAware, BeanClassLoaderAware,
DisposableBean {
// 緩存加了@Referece注解的元數(shù)據(jù)信息,key是bean的名稱或者類名,value是加了@Reference的屬性和方法
private final ConcurrentMap<String, ReferenceInjectionMetadata> injectionMetadataCache =
new ConcurrentHashMap<String, ReferenceInjectionMetadata>(256);
// 緩存new過的ReferenceBean,相同的key,只會(huì)產(chǎn)生一個(gè)ReferenceBean
private final ConcurrentMap<String, ReferenceBean<?>> referenceBeansCache =
new ConcurrentHashMap<String, ReferenceBean<?>>();
// spring設(shè)置屬性到bean之前調(diào)用該方法
@Override
public PropertyValues postProcessPropertyValues(
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeanCreationException {
// 根據(jù)bean的類型,獲取需要注入的元數(shù)據(jù)信息
InjectionMetadata metadata = findReferenceMetadata(beanName, bean.getClass(), pvs);
try {
// 注入對(duì)象
metadata.inject(bean, beanName, pvs);
} catch (BeanCreationException ex) {
throw ex;
} catch (Throwable ex) {
throw new BeanCreationException(beanName, "Injection of @Reference dependencies failed", ex);
}
return pvs;
}
private InjectionMetadata findReferenceMetadata(String beanName, Class<?> clazz, PropertyValues pvs) {
// 如果是自定義的消費(fèi)者,沒有beanName,退化成使用類名作為緩存key
String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
// 雙重檢查,判斷是否需要刷新注入信息
ReferenceInjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
// 判斷是否需要刷新
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
// 第一次判斷為需要刷新,則鎖住injectionMetadataCache對(duì)象
synchronized (this.injectionMetadataCache) {
// 再次判斷是否需要刷新
metadata = this.injectionMetadataCache.get(cacheKey);
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
// 需要刷新,而且原來緩存的信息不為空,清除緩存信息
if (metadata != null) {
metadata.clear(pvs);
}
try {
// 生成新的元數(shù)據(jù)信息
metadata = buildReferenceMetadata(clazz);
// 放入緩存
this.injectionMetadataCache.put(cacheKey, metadata);
} catch (NoClassDefFoundError err) {
throw new IllegalStateException("Failed to introspect bean class [" + clazz.getName() +
"] for reference metadata: could not find class that it depends on", err);
}
}
}
}
return metadata;
}
private ReferenceInjectionMetadata buildReferenceMetadata(final Class<?> beanClass) {
// 查找加了@Reference注解的屬性
Collection<ReferenceFieldElement> fieldElements = findFieldReferenceMetadata(beanClass);
// 查找加了@Reference注解的屬性
// !!!!@Reference還能加到方法上!!!還真沒試過
// 不過這個(gè)不關(guān)心,只關(guān)注屬性的
Collection<ReferenceMethodElement> methodElements = findMethodReferenceMetadata(beanClass);
return new ReferenceInjectionMetadata(beanClass, fieldElements, methodElements);
}
private List<ReferenceFieldElement> findFieldReferenceMetadata(final Class<?> beanClass) {
// 保存加了@Reference注解的屬性列表
final List<ReferenceFieldElement> elements = new LinkedList<ReferenceFieldElement>();
ReflectionUtils.doWithFields(beanClass, new ReflectionUtils.FieldCallback() {
@Override
public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException {
// 獲取屬性上的@Reference注解
Reference reference = getAnnotation(field, Reference.class);
// 如果存在@Reference注解
if (reference != null) {
// 不支持靜態(tài)屬性的注入
if (Modifier.isStatic(field.getModifiers())) {
if (logger.isWarnEnabled()) {
logger.warn("@Reference annotation is not supported on static fields: " + field);
}
return;
}
// 添加到隊(duì)列里
elements.add(new ReferenceFieldElement(field, reference));
}
}
});
return elements;
}大致的流程如下:

ReferenceInjectionMetadata
dubbo在ReferenceAnnotationBeanPostProcessor里定義了一個(gè)私有的子類
ReferenceInjectionMetadata繼承spring定義的InjectionMetadata類。
之所以需要自定義ReferenceInjectionMetadata類,是因?yàn)閐ubbo的@Reference注解可以使用在屬性和方法上,需要區(qū)分開。但是spring定義的InjectionMetadata類,只支持一個(gè)injectedElements集合,代碼如下:
public class InjectionMetadata {
private static final Log logger = LogFactory.getLog(InjectionMetadata.class);
private final Class<?> targetClass;
private final Collection<InjectedElement> injectedElements;
@Nullable
private volatile Set<InjectedElement> checkedElements;
public InjectionMetadata(Class<?> targetClass, Collection<InjectedElement> elements) {
// 構(gòu)造函數(shù)接收兩個(gè)參數(shù),類型,注入的元素
this.targetClass = targetClass;
this.injectedElements = elements;
}
......
......
......
public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
Collection<InjectedElement> checkedElements = this.checkedElements;
// 優(yōu)先使用checkedElements來注入,如果checkedElements為空,則直接使用injectedElements(沒有調(diào)用checkConfigMembers方法,checkedElements會(huì)空)
Collection<InjectedElement> elementsToIterate =
(checkedElements != null ? checkedElements : this.injectedElements);
if (!elementsToIterate.isEmpty()) {
// 循環(huán)遍歷所有待注入的元素
for (InjectedElement element : elementsToIterate) {
if (logger.isTraceEnabled()) {
logger.trace("Processing injected element of bean '" + beanName + "': " + element);
}
// 調(diào)用注入方法
element.inject(target, beanName, pvs);
}
}
}
基于這個(gè)原因,dubbo定義了ReferenceInjectionMetadata類,代碼如下:
private static class ReferenceInjectionMetadata extends InjectionMetadata {
private final Collection<ReferenceFieldElement> fieldElements;
private final Collection<ReferenceMethodElement> methodElements;
public ReferenceInjectionMetadata(Class<?> targetClass, Collection<ReferenceFieldElement> fieldElements,
Collection<ReferenceMethodElement> methodElements) {
// 構(gòu)造函數(shù)接收3個(gè)參數(shù),類型,待注入的屬性元素,待注入的方法元素
// 把fieldElements和methodElements的內(nèi)容合并,作為InjectionMetadata的injectedElements
super(targetClass, combine(fieldElements, methodElements));
this.fieldElements = fieldElements;
this.methodElements = methodElements;
}
private static <T> Collection<T> combine(Collection<? extends T>... elements) {
List<T> allElements = new ArrayList<T>();
for (Collection<? extends T> e : elements) {
allElements.addAll(e);
}
return allElements;
}
public Collection<ReferenceFieldElement> getFieldElements() {
return fieldElements;
}
public Collection<ReferenceMethodElement> getMethodElements() {
return methodElements;
}
}
代碼很簡(jiǎn)單,入?yún)⒆優(yōu)?個(gè),屬性和方法列表區(qū)分開,然后把兩者合并起來,調(diào)用父類的構(gòu)造函數(shù),用fieldElements保存屬性列表,用methodElements保存方法列表。
ReferenceFieldElement
屬性注入實(shí)際發(fā)生在ReferenceFieldElement類,代碼如下:
private class ReferenceFieldElement extends InjectionMetadata.InjectedElement {
private final Field field;
private final Reference reference;
private volatile ReferenceBean<?> referenceBean;
// 構(gòu)造函數(shù)會(huì)傳入要設(shè)置的Field對(duì)象,Reference注解對(duì)象
protected ReferenceFieldElement(Field field, Reference reference) {
super(field, null);
this.field = field;
this.reference = reference;
}
@Override
protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable {
Class<?> referenceClass = field.getType();
// 構(gòu)建ReferenceBean對(duì)象
referenceBean = buildReferenceBean(reference, referenceClass);
// 將屬性設(shè)置為可訪問的
ReflectionUtils.makeAccessible(field);
// 給Field對(duì)象設(shè)置屬性
field.set(bean, referenceBean.getObject());
}
}
ReferenceMethodElement
方法注入實(shí)際發(fā)生在ReferenceMethodElement類,代碼如下:
private class ReferenceMethodElement extends InjectionMetadata.InjectedElement {
private final Method method;
private final Reference reference;
private volatile ReferenceBean<?> referenceBean;
protected ReferenceMethodElement(Method method, PropertyDescriptor pd, Reference reference) {
super(method, pd);
this.method = method;
this.reference = reference;
}
@Override
protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable {
// 獲取類型
Class<?> referenceClass = pd.getPropertyType();
// 構(gòu)建ReferenceBean對(duì)象
referenceBean = buildReferenceBean(reference, referenceClass);
// 將方法設(shè)置為可訪問
ReflectionUtils.makeAccessible(method);
// 把referenceBean生成的對(duì)象作為入?yún)?,調(diào)用bean對(duì)象的method方法
// 看到這里,就能明白,@Reference也可以加在那些setXXX方法上
// 例如有個(gè)userService屬性,有個(gè)setUserService方法,可以在setUserService方法上加@Reference注解
method.invoke(bean, referenceBean.getObject());
}
}
為什么加了@Reference注解的屬性是null
從上面的代碼分析,可以知道屬性的注入,是靠ReferenceAnnotationBeanPostProcessor后置處理來觸發(fā),往filed設(shè)置值。
如果這一過程中,發(fā)生異常,導(dǎo)致沒有成功為field設(shè)置值,則加了@Referencce的屬性就會(huì)一直是null。
2020-07-30 17:00:00.013 WARN 13092 --- [ main] com.alibaba.dubbo.config.AbstractConfig : [] [DUBBO] null, dubbo version: 2.6.2, current host: 10.0.45.150
java.lang.reflect.InvocationTargetException: null
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.alibaba.dubbo.config.AbstractConfig.toString(AbstractConfig.java:474)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at com.alibaba.dubbo.config.spring.beans.factory.annotation.AbstractAnnotationConfigBeanBuilder.build(AbstractAnnotationConfigBeanBuilder.java:79)
at com.alibaba.dubbo.config.spring.beans.factory.annotation.ReferenceAnnotationBeanPostProcessor.buildReferenceBean(ReferenceAnnotationBeanPostProcessor.java:385)
at com.alibaba.dubbo.config.spring.beans.factory.annotation.ReferenceAnnotationBeanPostProcessor.access$100(ReferenceAnnotationBeanPostProcessor.java:65)
at com.alibaba.dubbo.config.spring.beans.factory.annotation.ReferenceAnnotationBeanPostProcessor$ReferenceFieldElement.inject(ReferenceAnnotationBeanPostProcessor.java:363)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:90)
at com.alibaba.dubbo.config.spring.beans.factory.annotation.ReferenceAnnotationBeanPostProcessor.postProcessPropertyValues(ReferenceAnnotationBeanPostProcessor.java:92)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1400)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:592)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:277)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1247)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1167)
at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:857)
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:760)
at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:218)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1325)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1171)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:555)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:849)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:877)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:549)
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:142)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:775)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:316)
at com.xdchen.bp.award.api.server.Application.main(Application.java:20)
Caused by: java.lang.IllegalStateException: Failed to check the status of the service com.xdchen.searchplatform.searcher.protocol.SearcherService. No provider available for the service com.xdchen.searchplatform.searcher.protocol.SearcherService:1.0.0111 from the url zookeeper://zk1.esf.fdd:2181/com.alibaba.dubbo.registry.RegistryService?application=award.ddxf.bp.fdd&default.reference.filter=traceIdConsumer,default,consumerCatFilter&default.timeout=6000&dubbo=2.6.2&interface=com.xdchen.searchplatform.searcher.protocol.SearcherService&methods=search,searchByBytes,multiSearch,scrollIndex,searchByHttp,searchByIds,multiSearchByBytes&organization=fangdd&owner=chenxudong&pid=13092®ister.ip=10.0.45.150&revision=3.8.0&side=consumer&timeout=5000×tamp=1596099599500&version=1.0.0111 to the consumer 10.0.45.150 use dubbo version 2.6.2
at com.alibaba.dubbo.config.ReferenceConfig.createProxy(ReferenceConfig.java:422)
at com.alibaba.dubbo.config.ReferenceConfig.init(ReferenceConfig.java:333)
at com.alibaba.dubbo.config.ReferenceConfig.get(ReferenceConfig.java:163)
at com.alibaba.dubbo.config.spring.ReferenceBean.getObject(ReferenceBean.java:66)
... 42 common frames omitted2020-07-30 17:00:00.014 INFO 13092 --- [ main] c.a.d.c.s.b.f.a.ReferenceBeanBuilder : [] <dubbo:reference singleton="true" interface="com.xdchen.searchplatform.searcher.protocol.SearcherService" uniqueServiceName="com.xdchen.searchplatform.searcher.protocol.SearcherService:1.0.0111" generic="false" version="1.0.0111" timeout="5000" id="com.xdchen.searchplatform.searcher.protocol.SearcherService" /> has been built.
看這一段錯(cuò)誤日志,當(dāng)SearcherService沒有任何provider啟動(dòng)的時(shí)候調(diào)用ReferenceBean.getObject方法,就會(huì)拋IllegalStateException異常,設(shè)置屬性失敗。
網(wǎng)上很多說,遇到加@Reference注解的屬性為null的,應(yīng)該就是這個(gè)情況。
什么情況會(huì)拋No provider的IllegalStateException異常
ReferenceAnnotationBeanPostProcessor.buildReferenceBean
private ReferenceBean<?> buildReferenceBean(Reference reference, Class<?> referenceClass) throws Exception {
String referenceBeanCacheKey = generateReferenceBeanCacheKey(reference, referenceClass);
ReferenceBean<?> referenceBean = referenceBeansCache.get(referenceBeanCacheKey);
if (referenceBean == null) {
ReferenceBeanBuilder beanBuilder = ReferenceBeanBuilder
.create(reference, classLoader, applicationContext)
.interfaceClass(referenceClass);
// 這里報(bào)錯(cuò)
referenceBean = beanBuilder.build();
referenceBeansCache.putIfAbsent(referenceBeanCacheKey, referenceBean);
}
return referenceBean;
}
buildReferenceBean方法調(diào)用ReferenceBeanBuilder.build報(bào)錯(cuò)
ReferenceBeanBuilder.build
ReferenceBeanBuilder.build方法是它的父類AbstractAnnotationConfigBeanBuilder的
public final B build() throws Exception {
checkDependencies();
B bean = doBuild();
configureBean(bean);
if (logger.isInfoEnabled()) {
// 這里報(bào)錯(cuò)
logger.info(bean + " has been built.");
}
return bean;
}
ReferenceBeanBuilder.doBuild
ReferenceBeanBuilder重寫了doBuild方法,返回ReferenceBean對(duì)象
@Override
protected ReferenceBean doBuild() {
return new ReferenceBean<Object>();
}
所以,問題是出在了ReferenceBean.toString方法上
AbstractConfig.toString
ReferenceBean并沒有重寫toString方法,但他的根父類是AbstractConfig,看錯(cuò)誤日志,可以看到這個(gè):
at com.alibaba.dubbo.config.AbstractConfig.toString(AbstractConfig.java:474)
AbstractConfig.toString代碼如下:
@Override
public String toString() {
try {
StringBuilder buf = new StringBuilder();
buf.append("<dubbo:");
buf.append(getTagName(getClass()));
Method[] methods = getClass().getMethods();
// 拿到當(dāng)前類的所有方法
for (Method method : methods) {
try {
String name = method.getName();
// 過濾剩下get和is開頭的方法,但不包括getClass、get和is
if ((name.startsWith("get") || name.startsWith("is"))
&& !"getClass".equals(name) && !"get".equals(name) && !"is".equals(name)
&& Modifier.isPublic(method.getModifiers())
&& method.getParameterTypes().length == 0
&& isPrimitive(method.getReturnType())) {
int i = name.startsWith("get") ? 3 : 2;
String key = name.substring(i, i + 1).toLowerCase() + name.substring(i + 1);
// 反射獲取方法返回值,拼接字符串
// 就是這里報(bào)空指針
Object value = method.invoke(this, new Object[0]);
if (value != null) {
buf.append(" ");
buf.append(key);
buf.append("=\"");
buf.append(value);
buf.append("\"");
}
}
} catch (Exception e) {
logger.warn(e.getMessage(), e);
}
}
buf.append(" />");
return buf.toString();
} catch (Throwable t) {
logger.warn(t.getMessage(), t);
return super.toString();
}
}
ReferenceBean.getObjet
ReferenceBean類實(shí)現(xiàn)類FactoryBean接口,實(shí)現(xiàn)了getObject方法,getObject方法滿足get開頭的條件,會(huì)被AbstractConfig.toString方法調(diào)用到
public class ReferenceBean<T> extends ReferenceConfig<T> implements FactoryBean, ApplicationContextAware, InitializingBean, DisposableBean {
@Override
public Object getObject() throws Exception {
return get();
}
public synchronized T get() {
if (destroyed) {
throw new IllegalStateException("Already destroyed!");
}
if (ref == null) {
init();
}
return ref;
}
private void init() {
if (initialized) {
return;
}
initialized = true;
......
......
ref = createProxy(map);
ConsumerModel consumerModel = new ConsumerModel(getUniqueServiceName(), this, ref, interfaceClass.getMethods());
ApplicationModel.initConsumerModel(getUniqueServiceName(), consumerModel);
}
private T createProxy(Map<String, String> map) {
......
......
Boolean c = check;
if (c == null && consumer != null) {
c = consumer.isCheck();
}
if (c == null) {
c = true; // default true
}
if (c && !invoker.isAvailable()) {
throw new IllegalStateException("Failed to check the status of the service " + interfaceName + ". No provider available for the service " + (group == null ? "" : group + "/") + interfaceName + (version == null ? "" : ":" + version) + " from the url " + invoker.getUrl() + " to the consumer " + NetUtils.getLocalHost() + " use dubbo version " + Version.getVersion());
}
if (logger.isInfoEnabled()) {
logger.info("Refer dubbo service " + interfaceClass.getName() + " from url " + invoker.getUrl());
}
// create service proxy
return (T) proxyFactory.getProxy(invoker);
}
省略了大部分代碼,只保留了比較重要的,調(diào)用getObject方法,會(huì)判斷是否初始化過,如果初始化過,直接返回ref;如果沒有初始化,則會(huì)進(jìn)行初始化,然后調(diào)用createProxy方法來創(chuàng)建代理,如果我們沒有配置consumer的check或者check=true,則會(huì)檢查invoker對(duì)象的可用性“invoker.isAvailable()”,如果不可用,就會(huì)拋IllegalStateException異常。
避免@Reference注解的屬性為null
配置消費(fèi)者的檢查為false,即@Reference(check=false)
ReferenceBean.getObject調(diào)用時(shí)機(jī)的猜測(cè)
看的ReferenceFieldElement.inject方法,很容易以為IllegalStateException是在 “field.set(bean, referenceBean.getObject());”這一行報(bào)錯(cuò)的,但實(shí)際上是在 “referenceBean = buildReferenceBean(reference, referenceClass);”
@Override
protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable {
Class<?> referenceClass = field.getType();
// 構(gòu)建ReferenceBean對(duì)象
referenceBean = buildReferenceBean(reference, referenceClass);
// 將屬性設(shè)置為可訪問的
ReflectionUtils.makeAccessible(field);
// 給Field對(duì)象設(shè)置屬性
field.set(bean, referenceBean.getObject());
}
為什么要在AbstractConfig.toString就調(diào)用了getObject方法,觸發(fā)報(bào)錯(cuò)呢?
如果AbstractConfig.toString過濾掉getObject方法,會(huì)發(fā)生什么事情呢?
InjectionMetadata.inject方法是遍歷checkedElements列表,挨個(gè)調(diào)用element.inject方法。
如果AbstractConfig.toString過濾掉getObject方法,則首次調(diào)用ReferenceBean.getObject方法是在“field.set(bean, referenceBean.getObject());”。異常沒有被catch住,checkedElements列表的遍歷會(huì)被打斷。
會(huì)出現(xiàn)這樣的情況,有一個(gè)bean需要注入5個(gè)代理對(duì)象,但是調(diào)用第一個(gè)ReferenceBean.getObject的時(shí)候拋異常,則注入行為被中斷,另外4個(gè)屬性也沒有被注入。
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Spring使用ThreadPoolTaskExecutor自定義線程池及異步調(diào)用方式
這篇文章主要介紹了Spring使用ThreadPoolTaskExecutor自定義線程池及異步調(diào)用方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-02-02
詳解hibernate雙向多對(duì)多關(guān)聯(lián)映射XML與注解版
本篇文章主要介紹了詳解hibernate雙向多對(duì)多關(guān)聯(lián)映射XML與注解版,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-05-05
Java實(shí)現(xiàn)郵件發(fā)送的過程及代碼詳解
這篇文章主要介紹了Java實(shí)現(xiàn)郵件發(fā)送的過程及代碼詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-07-07
java設(shè)計(jì)模式:建造者模式之生產(chǎn)線
這篇文章主要介紹了Java設(shè)計(jì)模式之建造者模式,結(jié)合具體實(shí)例形式分析了建造者模式的概念、原理、實(shí)現(xiàn)方法與相關(guān)使用注意事項(xiàng),需要的朋友可以參考下2021-08-08
springboot?@PostConstruct無效的解決
這篇文章主要介紹了springboot?@PostConstruct無效的解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-11-11
Spring整合WebSocket應(yīng)用示例(上)
以下教程是小編在參與開發(fā)公司的一個(gè)crm系統(tǒng),整理些相關(guān)資料,在該系統(tǒng)中有很多消息推送功能,在其中用到了websocket技術(shù)。下面小編整理分享到腳本之家平臺(tái)供大家參考2016-04-04
Java雙向鏈表按照順序添加節(jié)點(diǎn)的方法實(shí)例
這篇文章主要給大家介紹了關(guān)于Java雙向鏈表按照順序添加節(jié)點(diǎn)的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-02-02
java web中圖片驗(yàn)證碼功能的簡(jiǎn)單實(shí)現(xiàn)方法
下面小編就為大家?guī)硪黄猨ava web 驗(yàn)證碼的簡(jiǎn)單實(shí)現(xiàn)方法。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2016-06-06
IntelliJ?IDEA無公網(wǎng)遠(yuǎn)程Linux服務(wù)器環(huán)境開發(fā)過程(推薦收藏)
下面介紹如何在IDEA中設(shè)置遠(yuǎn)程連接服務(wù)器開發(fā)環(huán)境并結(jié)合Cpolar內(nèi)網(wǎng)穿透工具實(shí)現(xiàn)無公網(wǎng)遠(yuǎn)程連接,然后實(shí)現(xiàn)遠(yuǎn)程Linux環(huán)境進(jìn)行開發(fā),感興趣的朋友跟隨小編一起看看吧2023-12-12

