봄 5.x를 소스 여행 여덟 네의 getBean 상세한

인스턴스화하는 instantiateUsingFactoryMethod 팩토리 메소드

마지막으로 말하는 프로 바이더 인스턴스는, 기사가, 이번에는 같은의 인스턴스를, 나중에 팩토리 메소드를 계속 말을 bean주석도 고려된다.
생성자는 먼저 파서를 확보하고 팩토리 메소드를 인스턴스화해야합니다.

	protected BeanWrapper instantiateUsingFactoryMethod(
			String beanName, RootBeanDefinition mbd, @Nullable Object[] explicitArgs) {

		return new ConstructorResolver(this).instantiateUsingFactoryMethod(beanName, mbd, explicitArgs);
	}

ConstructorResolver

논리를 결여 어느 주로 저장합니다 beanFactory.

	public ConstructorResolver(AbstractAutowireCapableBeanFactory beanFactory) {
		this.beanFactory = beanFactory;
		this.logger = beanFactory.getLogger();
	}

세그먼트 1 - instantiateUsingFactoryMethod 방법은 현실을 만들 수 있습니다

고유의 경우이 방법은 매우 핵심입니다, 그가 기반으로합니다 공장을 만들 수있는 유일한 방법은 아닙니다, 우리는 간단한 경우에 대해 이야기, 재 처리, 직접,뿐만 아니라 단어를 만들뿐만 아니라 모든 방법을 얻을 수 있도록하고 공장 방법을 선택 그것. 내가 실제로 래퍼 클래스, 첫 번째 인스턴스 휴대용 장치를 만들고, 첫 번째 단락을 이야기하고하자에서 RootBeanDefinition의 인수 factoryBeanName, 또한 공장 방법 같은 bean주석 방법은 다음 심판이 자신의 만들 수없는 경우, 오류가 존재 얻을 것입니다, 자신의 동등한 무한 루프를 생성하는 생성됩니다. 그렇지 않다면, 당신은 얻을 factoryBean즉 비 정적을 설정 식물의 종류, 취득, 공장 인스턴스입니다. 당신은 팩토리 인스턴스보다 덜받을 경우, 그 정적 방법이다.

		BeanWrapperImpl bw = new BeanWrapperImpl();//实例持有器
		this.beanFactory.initBeanWrapper(bw);

		Object factoryBean;//工厂实例
		Class<?> factoryClass;//工厂类型
		boolean isStatic;//是否是静态的,存在factoryBeanName表示是实例工厂,非静态方法,否则是静态的
		//factoryBeanName,也就是工厂方法所属的类的简单名字,比如配置类,这里的factoryBean,不是FactoryBean接口
		String factoryBeanName = mbd.getFactoryBeanName();
		if (factoryBeanName != null) {//存在factoryBean
			if (factoryBeanName.equals(beanName)) {//factoryBean创建出来的是工厂自身,会报异常,这样貌似等于无限递归创建了
				throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName,
						"factory-bean reference points back to the same bean definition");
			}
			factoryBean = this.beanFactory.getBean(factoryBeanName);//获得factoryBean
			if (mbd.isSingleton() && this.beanFactory.containsSingleton(beanName)) {//已经创建了
				throw new ImplicitlyAppearedSingletonException();
			}
			factoryClass = factoryBean.getClass();
			isStatic = false;//非静态的
		}
		else {//静态的方法,无factoryBean实例
			// It's a static factory method on the bean class.
			if (!mbd.hasBeanClass()) {
				throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName,
						"bean definition declares neither a bean class nor a factory-bean reference");
			}
			factoryBean = null;
			factoryClass = mbd.getBeanClass();
			isStatic = true;
		}

방법은 정말 만들어 instantiateUsingFactoryMethod - 호 2

준비 인수, 데이터가 처음으로 비어있는, 해석이 좀하려고.

Method factoryMethodToUse = null;//准备使用的工厂方法
		ArgumentsHolder argsHolderToUse = null;//准备使用的参数包装器
		Object[] argsToUse = null;//准备使用的参数

		if (explicitArgs != null) {
			argsToUse = explicitArgs;//如果有显示参数就使用这些参数
		}
		else {
			Object[] argsToResolve = null;//解析出的参数
			synchronized (mbd.constructorArgumentLock) {
				factoryMethodToUse = (Method) mbd.resolvedConstructorOrFactoryMethod;
				if (factoryMethodToUse != null && mbd.constructorArgumentsResolved) {//如果有工厂方法,且构造函数已经解析了
					// Found a cached factory method...
					argsToUse = mbd.resolvedConstructorArguments;
					if (argsToUse == null) {
						argsToResolve = mbd.preparedConstructorArguments;
					}
				}
			}
			if (argsToResolve != null) {
				argsToUse = resolvePreparedArguments(beanName, mbd, bw, factoryMethodToUse, argsToResolve, true);
			}
		}

정말 만든 instantiateUsingFactoryMethod 방법 - 호 3

당신이 구문 분석하지 않는 경우, 당신은 얻을 factoryClass이 시간에 있기 때문에, 사용자 정의 유형을 factoryClass할 수있다 CGLIB, 그래서 부모 클래스의 유형에 익숙해 동적 프록시 유형. 공장이 유일한 방법 인 경우 비어 있지 않은 경우,이 과부하되지 팩토리 메소드는이 비어있는 경우, 당신은 갈 것, 불변의리스트에 추가되고, 해결하세요 찾기 위해 factoryClass부모 클래스의 모든뿐만 아니라 방법은이름이 같은 방법으로 일관하고 수정 이름을 찾아 공장 방법입니다 bean주석 방법 및 목록에 배치.

if (factoryMethodToUse == null || argsToUse == null) {
			// Need to determine the factory method...
			// Try all methods with this name to see if they match the given arguments.
			factoryClass = ClassUtils.getUserClass(factoryClass);//获取用户定义的类
			//方法集合
			List<Method> candidateList = null;
			if (mbd.isFactoryMethodUnique) {//如果工厂方法唯一,没重载的
				if (factoryMethodToUse == null) {
					factoryMethodToUse = mbd.getResolvedFactoryMethod();//获取解析的工厂方法
				}
				if (factoryMethodToUse != null) {//存在的话,返回仅包含factoryMethodToUse的不可变列表
					candidateList = Collections.singletonList(factoryMethodToUse);
				}
			}
			if (candidateList == null) {//如果没找到工厂方法,可能有重载
				candidateList = new ArrayList<>();
				Method[] rawCandidates = getCandidateMethods(factoryClass, mbd);//获取factoryClass以及父类的所有方法作为候选的方法
				for (Method candidate : rawCandidates) {//过滤出修饰符一样,工厂方法名一样且是bean注解的方法
					if (Modifier.isStatic(candidate.getModifiers()) == isStatic && mbd.isFactoryMethod(candidate)) {
						candidateList.add(candidate);//如果isStatic修饰符一样且名字跟工厂方法名一样就添加
					}
				}
			}

사용자 정의 형식을 찾을 수 ClassUtils.getUserClass

public static Class<?> getUserClass(Class<?> clazz) {
		if (clazz.getName().contains(CGLIB_CLASS_SEPARATOR)) {//如果包含CGLIB的名字符号,尝试获取父类
			Class<?> superclass = clazz.getSuperclass();
			if (superclass != null && superclass != Object.class) {
				return superclass;
			}
		}
		return clazz;
	}

getCandidateMethods 취득 모든 후보 상위 클래스의 방법에있어서,

	private Method[] getCandidateMethods(Class<?> factoryClass, RootBeanDefinition mbd) {
		if (System.getSecurityManager() != null) {
			return AccessController.doPrivileged((PrivilegedAction<Method[]>) () ->
					(mbd.isNonPublicAccessAllowed() ?
						ReflectionUtils.getAllDeclaredMethods(factoryClass) : factoryClass.getMethods()));
		}
		else {
			return (mbd.isNonPublicAccessAllowed() ?
					ReflectionUtils.getAllDeclaredMethods(factoryClass) : factoryClass.getMethods());
		}
	}

반사 ReflectionUtils.getAllDeclaredMethods를 얻는 방법

비 허용하면 Public접근 방식, 당신이 그렇지 않으면 부모 클래스를 포함한 모든 진술 방법을 얻을 Public상위 클래스를 포함, 기본적으로 활성화되어, 우리가 직접 볼 수, 같은 원리를 허용.

	public static Method[] getAllDeclaredMethods(Class<?> leafClass) {
		final List<Method> methods = new ArrayList<>(32);
		doWithMethods(leafClass, methods::add);
		return methods.toArray(EMPTY_METHOD_ARRAY);
	}
	public static void doWithMethods(Class<?> clazz, MethodCallback mc) {
		doWithMethods(clazz, mc, null);
	}
doWithMethods 재귀 인수

재귀 방법 및 액세스의 구현 후, 상위 클래스의 모든 얻을 mc.doWith(method)위의 사실, 방법 methods::addlist 메소드에 추가하고, 마지막으로 돌아 가기 배열로.

public static void doWithMethods(Class<?> clazz, MethodCallback mc, @Nullable MethodFilter mf) {
		// Keep backing up the inheritance hierarchy.
		Method[] methods = getDeclaredMethods(clazz, false);
		for (Method method : methods) {
			if (mf != null && !mf.matches(method)) {
				continue;
			}
			try {
				mc.doWith(method);
			}
			catch (IllegalAccessException ex) {
				throw new IllegalStateException("Not allowed to access method '" + method.getName() + "': " + ex);
			}
		}
		if (clazz.getSuperclass() != null && (mf != USER_DECLARED_METHODS || clazz.getSuperclass() != Object.class)) {
			doWithMethods(clazz.getSuperclass(), mc, mf);
		}
		else if (clazz.isInterface()) {
			for (Class<?> superIfc : clazz.getInterfaces()) {
				doWithMethods(superIfc, mc, mf);
			}
		}
	}

나머지 다음은 언어를 사용합니다.

음, 오늘, 우리는 단지 자신의 학습, 제한 용량 이해를 참조하십시오 위대한 하나님을 뿌리지 마십시오 도움이 연구에 희망과 이해, 용서하십시오.

게시 된 235 개 원래 기사 · 원 찬양 74 ·은 30000 +를 볼

추천

출처blog.csdn.net/wangwei19871103/article/details/105052088