Spring 물방울 뚫 기(5)공장 실현 사례 등록 Default Singleton Bean Registry
이 클 라 스 는 비교적 관건 적 인 유형 으로 공장 계승 을 완성 한 최고급 클 라 스 이기 도 하 다.주로 별명 등록 인터페이스 와 단일 등록 인 터 페 이 스 를 실현 하여 이러한 서 비 스 를 제공 하 는 것 이다.
속성
// 100
private static final int SUPPRESSED_EXCEPTIONS_LIMIT = 100;
// , beanName bean
private final Map singletonObjects = new ConcurrentHashMap<>(256);
// , beanName
private final Map> singletonFactories = new HashMap<>(16);
// , beanName bean
private final Map earlySingletonObjects = new HashMap<>(16);
//
private final Set registeredSingletons = new LinkedHashSet<>(256);
//
private final Set singletonsCurrentlyInCreation =
Collections.newSetFromMap(new ConcurrentHashMap<>(16));
// bean
private final Set inCreationCheckExclusions =
Collections.newSetFromMap(new ConcurrentHashMap<>(16));
//
@Nullable
private Set suppressedExceptions;
//
private boolean singletonsCurrentlyInDestruction = false;
// bean
private final Map disposableBeans = new LinkedHashMap<>();
//bean bean map
private final Map> containedBeanMap = new ConcurrentHashMap<>(16);
//bean bean map
private final Map> dependentBeanMap = new ConcurrentHashMap<>(64);
//bean bean map,
private final Map> dependenciesForBeanMap = new ConcurrentHashMap<>(64);
방법.
registerSingleton
public void registerSingleton(String beanName, Object singletonObject) throws IllegalStateException {
synchronized (this.singletonObjects) {
Object oldObject = this.singletonObjects.get(beanName);
if (oldObject != null) {
throw new IllegalStateException("Could not register object [" + singletonObject +
"] under bean name '" + beanName + "': there is already object [" + oldObject + "] bound");
}
addSingleton(beanName, singletonObject);
}
}
다음은 진정 으로 일 을 하 는 방법 입 니 다.1 급 캐 시 에 데 이 터 를 추가 하고 다른 캐 시 는 모두 삭제 합 니 다.
protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
this.singletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
여 기 는 왜 두 개의 synchronized 키 워드 를 사용 해 야 합 니까?가장 바깥쪽 은 남 겨 두 면 되 지 않 겠 습 니까?
getSingleton
하나의 예 를 되 돌려 줍 니 다.여기 서 하나의 매개 변 수 를 미리 노출 시 킬 수 있 는 지 주의 하 십시오.그러나 완성 되 지 않 은 bean 을 초기 화 합 니 다.이렇게 디자인 하 는 것 은 순환 인용 문 제 를 해결 하기 위해 서 입 니 다.이 문 제 는 매우 간단 합 니 다.바로 beanA 는 beanB 에 의존 하고 beanB 는 beanA 에 의존 합 니 다.만약 에 모든 것 이 다른 bean 이 완성 되 기 를 기다 리 면 순환 에 빠 집 니 다.이 방법 은 인터페이스 에서 의 정 의 를 실현 하 였 으 며,주의해 야 할 것 은 동명 의 리 셋 방법 이 있 는데,직접 인 터 페 이 스 를 실현 하 는 것 이 아니다.
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
ObjectFactory> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
동명 중재 방법
이 방법 은 인용 을 미리 노출 시 키 지 않 았 습 니 다.주로 해당 사례 를 찾 지 못 한 상태 에서 하나의 예 를 만 들 고 캐 시 에 넣 는 것 입 니 다.
public Object getSingleton(String beanName, ObjectFactory> singletonFactory) {
synchronized (this.singletonObjects) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
if (this.singletonsCurrentlyInDestruction) {
throw new BeanCreationNotAllowedException}
//
beforeSingletonCreation(beanName);
boolean newSingleton = false;
try {
singletonObject = singletonFactory.getObject();
newSingleton = true;
}
catch (IllegalStateException ex) {
// Has the singleton object implicitly appeared in the meantime ->
// if yes, proceed with it since the exception indicates that state.
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
throw ex;
}
}
catch (BeanCreationException ex) {
throw ex;
}
finally {
//
afterSingletonCreation(beanName);
}
if (newSingleton) {
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}
주의해 야 할 것 은 생 성 전 검 측 과 생 성 후 검 측 이 있 습 니 다.
protected void beforeSingletonCreation(String beanName) {
// beanName, ,
if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
}
protected void afterSingletonCreation(String beanName) {
// beanName, ,
if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) {
throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation");
}
}
removeSingleton
더 이상 할 말 이 없습니다.관련 캐 시 에서 모두 제거 합 니 다.
protected void removeSingleton(String beanName) {
synchronized (this.singletonObjects) {
this.singletonObjects.remove(beanName);
this.singletonFactories.remove(beanName);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.remove(beanName);
}
}
isDependent
이 곳 의 already Seen 은 이미 찾 은 beanName 을 기록 하 는 데 사 용 됩 니 다.bean 간 의 의존 관 계 를 판단 하려 면 이 bean 의 직접적인 의존 도 를 볼 뿐만 아니 라 이 bean 의 의존 도 를 찾 아야 하기 때문에 재 귀적 이 필요 합 니 다.재 귀 할 때 어떤 beanName 이 검증 되 었 을 때 건 너 뜁 니 다.그래서 이 already Seen 이 검 증 된 bean 을 기록 해 야 합 니 다 Name
private boolean isDependent(String beanName, String dependentBeanName, @Nullable Set alreadySeen) {
// ?
if (alreadySeen != null && alreadySeen.contains(beanName)) {
return false;
}
//
String canonicalName = canonicalName(beanName);
Set dependentBeans = this.dependentBeanMap.get(canonicalName);
if (dependentBeans == null) {
return false;
}
if (dependentBeans.contains(dependentBeanName)) {
return true;
}
for (String transitiveDependency : dependentBeans) {
if (alreadySeen == null) {
alreadySeen = new HashSet<>();
}
alreadySeen.add(beanName);
if (isDependent(transitiveDependency, dependentBeanName, alreadySeen)) {
return true;
}
}
return false;
}
destroyBean
protected void destroyBean(String beanName, @Nullable DisposableBean bean) {
// Trigger destruction of dependent beans first...
Set dependencies;
synchronized (this.dependentBeanMap) {
// Within full synchronization in order to guarantee a disconnected Set
dependencies = this.dependentBeanMap.remove(beanName);
}
if (dependencies != null) {
if (logger.isTraceEnabled()) {
logger.trace("Retrieved dependent beans for bean '" + beanName + "': " + dependencies);
}
for (String dependentBeanName : dependencies) {
destroySingleton(dependentBeanName);
}
}
// Actually destroy the bean now...
if (bean != null) {
try {
bean.destroy();
}
catch (Throwable ex) {
if (logger.isWarnEnabled()) {
logger.warn("Destruction of bean with name '" + beanName + "' threw an exception", ex);
}
}
}
// Trigger destruction of contained beans...
Set containedBeans;
synchronized (this.containedBeanMap) {
// Within full synchronization in order to guarantee a disconnected Set
containedBeans = this.containedBeanMap.remove(beanName);
}
if (containedBeans != null) {
for (String containedBeanName : containedBeans) {
destroySingleton(containedBeanName);
}
}
// Remove destroyed bean from other beans' dependencies.
synchronized (this.dependentBeanMap) {
for (Iterator>> it = this.dependentBeanMap.entrySet().iterator(); it.hasNext();) {
Map.Entry> entry = it.next();
Set dependenciesToClean = entry.getValue();
dependenciesToClean.remove(beanName);
if (dependenciesToClean.isEmpty()) {
it.remove();
}
}
}
// Remove destroyed bean's prepared dependency information.
this.dependenciesForBeanMap.remove(beanName);
}
폐기 절차
1.의존 표 에서 현재 bean 을 삭제 합 니 다.의존 표 는 대상 과 의존 대상 의 관계 표 입 니 다.
2.bean 이 의존 하 는 대상 을 옮 겨 다 니 며 하나씩 소각 방법 을 호출 합 니 다.
3.소각 가능 대상 이 라면 그 대상 의 소각 방법 을 사용한다.
4.bean 의 내부 bean 대상 을 옮 겨 다 니 며 각각 폐기 방법 을 호출 합 니 다.
5.전체 의존 표를 교체 합 니 다.왜 요?의존 표 에서 현재 bean 에 의존 한 대상 을 찾 아야 하기 때문에 의존 대상 집합 에서 이 bean 을 삭제 하여 현재 bean 의 캐 시 청 소 를 완성 합 니 다.
6.의존 표 에서 현재 bean 을 제거 합 니 다.옮 겨 다 닐 필요 가 없습니다!이 맵 은 원래 bean 과 그 에 의존 하 는 대상 을 유지 하 는 관계 표 이기 때 문 입 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Is Eclipse IDE dying?In 2014 the Eclipse IDE is the leading development environment for Java with a market share of approximately 65%. but ac...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.