spring 4.0 소스 코드 분석.

32953 단어 응용 개발
요즘 은 여유 가 있어 서 개원 의 틀 을 연구 하고 싶 습 니 다. NIO 를 기반 으로 한 분포 식 틀 을 연 구 했 지만 소감 을 쓸 시간 이 없 었 습 니 다.금방 잊 어 버 려 서 최근 에 연구 한 spring 오픈 소스 프레임 워 크 를 쓰 려 고 합 니 다.사실 연구 나 틀 을 읽 을 때마다 많은 이익 을 얻 을 수 있다.자신의 기술 에 대해 매우 큰 향상 이 있다.
       오늘 은 스프링 의 IOC 를 먼저 쓰 겠 습 니 다.IOC 의 개념 은 반전 을 제어 합 니 다. 저 는 spring 이 xml 설정 을 통 해 일부 속성의 실례 화 를 원래 우리 가 프로그램 에서 한 일 을 spring 의 IOC 용기 에 맡 겼 다 는 것 을 깨 달 았 습 니 다.하지만 이것 은 가장 간단 하 다. 스프링 은 우리 에 게 다른 많은 일 을 해 주 었 다.하지만 IOC 의 가장 핵심 적 인 업무 가 바로 이것 이 라 고 생각 합 니 다.
       처음에 제 가 spring 의 소스 코드 를 읽 은 것 은 다운로드 한 spring 기술 내부 pdf 자료 에 따 른 것 입 니 다.내 가 다운로드 한 것 은 spring 3.0 이 고, 이 pdf 는 2.0 이다.그리고 어 리 석 게 읽 고 모 르 는 것 을 만나면 소스 코드 와 디 버 깅 을 봅 니 다.이렇게 된 지 며칠 이 되 었 지만 아직 아무런 진전 이 없다.나중에 생각해 보 니 이렇게 연구 해 서 는 안 된다 고 생각 했 어 요.목 표를 찾 은 다음 에 목적 성 있 는 연 구 를 해 야 한다.이렇게 되면 효율 이 훨씬 높아진다.비록 내 가 이전에 연구 한 것 도 모두 문제 에 근거 하여 목적 성 있 는 연 구 였 지만 이런 것들 은 모두 좋 은 규범 이 없 었 다.그래서 집행 이 좀 복잡 합 니 다.
       오늘 은 아래 두 가지 각도 에서 세분 화 하 겠 습 니 다.
  • xml 프로필 을 어떻게 읽 는 지
  • 그 속성 을 어떻게 설정 합 니까
  •       프로필 을 읽 는 입 구 는 XmlBeanDefinitionReader 와 같 습 니 다.그 중 에 이런 방법 이 있어 요.
    protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
    			throws BeanDefinitionStoreException {
    		try {
    			int validationMode = getValidationModeForResource(resource);
    			Document doc = this.documentLoader.loadDocument(
    					inputSource, getEntityResolver(), this.errorHandler, validationMode, isNamespaceAware());
    			return registerBeanDefinitions(doc, resource);
    		}

    이 중 document Loader 는 속성 이 며 초기 화 되 어 있 습 니 다.loadDocument 방법 코드 는 다음 과 같 습 니 다.
     * Load the {@link Document} at the supplied {@link InputSource} using the standard JAXP-configured
    	 * XML parser.
    	 */
    	public Document loadDocument(InputSource inputSource, EntityResolver entityResolver,
    			ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception {
    
    		DocumentBuilderFactory factory = createDocumentBuilderFactory(validationMode, namespaceAware);
    		if (logger.isDebugEnabled()) {
    			logger.debug("Using JAXP provider [" + factory.getClass().getName() + "]");
    		}
    		DocumentBuilder builder = createDocumentBuilder(factory, entityResolver, errorHandler);
    		return builder.parse(inputSource);
    	}
    
    	/**
    	 * Create the {@link DocumentBuilderFactory} instance.
    	 * @param validationMode the type of validation: {@link XmlValidationModeDetector#VALIDATION_DTD DTD}
    	 * or {@link XmlValidationModeDetector#VALIDATION_XSD XSD})
    	 * @param namespaceAware whether the returned factory is to provide support for XML namespaces
    	 * @return the JAXP DocumentBuilderFactory
    	 * @throws ParserConfigurationException if we failed to build a proper DocumentBuilderFactory
    	 */
    	protected DocumentBuilderFactory createDocumentBuilderFactory(int validationMode, boolean namespaceAware)
    			throws ParserConfigurationException {
    
    		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
    		factory.setNamespaceAware(namespaceAware);
    
    		if (validationMode != XmlValidationModeDetector.VALIDATION_NONE) {
    			factory.setValidating(true);
    
    			if (validationMode == XmlValidationModeDetector.VALIDATION_XSD) {
    				// Enforce namespace aware for XSD...
    				factory.setNamespaceAware(true);
    				try {
    					factory.setAttribute(SCHEMA_LANGUAGE_ATTRIBUTE, XSD_SCHEMA_LANGUAGE);
    				}
    				catch (IllegalArgumentException ex) {
    					ParserConfigurationException pcex = new ParserConfigurationException(
    							"Unable to validate using XSD: Your JAXP provider [" + factory +
    							"] does not support XML Schema. Are you running on Java 1.4 with Apache Crimson? " +
    							"Upgrade to Apache Xerces (or Java 1.5) for full XSD support.");
    					pcex.initCause(ex);
    					throw pcex;
    				}
    			}
    		}
    
    		return factory;
    	}
    
    	/**
    	 * Create a JAXP DocumentBuilder that this bean definition reader
    	 * will use for parsing XML documents. Can be overridden in subclasses,
    	 * adding further initialization of the builder.
    	 * @param factory the JAXP DocumentBuilderFactory that the DocumentBuilder
    	 * should be created with
    	 * @param entityResolver the SAX EntityResolver to use
    	 * @param errorHandler the SAX ErrorHandler to use
    	 * @return the JAXP DocumentBuilder
    	 * @throws ParserConfigurationException if thrown by JAXP methods
    	 */
    	protected DocumentBuilder createDocumentBuilder(
    			DocumentBuilderFactory factory, EntityResolver entityResolver, ErrorHandler errorHandler)
    			throws ParserConfigurationException {
    
    		DocumentBuilder docBuilder = factory.newDocumentBuilder();
    		if (entityResolver != null) {
    			docBuilder.setEntityResolver(entityResolver);
    		}
    		if (errorHandler != null) {
    			docBuilder.setErrorHandler(errorHandler);
    		}
    		return docBuilder;
    	}

     
    이 를 통 해 알 수 있 듯 이 spring 해석 xml 은 dom4j 와 jdom 같은 프레임 워 크 를 사용 하지 않 고 자바 의 API 방식 을 직접 사용 합 니 다.그 중에서 DocumentBuilder Factory 를 만 들 때 vaidating 을 true 로 설정 합 니 다. 읽 을 때 xml 설정 의 정확성 을 검증 합 니 다.그 중 에는 xsd 의 모델 에 따른다.여기 에는 많은 다른 학우 들 이 이런 문 제 를 만 났 을 것 이다. 가끔 은 spring 의 프로젝트 운행 이 좋 지만 인터넷 이 끊 긴 상황 에서 오류 가 발생 했다.사실은 spring 의 검증 이 이상 한 짓 을 하고 있 습 니 다.물론 기본 적 인 상황 에서 spring 은 인터넷 에 접속 하여 검증 하지 않 을 것 입 니 다. xsd 를 그 중의 한 곳 에 두 었 을 것 입 니 다.그럼 어디 다 놓 을까요?docBuilder.setEntityResolver(entityResolver);여기 있 습 니 다.다음 entitiResolver 는 InputSource 클래스 를 되 돌려 줍 니 다.
    InputSource source = super.resolveEntity(publicId, systemId);
    		if (source == null && systemId != null) {
    			String resourcePath = null;
    			try {
    				String decodedSystemId = URLDecoder.decode(systemId);
    				String givenUrl = new URL(decodedSystemId).toString();
    				String systemRootUrl = new File("").toURL().toString();
    				// Try relative to resource base if currently in system root.
    				if (givenUrl.startsWith(systemRootUrl)) {
    					resourcePath = givenUrl.substring(systemRootUrl.length());
    				}
    			}

     souce 가 비어 있 을 때 xsd 파일 을 URL 로 읽 는 것 이 분명 합 니 다. 그 중 systemId 는 http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 입 니 다.
    http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
    http://www.springframework.org/schema/tool/spring-tool-3.0.xsd
    기다리다그래서 인터넷 이 없 으 면 방문 하지 못 하면 실수 할 것 이다.
    그 중에서 spring 의 기본 구현 은 Pluggable SchemaResolver 류 입 니 다.
    private Map<String, String> getSchemaMappings() {
    		if (this.schemaMappings == null) {
    			synchronized (this) {
    				if (this.schemaMappings == null) {
    					if (logger.isDebugEnabled()) {
    						logger.debug("Loading schema mappings from [" + this.schemaMappingsLocation + "]");
    					}
    					try {
    						Properties mappings =
    								PropertiesLoaderUtils.loadAllProperties(this.schemaMappingsLocation, this.classLoader);
    						if (logger.isDebugEnabled()) {
    							logger.debug("Loaded schema mappings: " + mappings);
    						}
    						Map<String, String> schemaMappings = new ConcurrentHashMap<String, String>();
    						CollectionUtils.mergePropertiesIntoMap(mappings, schemaMappings);
    						this.schemaMappings = schemaMappings;
    					}
    					catch (IOException ex) {
    						throw new IllegalStateException(
    								"Unable to load schema mappings from location [" + this.schemaMappingsLocation + "]", ex);
    					}
    				}
    			}
    		}
    		return this.schemaMappings;
    	}
    

     이 systemId 에 대응 하 는 xsd 위 치 를 초기 화 했 습 니 다.그 중의 DEFAULTSCHEMA_MAPPINGS_LOCATION = "META-INF/spring.schemas"。이것 은 정적 으로 변 하지 않 는 클래스 구성원 변수 입 니 다.그래서 spring 은 classpath 경로 의 모든 jar 아래 META - INF / spring. schemas 를 읽 습 니 다.그 중에서 org. springframework. beans - 3.0.5. RELEASE. jar 에서 spring. schemas 의 내용 은 다음 과 같다.
    http\://www.springframework.org/schema/beans/spring-beans-2.0.xsd=org/springframework/beans/factory/xml/spring-beans-2.0.xsd
    http\://www.springframework.org/schema/beans/spring-beans-2.5.xsd=org/springframework/beans/factory/xml/spring-beans-2.5.xsd
    http\://www.springframework.org/schema/beans/spring-beans-3.0.xsd=org/springframework/beans/factory/xml/spring-beans-3.0.xsd
    http\://www.springframework.org/schema/beans/spring-beans.xsd=org/springframework/beans/factory/xml/spring-beans-3.0.xsd
    http\://www.springframework.org/schema/tool/spring-tool-2.0.xsd=org/springframework/beans/factory/xml/spring-tool-2.0.xsd
    http\://www.springframework.org/schema/tool/spring-tool-2.5.xsd=org/springframework/beans/factory/xml/spring-tool-2.5.xsd
    http\://www.springframework.org/schema/tool/spring-tool-3.0.xsd=org/springframework/beans/factory/xml/spring-tool-3.0.xsd
    http\://www.springframework.org/schema/tool/spring-tool.xsd=org/springframework/beans/factory/xml/spring-tool-3.0.xsd
    http\://www.springframework.org/schema/util/spring-util-2.0.xsd=org/springframework/beans/factory/xml/spring-util-2.0.xsd
    http\://www.springframework.org/schema/util/spring-util-2.5.xsd=org/springframework/beans/factory/xml/spring-util-2.5.xsd
    http\://www.springframework.org/schema/util/spring-util-3.0.xsd=org/springframework/beans/factory/xml/spring-util-3.0.xsd
    http\://www.springframework.org/schema/util/spring-util.xsd=org/springframework/beans/factory/xml/spring-util-3.0.xsd
    

     
    그래서 지금 은 왜 그 잘못 이 일 어 났 는 지 이해 할 수 있다.classpath 경로 에 이 파일 들 이 없 는 지 인터넷 에서 찾 았 더 니 오류 가 발생 했 습 니 다.그 중에서 도 이것 과 유사 한 부분 이 있 습 니 다. 바로 op 입 니 다. spring 은 xml 의 네 임 스페이스 에 대해 서로 다른 유형 으로 해석 할 수 있 습 니 다.읽 은 파일 은 spring. handlers 입 니 다.
     이상 xml 의 검증 분석 입 니 다.
     
          검증 이 통과 되 었 습 니 다. xml 을 어떻게 읽 는 지 에 대한 문제 입 니 다.여 기 는 DefaultBean Definition DocumentReader 클래스 의 다음 과 같은 방법 으로 끝 납 니 다.
     * Parse the elements at the root level in the document:
    	 * "import", "alias", "bean".
    	 * @param root the DOM root element of the document
    	 */
    	protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
    		if (delegate.isDefaultNamespace(root)) {
    			NodeList nl = root.getChildNodes();
    			for (int i = 0; i < nl.getLength(); i++) {
    				Node node = nl.item(i);
    				if (node instanceof Element) {
    					Element ele = (Element) node;
    					if (delegate.isDefaultNamespace(ele)) {
    						parseDefaultElement(ele, delegate);
    					}
    					else {
    						delegate.parseCustomElement(ele);
    					}
    				}
    			}
    		}
    		else {
    			delegate.parseCustomElement(root);
    		}
    	}

     xml 에서 Element 의 네 임 스페이스 를 분석 하면 기본 값 과 다른 처리 방식 을 볼 수 있 습 니 다.기본 값 은 http://www.springframework.org/schema/beans, 즉 라벨 이 < bean > 인 Element 입 니 다.< op >, < tx > 등 이 라면 서로 다른 처리 가 될 것 입 니 다. 여기 서 언급 한 META - INF / spring. handlers 에서 프로필 정 보 를 읽 었 습 니 다.< op > 이 라면 다음 내용 http \: / www. springframework. org / schema / ap = org. springframework. aop. config. aop NamespaceHandler

    op, tx (사무) 와 같은 탭 이 라면 이 방법 에 도달 할 수 있 습 니 다. Bean Definition ParserDelegate 클래스 에서 이 중 handler 는 위 에 설정 한 파일 의 AopNamespaceHandler 입 니 다.
    public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
    		String namespaceUri = getNamespaceURI(ele);
    		NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
    		if (handler == null) {
    			error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
    			return null;
    		}
    		return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
    	}

     
          여 기 는 bean 의 읽 기 에 중점 을 두 었 습 니 다.op 은 다음 에 설명 할 때 까지 기 다 려 야 op 이 자세히 설명 할 수 있 습 니 다.책 에 프로그램 이 알고리즘 + 데이터 구조 라 는 말 이 있 는 것 같 습 니 다.
         예전 에 나 는 줄곧 알고리즘 을 맨 앞 에 놓 았 다.이것 은 약간 과정 을 향 한 것 처럼 때로는 비교적 빠 르 고 작은 프로그램 에 직면 하기 도 한다.그러나 프로그램 이 복잡 해 지면 데이터 구 조 를 먼저 보 는 것 이 오히려 쉽다.그래서 저 는 잠시 < bean > 을 연구 해 보 겠 습 니 다. 이 대응 하 는 유형의 데이터 구 조 는 다음 에 코드 를 보면 더욱 쉬 워 집 니 다. 이 클래스 의 AbstractBean Definition 에 대응 합 니 다.이 클래스 는 Default Listable BeanFactory 클래스 에 private final Map < String, Bean Definition > bean DefinitionMap = new Concurrent HashMap < String, Bean Definition > () 이 있 습 니 다.  안전 한 맵 을 스 레 드 한 다음 에 BeanFactory 류 getBean 을 통과 할 때 실제 이 맵 을 방문 하여 BeanDefinition 을 초기 화하 고 속성 을 설정 합 니 다.그래서 빈 데 피 니 션 데이터 구 조 를 이해 하 는 것 이 중요 하 다.그 데이터 구 조 는 다음 과 같다.
    /**
    	 * Constant for the default scope name: "", equivalent to singleton status
    	 * but to be overridden from a parent bean definition (if applicable).
    	 */
    	public static final String SCOPE_DEFAULT = "";
    
    
    	/**
    	 * Constant that indicates no autowiring at all.
    	 * @see #setAutowireMode
    	 */
    	public static final int AUTOWIRE_NO = AutowireCapableBeanFactory.AUTOWIRE_NO;
    
    	/**
    	 * Constant that indicates autowiring bean properties by name.
    	 * @see #setAutowireMode
    	 */
    	public static final int AUTOWIRE_BY_NAME = AutowireCapableBeanFactory.AUTOWIRE_BY_NAME;
    
    	/**
    	 * Constant that indicates autowiring bean properties by type.
    	 * @see #setAutowireMode
    	 */
    	public static final int AUTOWIRE_BY_TYPE = AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE;
    
    	/**
    	 * Constant that indicates autowiring a constructor.
    	 * @see #setAutowireMode
    	 */
    	public static final int AUTOWIRE_CONSTRUCTOR = AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR;
    
    	/**
    	 * Constant that indicates determining an appropriate autowire strategy
    	 * through introspection of the bean class.
    	 * @see #setAutowireMode
    	 * @deprecated as of Spring 3.0: If you are using mixed autowiring strategies,
    	 * use annotation-based autowiring for clearer demarcation of autowiring needs.
    	 */
    	@Deprecated
    	public static final int AUTOWIRE_AUTODETECT = AutowireCapableBeanFactory.AUTOWIRE_AUTODETECT;
    
    
    	/**
    	 * Constant that indicates no dependency check at all.
    	 * @see #setDependencyCheck
    	 */
    	public static final int DEPENDENCY_CHECK_NONE = 0;
    
    	/**
    	 * Constant that indicates dependency checking for object references.
    	 * @see #setDependencyCheck
    	 */
    	public static final int DEPENDENCY_CHECK_OBJECTS = 1;
    
    	/**
    	 * Constant that indicates dependency checking for "simple" properties.
    	 * @see #setDependencyCheck
    	 * @see org.springframework.beans.BeanUtils#isSimpleProperty
    	 */
    	public static final int DEPENDENCY_CHECK_SIMPLE = 2;
    
    	/**
    	 * Constant that indicates dependency checking for all properties
    	 * (object references as well as "simple" properties).
    	 * @see #setDependencyCheck
    	 */
    	public static final int DEPENDENCY_CHECK_ALL = 3;
    
    
    	private volatile Object beanClass;
    
    	private String scope = SCOPE_DEFAULT;
    
    	private boolean singleton = true;
    
    	private boolean prototype = false;
    
    	private boolean abstractFlag = false;
    
    	private boolean lazyInit = false;
    
    	private int autowireMode = AUTOWIRE_NO;
    
    	private int dependencyCheck = DEPENDENCY_CHECK_NONE;
    
    	private String[] dependsOn;
    
    	private boolean autowireCandidate = true;
    
    	private boolean primary = false;
    
    	private final Map<String, AutowireCandidateQualifier> qualifiers =
    			new LinkedHashMap<String, AutowireCandidateQualifier>(0);
    
    	private boolean nonPublicAccessAllowed = true;
    
    	private boolean lenientConstructorResolution = true;
    
    	private ConstructorArgumentValues constructorArgumentValues;
    
    	private MutablePropertyValues propertyValues; 
    	private MethodOverrides methodOverrides = new MethodOverrides();
    
    	private String factoryBeanName;
    
    	private String factoryMethodName;
    
    	private String initMethodName;
    
    	private String destroyMethodName;
    
    	private boolean enforceInitMethod = true;
    
    	private boolean enforceDestroyMethod = true;
    
    	private boolean synthetic = false;
    
    	private int role = BeanDefinition.ROLE_APPLICATION;
    
    	private String description;
    
    	private Resource resource;

     
    이것 을 보 니 < bean > 프로필 의 속성 이 아 닙 니까? lazy Init, autowireMode 등 이 맞습니다.그 중에서 도 가장 중요 한 것 은 빨간색 을 표시 하 는 부분 이다.그것 은 바로 그 중의 < property > 라벨 의 데이터 구조 입 니 다.Mutable Property Values 클래스 에 이러한 구성원 변수 가 있 습 니 다. private final List < Property Value > property ValueList;PropertyValue 의 데이터 구 조 는 다음 과 같다.
    private final String name;
    
    	private final Object value;
    
    	private Object source;
    
    	private boolean optional = false;
    
    	private boolean converted = false;
    
    	private Object convertedValue;
    
    	/** Package-visible field that indicates whether conversion is necessary */
    	volatile Boolean conversionNecessary;
    
    	/** Package-visible field for caching the resolved property path tokens */
    	volatile Object resolvedTokens;
    
    	/** Package-visible field for caching the resolved PropertyDescriptor */
    	volatile PropertyDescriptor resolvedDescriptor;

     이 건 프로 퍼티 스타일 같 아.그 중에서 name 은 name 입 니 다. Object 는 value 나 ref 입 니 다.왜 하나의 맵 으로 bean 의 속성 을 저장 하지 않 습 니까?공식 적 인 해석 은 Property Value 의 유연성 을 더 많이 사용 하고 색인 속성 등 을 최적화 하 는 방식 으로 처리 할 수 있다 는 것 이다.여기 Property Value 가 몇 개 더 생 겼 나 봐 요.
           xml 의 검증 읽 기와 < bean > 태그 에 대응 하 는 데이터 구 조 를 알 게 된 후 xml 를 어떻게 읽 는 지, 이 BeanDefinition 을 어떻게 생 성 하 는 지 말 하지 않 았 습 니 다.여기 서 앞의 분석 을 생략 하고 BeanDefinition 을 생 성 하 는 것 은 BeanDefinition ParserDelegate 와 같은 것 입 니 다. 사실 spring 의 클래스 이름 은 좋 습 니 다. 이 를 보면 BeanDefinition 이 해석 한 대표 라 는 것 을 알 수 있 습 니 다. 그것 은 BeanDefinition 과 막대 한 관 계 를 가 진 것 이 분명 합 니 다.사실 모든 생 성 된 BeanDefinition 은 이런 종류 에서 생 긴 것 이다.이 방법 에서
    public AbstractBeanDefinition parseBeanDefinitionElement(
    			Element ele, String beanName, BeanDefinition containingBean) {
    
    		this.parseState.push(new BeanEntry(beanName));
    
    		String className = null;
    		if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
    			className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
    		}
    
    		try {
    			String parent = null;
    			if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
    				parent = ele.getAttribute(PARENT_ATTRIBUTE);
    			}
    			AbstractBeanDefinition bd = createBeanDefinition(className, parent);
    
    			parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
    			bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
    
    			parseMetaElements(ele, bd);
    			parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
    			parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
    
    			parseConstructorArgElements(ele, bd);
    			parsePropertyElements(ele, bd);
    			parseQualifierElements(ele, bd);
    
    			bd.setResource(this.readerContext.getResource());
    			bd.setSource(extractSource(ele));
    
    			return bd;
    		}
    		catch (ClassNotFoundException ex) {
    			error("Bean class [" + className + "] not found", ele, ex);
    		}
    		catch (NoClassDefFoundError err) {
    			error("Class that bean class [" + className + "] depends on not found", ele, err);
    		}
    		catch (Throwable ex) {
    			error("Unexpected failure during bean definition parsing", ele, ex);
    		}
    		finally {
    			this.parseState.pop();
    		}
    
    		return null;
    	}

      클 라 스 의 속성 과 parent 의 속성 에 따라 AbstractBean Definition 클래스 를 만 드 는 것 을 볼 수 있 습 니 다.실제 제 네 릭 빈 데 피 니 션 을 만 들 었 고 제 네 릭 빈 데 피 니 션 류 는 Abstract빈 데 피 니 션 을 계승 했다.그 중에서 자신 만 의 parseBean Definition Attributes (ele, beanName, containingBean, bd) 를 호출 했 습 니 다.방법, 이 방법 은 이러한 bean 의 속성 을 실례 화 하 는 것 을 소개 합 니 다. 예 를 들 어 중요 한 scope, abstract, lazy - init, autowire, depends - on, init - method, factory - method 등 입 니 다.설정 이 없 으 면 기본 방식 입 니 다.더 중요 한 것 은 해석 값 이다.
    public void parsePropertyElements(Element beanEle, BeanDefinition bd) {
    		NodeList nl = beanEle.getChildNodes();
    		for (int i = 0; i < nl.getLength(); i++) {
    			Node node = nl.item(i);
    			if (isCandidateElement(node) && nodeNameEquals(node, PROPERTY_ELEMENT)) {
    				parsePropertyElement((Element) node, bd);
    			}
    		}
    	}
     값 을 분석 할 때 위의 이 방법 을 호출 합 니 다.property 라 는 탭 을 반복 해서 찾 을 수 있 습 니 다.그리고 해석
     
    /**
    	 * Parse a property element.
    	 */
    	public void parsePropertyElement(Element ele, BeanDefinition bd) {
    		String propertyName = ele.getAttribute(NAME_ATTRIBUTE);
    		if (!StringUtils.hasLength(propertyName)) {
    			error("Tag 'property' must have a 'name' attribute", ele);
    			return;
    		}
    		this.parseState.push(new PropertyEntry(propertyName));
    		try {
    			if (bd.getPropertyValues().contains(propertyName)) {
    				error("Multiple 'property' definitions for property '" + propertyName + "'", ele);
    				return;
    			}
    			Object val = parsePropertyValue(ele, bd, propertyName);
    			PropertyValue pv = new PropertyValue(propertyName, val);
    			parseMetaElements(ele, pv);
    			pv.setSource(extractSource(ele));
    			bd.getPropertyValues().addPropertyValue(pv);
    		}
    		finally {
    			this.parseState.pop();
    		}
    	}
     그 중에서 하나의 속성 이 있 고 있 는 것 을 발견 하면 바로 돌아 오기 때문에 하나의 bean 이 두 개의 name 을 p1 로 설정 하면 첫 번 째 역할 을 합 니 다.그 중에서 Object val = parsePropertyValue (ele, bd, propertyName);또한 이 종류의 여러 가지 방법 으로 호출 됩 니 다. property 태그 에 value 가 직접 있 으 면 가장 간단 한 방법 입 니 다. 그렇지 않 으 면 하위 태그, list, set, map 등 이 있 을 수 있 습 니 다.독자 들 은 Bean Definition ParseDelege 류 의 상응하는 방법 을 스스로 볼 수 있다.위 에 서 는 value 를 얻 은 후 Property Value 류 를 만 드 는 것 도 볼 수 있다.그리고 AbstractBean Definition 류 getProperty Values (). addProperty Value (pv) 를 통 해 여기까지 모두 해석 되 었 습 니 다.
    public Object parsePropertySubElement(Element ele, BeanDefinition bd, String defaultValueType) {
    		if (!isDefaultNamespace(ele)) {
    			return parseNestedCustomElement(ele, bd);
    		}
    		else if (nodeNameEquals(ele, BEAN_ELEMENT)) {
    			BeanDefinitionHolder nestedBd = parseBeanDefinitionElement(ele, bd);
    			if (nestedBd != null) {
    				nestedBd = decorateBeanDefinitionIfRequired(ele, nestedBd, bd);
    			}
    			return nestedBd;
    		}
    		else if (nodeNameEquals(ele, REF_ELEMENT)) {
    			// A generic reference to any name of any bean.
    			String refName = ele.getAttribute(BEAN_REF_ATTRIBUTE);
    			boolean toParent = false;
    			if (!StringUtils.hasLength(refName)) {
    				// A reference to the id of another bean in the same XML file.
    				refName = ele.getAttribute(LOCAL_REF_ATTRIBUTE);
    				if (!StringUtils.hasLength(refName)) {
    					// A reference to the id of another bean in a parent context.
    					refName = ele.getAttribute(PARENT_REF_ATTRIBUTE);
    					toParent = true;
    					if (!StringUtils.hasLength(refName)) {
    						error("'bean', 'local' or 'parent' is required for <ref> element", ele);
    						return null;
    					}
    				}
    			}
    			if (!StringUtils.hasText(refName)) {
    				error("<ref> element contains empty target attribute", ele);
    				return null;
    			}
    			RuntimeBeanReference ref = new RuntimeBeanReference(refName, toParent);
    			ref.setSource(extractSource(ele));
    			return ref;
    		}
    		else if (nodeNameEquals(ele, IDREF_ELEMENT)) {
    			return parseIdRefElement(ele);
    		}
    		else if (nodeNameEquals(ele, VALUE_ELEMENT)) {
    			return parseValueElement(ele, defaultValueType);
    		}
    		else if (nodeNameEquals(ele, NULL_ELEMENT)) {
    			// It's a distinguished null value. Let's wrap it in a TypedStringValue
    			// object in order to preserve the source location.
    			TypedStringValue nullHolder = new TypedStringValue(null);
    			nullHolder.setSource(extractSource(ele));
    			return nullHolder;
    		}
    		else if (nodeNameEquals(ele, ARRAY_ELEMENT)) {
    			return parseArrayElement(ele, bd);
    		}
    		else if (nodeNameEquals(ele, LIST_ELEMENT)) {
    			return parseListElement(ele, bd);
    		}
    		else if (nodeNameEquals(ele, SET_ELEMENT)) {
    			return parseSetElement(ele, bd);
    		}
    		else if (nodeNameEquals(ele, MAP_ELEMENT)) {
    			return parseMapElement(ele, bd);
    		}
    		else if (nodeNameEquals(ele, PROPS_ELEMENT)) {
    			return parsePropsElement(ele);
    		}
    		else {
    			error("Unknown property sub-element: [" + ele.getNodeName() + "]", ele);
    			return null;
    		}
    	}
    여기까지 Bean Definition 은 xml 를 분석 하여 생 성 되 었 습 니 다. Default Listable Bean Factory 류 에 어떻게 넣 었 습 니까?앞에서 도 말 했 듯 이 빈 데 피 니 션 은 결국 이 클래스 의 맵 대상 에 놓 인 다.
     /** Map of bean definition objects, keyed by bean name */
     private final Map beanDefinitionMap = new ConcurrentHashMap();
     
    이 방법 은 매우 중요 합 니 다. 어떻게 XmlBeanDefinitionReader 를 통 해 xml 를 분석 하고 최종 적 으로 BeanDefinitionParserDelegate 에 가서 bean 라벨 을 분석 합 니까?그 중의 방식 은
    XmlBeanDefinitionReader---DefaultBeanDefinitionDocumentReader--BeanDefinitionParserDelegate。
    /**
    	 * Process the given bean element, parsing the bean definition
    	 * and registering it with the registry.
    	 */
    	protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
    		BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
    		if (bdHolder != null) {
    			bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
    			try {
    				// Register the final decorated instance.
    				BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
    			}
    			catch (BeanDefinitionStoreException ex) {
    				getReaderContext().error("Failed to register bean definition with name '" +
    						bdHolder.getBeanName() + "'", ele, ex);
    			}
    			// Send registration event.
    			getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
    		}
    	}
     
    그 중에서 DefaultBeanDefinitionDocumentReader 에서 bean 라벨 을 분석 할 때 위의 방법 을 호출 합 니 다. BeanDefinitionParserDelegate 분석 을 통 해 생 성 된 것 은 BeanDefinitionHolder 입 니 다. 실제로 세 가지 속성 이 있 습 니 다.
    private final BeanDefinition beanDefinition;
    
    	private final String beanName;
    
    	private final String[] aliases;
     
     
    그리고 Bean Definition ReaderUtils 에서
    	public static void registerBeanDefinition(
    			BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
    			throws BeanDefinitionStoreException {
    
    		// Register bean definition under primary name.
    		String beanName = definitionHolder.getBeanName();
    		registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
    
    		// Register aliases for bean name, if any.
    		String[] aliases = definitionHolder.getAliases();
    		if (aliases != null) {
    			for (String aliase : aliases) {
    				registry.registerAlias(beanName, aliase);
    			}
    		}
    	}
    
     
    그 중의 registry 는 바로 Default Listable Bean Factory 류 입 니 다. 그 는 Bean Definition Registry 를 실현 하여 이 인 터 페 이 스 를 만 들 었 습 니 다.이 인터페이스의 내용 은 아래 이다.registry 는 XmlReader Context 와 같은 종 류 를 통 해 얻 을 수 있 습 니 다.XmlReader Context 는 이름 에서 xml 을 읽 는 컨 텍스트 로 설명 합 니 다.XmlBean DefinitionReader 클래스 와 NamespaceHandler Resolver 클래스 를 포함 하 는 상하 의 역할 을 합 니 다.이 NamespaceHandler Resolver 는 태그 가 기본 이름 공간 이 아 닐 때 유용 합 니 다.
    public interface BeanDefinitionRegistry extends AliasRegistry {
    
    	/**
    	 * Register a new bean definition with this registry.
    	 * Must support RootBeanDefinition and ChildBeanDefinition.
    	 * @param beanName the name of the bean instance to register
    	 * @param beanDefinition definition of the bean instance to register
    	 * @throws BeanDefinitionStoreException if the BeanDefinition is invalid
    	 * or if there is already a BeanDefinition for the specified bean name
    	 * (and we are not allowed to override it)
    	 * @see RootBeanDefinition
    	 * @see ChildBeanDefinition
    	 */
    	void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
    			throws BeanDefinitionStoreException;
    
    	/**
    	 * Remove the BeanDefinition for the given name.
    	 * @param beanName the name of the bean instance to register
    	 * @throws NoSuchBeanDefinitionException if there is no such bean definition
    	 */
    	void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
    
    	/**
    	 * Return the BeanDefinition for the given bean name.
    	 * @param beanName name of the bean to find a definition for
    	 * @return the BeanDefinition for the given name (never <code>null</code>)
    	 * @throws NoSuchBeanDefinitionException if there is no such bean definition
    	 */
    	BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
    
    	/**
    	 * Check if this registry contains a bean definition with the given name.
    	 * @param beanName the name of the bean to look for
    	 * @return if this registry contains a bean definition with the given name
    	 */
    	boolean containsBeanDefinition(String beanName);
    
    	/**
    	 * Return the names of all beans defined in this registry.
    	 * @return the names of all beans defined in this registry,
    	 * or an empty array if none defined
    	 */
    	String[] getBeanDefinitionNames();
    
    	/**
    	 * Return the number of beans defined in the registry.
    	 * @return the number of beans defined in the registry
    	 */
    	int getBeanDefinitionCount();
    
    	/**
    	 * Determine whether the given bean name is already in use within this registry,
    	 * i.e. whether there is a local bean or alias registered under this name.
    	 * @param beanName the name to check
    	 * @return whether the given bean name is already in use
    	 */
    	boolean isBeanNameInUse(String beanName);
    
    }
     
     
             이렇게 많아그래도 알 겠 어.관리 가 좀 어 지 러 웠 나 봐 요.여 기 는 다른 방식 으로사실 이런 방식 으로 spring 을 사용 할 수 있 습 니 다. 틀 리 지 않 습 니 다.이렇게 사용 하면 이해 하기 가 더욱 좋 을 것 이다.XmlBean DefinitionReader 를 만 들 때 Default Listable Bean Factory 를 가지 고 들 어 가 는 것 을 발 견 했 기 때문에 이 reader 는 항상 가지 고 다 니 는 IOC 용기 로 xml 를 분석 하면 bean 하 나 를 쉽게 해석 하고 용기 에 bean 을 넣 을 수 있 습 니 다.독자 들 은 아래 의 이 한 걸음 한 걸음 봄 을 보면 훨씬 간단명료 해 질 것 이다.
    @org.junit.Test
    	public void testWebXmlFactory(){
    		IBankSecurityDao dao ;
    		Resource resource = new ClassPathResource("beanFactory.xml");
    		DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
    		XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
    		reader.loadBeanDefinitions(resource);
    		dao =(BankSecurityDaoImpl) factory.getBean("Dao");
    		dao.add("a");
    	}
     

    좋은 웹페이지 즐겨찾기