springboot bean 순환 의존 실현 및 소스 코드 분석
20220 단어 springbootbean순환 의존
본 고 는 springboot 버 전 2.5.1 을 바탕 으로 한다.
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.1</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
본 고 는 주로 순환 의존 부분 에 초점 을 맞 추고 주로 하나의 bean 으로 설명 하 며 다른 bean 이 실현 하 는 절 차 는 많이 언급 되 지 않 습 니 다.1.순환 의존 이란 무엇 인가
쉽게 말 하면 springboot 용기 에 있 는 여러 개의 bean 이다.예 를 들 어 A,B 두 개의 bean,A 는 속성 B 가 주입 해 야 하고 B 는 속성 A 가 주입 해 야 하 며 서로 의존 하 는 상황 을 형성한다.
코드 를 보 세 요.바로 아래 와 같은 상황 입 니 다.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class ServiceA {
@Autowired
private ServiceB serviceB;
}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class ServiceB {
@Autowired
private ServiceA serviceA;
}
위 에는 두 개의 bean 이 있 는데 각각 ServiceA,ServiceB 이다.ServiceA 에 ServiceB 의 인 스 턴 스 를 주입 해 야 한다.ServiceB 에 ServiceA 의 인 스 턴 스 를 주입 해 야 한다.이것 은 전형 적 인 순환 의존 이 고 다른 방법 으로 매개 변수 순환 의존 장면 등 이 있 지만 그들의 내부 실현 은 대체적으로 같다.2.순환 의존 코드 논리 가 구체 적 으로 나타난다.
bean 가 져 오 는 방법
springboot 에서 기본 beanFactory 는 Default Listable BeanFactory 입 니 다.bean 대상 을 가 져 올 때 bean 대상 이 존재 하면 바로 돌아 갑 니 다.존재 하지 않 으 면 bean 대상 을 만 들 고 돌아 갑 니 다.
우리 가 bean 을 얻 는 데 자주 사용 하 는 방법 이 어떤 것들 이 있 는 지 먼저 봅 시다.
public <T> T getBean(Class<T> requiredType) throws BeansException
public Object getBean(String name) throws BeansException
public <T> Map<String, T> getBeansOfType(@Nullable Class<T> type) throws BeansException
public Map<String, Object> getBeansWithAnnotation(Class<? extends Annotation> annotationType)
public void preInstantiateSingletons() throws BeansException
자주 사용 하 는 bean 을 가 져 오 는 방법 은 위 에 있 는 몇 가지 와 그들의 리 셋 버 전이 있 는데,세 번 째 줄,네 번 째 줄,다섯 번 째 줄 에 대해 서 는 최종 적 으로 두 번 째 줄 로 호출 되 는 방법 으로 bean 을 가 져 옵 니 다.doGetBean(AbstractBean Factory 클래스 에서)을 호출 하여 bean 을 가 져 옵 니 다.
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}
첫 번 째 줄 의 방법 도 doGetBean 을 호출 하여 bean 을 가 져 옵 니 다.
public <T> T getBean(String name, @Nullable Class<T> requiredType, @Nullable Object... args)
throws BeansException {
return doGetBean(name, requiredType, args, false);
}
모든 최종 적 으로 bean 을 얻 는 방법 은
protected <T> T doGetBean(
String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
throws BeansException {
이 방법 은 protected 이 고 대외 적 으로 제공 되 지 않 습 니 다.그래서 우 리 는 그것 을 직접 호출 할 수 없고 위 에서 제공 한 5 가지 방법 으로 bean 대상 을 얻 을 수 있 습 니 다.다음은 doGetBean 에서 serviceA 생 성 과정 을 살 펴 보 겠 습 니 다.
protected <T> T doGetBean(
String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
throws BeansException {
// bean , shareInstance , if , bean , bean
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
......
// , bean, false, bean , beanName alreadyCreated
if (!typeCheckOnly) {
markBeanAsCreated(beanName);
}
// bean , ,
// Create bean instance.
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
});
beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
}
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(beanName, "Bean name must not be null");
synchronized (this.singletonObjects) {
......
// bean singletonsCurrentlyInCreation
beforeSingletonCreation(beanName);
......
try {
// return createBean(beanName, mbd, args); ,
singletonObject = singletonFactory.getObject();
newSingleton = true;
}
......
}
return singletonObject;
}
}
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
......
// Make sure bean class is actually resolved at this point, and
// clone the bean definition in case of a dynamically resolved Class
// which cannot be stored in the shared merged bean definition.
// bean class
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
......
try {
// ,
//3
//1、beanName bean
//2、mbdToUseRootBeanDefinition , bean , bean ,bean ,bean
//3、args bean ,
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
if (logger.isTraceEnabled()) {
logger.trace("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}
......
}
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
......
// bean , instanceWrapper bean BeanWrapper
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
// bean bean
Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
......
// Eagerly cache singletons to be able to resolve circular references
// even when triggered by lifecycle interfaces like BeanFactoryAware.
// , , BeanFactoryAware
//mbd.isSingleton() bean ( bean , ),
//this.allowCircularReferences , beanFactory , true
//isSingletonCurrentlyInCreation(beanName) bean 。beforeSingletonCreation(beanName); bean
// earlySingletonExposure true , if
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isTraceEnabled()) {
logger.trace("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
// () -> getEarlyBeanReference(beanName, mbd, bean) lambda this.singletonFactories
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
// Initialize the bean instance.
Object exposedObject = bean;
try {
// , , serviceA bean serviceB ,
populateBean(beanName, mbd, instanceWrapper);
......
}
......
return exposedObject;
}
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
......
if (hasInstAwareBpps) {
if (pvs == null) {
pvs = mbd.getPropertyValues();
}
// ,aop 。 beanFactory InstantiationAwareBeanPostProcessor bean
// @Resource, CommonAnnotationBeanPostProcessor
// @Autowired, AutowiredAnnotationBeanPostProcessor
// AOP InfrastructureAdvisorAutoProxyCreator
// @Autowired, AutowiredAnnotationBeanPostProcessor 。 postProcessProperties
for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
PropertyValues pvsToUse = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
......
}
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
// bean org.springframework.beans.factory.annotation.Autowired,org.springframework.beans.factory.annotation.Value
InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
try {
//
metadata.inject(bean, beanName, pvs);
}
......
}
public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
......
// ,
element.inject(target, beanName, pvs);
}
}
}
@Override
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
Field field = (Field) this.member;
Object value;
// , , ,
if (this.cached) {
try {
value = resolvedCachedArgument(beanName, this.cachedFieldValue);
}
catch (NoSuchBeanDefinitionException ex) {
// Unexpected removal of target bean for cached argument -> re-resolve
value = resolveFieldValue(field, bean, beanName);
}
}
else {
// ,
value = resolveFieldValue(field, bean, beanName);
}
if (value != null) {
ReflectionUtils.makeAccessible(field);
field.set(bean, value);
}
}
@Nullable
private Object resolveFieldValue(Field field, Object bean, @Nullable String beanName) {
// DependencyDescriptor
DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
try {
// ,
value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
}
catch (BeansException ex) {
throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
}
synchronized (this) {
// ,
if (!this.cached) {
......
}
this.cachedFieldValue = cachedFieldValue;
this.cached = true;
}
}
return value;
}
}
public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());
if (Optional.class == descriptor.getDependencyType()) {
return createOptionalDependency(descriptor, requestingBeanName);
}
else if (ObjectFactory.class == descriptor.getDependencyType() ||
ObjectProvider.class == descriptor.getDependencyType()) {
return new DependencyObjectProvider(descriptor, requestingBeanName);
}
else if (javaxInjectProviderClass == descriptor.getDependencyType()) {
return new Jsr330Factory().createDependencyProvider(descriptor, requestingBeanName);
}
else {
// class, , bean Lazy , null, if
Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
descriptor, requestingBeanName);
if (result == null) {
// 。
//descriptor 。
//requestingBeanName bean serviceA,
//autowiredBeanNames bean , serviceB
//typeConverter ,
result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
}
return result;
}
}
@Nullable
public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
......
if (instanceCandidate instanceof Class) {
// , DependencyDescriptor resolveCandidate
// : autowiredBeanName serviceB
instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
}
......
}
public Object resolveCandidate(String beanName, Class<?> requiredType, BeanFactory beanFactory)
throws BeansException {
// , , beanFactory.getBean("serviceB") serviceB bean , serivceA Bean , , serviceB , serviceB serviceA 。
// beanFactory.getBean("serviceA")
return beanFactory.getBean(beanName);
}
바로 아래 그림 의 모습 입 니 다.3.순환 의존 을 해결 하 는 코드 구현
이어서 위의 beanFactory.getBean("serviceA")코드 를 계속 내 려 다 보 겠 습 니 다.
이번 에는 또 여기까지 올 거 예요.
protected <T> T doGetBean(
String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
throws BeansException {
// , ,
String beanName = transformedBeanName(name);
Object beanInstance;
// Eagerly check singleton cache for manually registered singletons.
// ,sharedInstance serviceA bean , if , if else ,
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
if (logger.isTraceEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
}
else {
logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
}
}
beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
@Nullable
public Object getSingleton(String beanName) {
//
return getSingleton(beanName, true);
}
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// Quick check for existing instance without full singleton lock
Object singletonObject = this.singletonObjects.get(beanName);
// serviceA bean , singletonObject ,
// isSingletonCurrentlyInCreation(beanName) , serviceA beforeSingletonCreation(beanName)( , ), true。 if
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
singletonObject = this.earlySingletonObjects.get(beanName);
// , this.earlySingletonObjects.get(beanName) null
// allowEarlyReference true, if
if (singletonObject == null && allowEarlyReference) {
synchronized (this.singletonObjects) {
// Consistent creation of early reference within full singleton lock
singletonObject = this.singletonObjects.get(beanName);
// singletonObject null, if
if (singletonObject == null) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null) {
// , serviceA , , addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean))( , ), singletonFactory lamdba ,getEarlyBeanReference(beanName, mbd, bean)) 3 , beanName serivceA,mdb serviceA serviceA RootBeanDefinition ,bean serviceA
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
// getEarlyBeanReference(beanName, mbd, bean) serviceA getEarlyBeanReference , earlySingletonObjects , singletonFactories
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects , .put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
}
}
return singletonObject;
}
마지막 으로 serviceA 라 는 bean 생 성 이 완료 되면 singletonsCurrently InCreation 에서 제거 합 니 다.
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
......
finally {
// singletonsCurrentlyInCreation
afterSingletonCreation(beanName);
}
if (newSingleton) {
// serviceA bean singletonObjects,registeredSingletons
// singletonFactories,earlySingletonObjects
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}
그래서 전체 serviceA 를 가 져 오 는 절차 가 이 렇 습 니 다.1、우선 serviceA 라 는 bean 을 만 들 고,
springboot bean 순환 의존 실현 및 소스 코드 분석 에 관 한 이 글 은 여기까지 소개 되 었 습 니 다.더 많은 springboot bean 순환 의존 내용 은 우리 의 이전 글 을 검색 하거나 아래 의 관련 글 을 계속 조회 하 시기 바 랍 니 다.앞으로 많은 응원 바 랍 니 다!
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Kotlin Springboot -- 파트 14 사용 사례 REST로 전환하여 POST로 JSON으로 전환前回 前回 前回 記事 の は は で で で で で で を 使っ 使っ 使っ て て て て て リクエスト を を 受け取り 、 reqeustbody で 、 その リクエスト の ボディ ボディ を を 受け取り 、 関数 内部 ...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.