Spring 물방울 뚫 기(5)공장 실현 사례 등록 Default Singleton Bean Registry

11231 단어 자바spring
개술
이 클 라 스 는 비교적 관건 적 인 유형 으로 공장 계승 을 완성 한 최고급 클 라 스 이기 도 하 다.주로 별명 등록 인터페이스 와 단일 등록 인 터 페 이 스 를 실현 하여 이러한 서 비 스 를 제공 하 는 것 이다.
속성
    //      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 과 그 에 의존 하 는 대상 을 유지 하 는 관계 표 이기 때 문 입 니 다.

좋은 웹페이지 즐겨찾기