[Sping 핵심] 빈 팩 토리 와 팩 토리 빈.

24088 단어 Spring
1. 빈 팩 토리 가 뭐 예요?
        빈 팩 토 리 는 가장 기본 적 인 IOC 용기 기능 을 제공 했다.이것 은 인터페이스 클래스 로 Default Listable BeanFactory, XmlBeanFactory, Application Context 등 은 용기 가 특정한 기능 을 부가 한 구체 적 인 실현 이 라 고 볼 수 있다.스프링 에 서 는 빈 을 빈 팩 토리 (즉 IOC 용기) 가 관리한다.
public interface BeanFactory {

    String FACTORY_BEAN_PREFIX = "&";
    Object getBean(String name) throws BeansException;
     T getBean(String name, Class requiredType) throws BeansException;
    Object getBean(String name, Object... args) throws BeansException;
     T getBean(Class requiredType) throws BeansException;
     T getBean(Class requiredType, Object... args) throws BeansException;
     ObjectProvider getBeanProvider(Class requiredType);
     ObjectProvider getBeanProvider(ResolvableType requiredType);
    /**
     *               Bean 
     */
    boolean containsBean(String name);
    /**
     *         Bean   Singleton   Bean 
     */
    boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
    /**
     *         Bean   Prototype   Bean 
     */
    boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
    boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;
    /**
     *         Bean Class        Class 
     */
    boolean isTypeMatch(String name, Class> typeToMatch) throws NoSuchBeanDefinitionException;
    /**
     *         Bean Class  
     */
    @Nullable
    Class> getType(String name) throws NoSuchBeanDefinitionException;
    /**
     *         Bean      
     */
    String[] getAliases(String name);
}

둘째, Factory Bean 이 무엇 입 니까?
       Spring 에는 두 가지 유형의 Bean 이 있 는데 하 나 는 일반 Bean 이 고 다른 하 나 는 공장 Bean 즉 Factory Bean 이다.Factory Bean 은 일반 Bean 과 달리 돌아 오 는 대상 은 지정 한 클래스 의 인 스 턴 스 가 아니 라 이 Factory Bean 의 getObject 방법 으로 돌아 오 는 대상 입 니 다.만 든 대상 이 단일 사례 에 속 하 는 지 여 부 는 isSingleton 의 반환 에 의 해 결정 된다.
public interface FactoryBean {
    /**
     *    FactoryBean“  ”   
     */
    @Nullable
    T getObject() throws Exception;
    /**
     *       getObject()           
     */
    @Nullable
    Class> getObjectType();
    /**
     *   “  ”       singleton(  )       。   singleton    ,   true,    false
     */
   //5.0  
    default boolean isSingleton() {
        return true;
    }
   //5.0  
    boolean isSingleton();
}

3. 코드 인 스 턴 스
public interface FactoryBeanService {
    /**
     *   FactoryBean
     */
    public void testFactoryBean();
}
import org.springframework.beans.factory.FactoryBean;
import org.springframework.stereotype.Component;

@Component
public class FactoryBeanStudy implements FactoryBean {
    @Override
    public FactoryBeanService getObject() throws Exception {
        return new FactoryBeanServiceImpl();
    }

    @Override
    public Class> getObjectType() {
        return FactoryBeanService.class;
    }

    @Override
    public boolean isSingleton() {
        return false;
    }
}
import org.junit.Test;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class FactoryBeanServiceImpl implements FactoryBeanService {

    @Override
    public void testFactoryBean() {
        System.out.println("test FactoryBean");
    }

    @Test
    public void test() {
        try {

        ApplicationContext ctx = new ClassPathXmlApplicationContext("test.xml");
        FactoryBeanService beanService = ctx.getBean(FactoryBeanService.class);
        beanService.testFactoryBean();
        System.out.println(beanService);
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}
  :
test FactoryBean
com.nuc.zp.sourcecode.ioc2.FactoryBeanServiceImpl@74bf1791

4. 소스 코드 분석
AbstractApplicationContext.class
@Override
	public  Map getBeansOfType(@Nullable Class type) throws BeansException {
		//  BeanFactory     
		assertBeanFactoryActive();
		//getBeanFactory()       DefaultListableBeanFactory   
		//     DefaultListableBeanFactory    getBean    
		return getBeanFactory().getBeansOfType(type);
	}

DefaultListableBeanFactory.class
/**
 *  requiredType:  com.nuc.zp.sourcecode.ioc2.FactoryBeanService
 */
@Override
public  T getBean(Class requiredType) throws BeansException {
   return getBean(requiredType, (Object[]) null);
}
@SuppressWarnings("unchecked")
@Override
public  T getBean(Class requiredType, @Nullable Object... args) throws BeansException {
   Assert.notNull(requiredType, "Required type must not be null");
   //  bean
   Object resolved = resolveBean(ResolvableType.forRawClass(requiredType), args, false);
   if (resolved == null) {
      throw new NoSuchBeanDefinitionException(requiredType);
   }
   return (T) resolved;
}
@Nullable
private  T resolveBean(ResolvableType requiredType, @Nullable Object[] args, boolean nonUniqueAsNull) {
  //      NamedBeanHolder,     requiredType   。
   NamedBeanHolder namedBean = resolveNamedBean(requiredType, args, nonUniqueAsNull);
   if (namedBean != null) {
      return namedBean.getBeanInstance();
   }
   //    Spring           Bean  ,        
   //SpringMVC           
   BeanFactory parent = getParentBeanFactory();
   if (parent instanceof DefaultListableBeanFactory) {
      return ((DefaultListableBeanFactory) parent).resolveBean(requiredType, args, nonUniqueAsNull);
   }
   else if (parent != null) {
      //         ,   BeanFactory     
      ObjectProvider parentProvider = parent.getBeanProvider(requiredType);
      if (args != null) {
         return parentProvider.getObject(args);
      }
      else {
         return (nonUniqueAsNull ? parentProvider.getIfUnique() : parentProvider.getIfAvailable());
      }
   }
   return null;
}
/**
*  NamedBeanHolder      MapM
*  beanName        key      factoryBeanStudy
*  beanInstance    value    factoryBeanService
*/
public class NamedBeanHolder implements NamedBean {

   private final String beanName;

   private final T beanInstance;


   /**
    * Create a new holder for the given bean name plus instance.
    * @param beanName the name of the bean
    * @param beanInstance the corresponding bean instance
    */
   public NamedBeanHolder(String beanName, T beanInstance) {
      Assert.notNull(beanName, "Bean name must not be null");
      this.beanName = beanName;
      this.beanInstance = beanInstance;
   }


   /**
    * Return the name of the bean.
    */
   @Override
   public String getBeanName() {
      return this.beanName;
   }

   /**
    * Return the corresponding bean instance.
    */
   public T getBeanInstance() {
      return this.beanInstance;
   }

}
/**
 *       Bean
 */
@SuppressWarnings("unchecked")
@Nullable
private  NamedBeanHolder resolveNamedBean(
      ResolvableType requiredType, @Nullable Object[] args, boolean nonUniqueAsNull) throws BeansException {
   Assert.notNull(requiredType, "Required type must not be null");
   //          Class     BeanName,                  (  ),
   //          String  。         。
   //        ,    getBean     type com.nuc.zp.sourcecode.ioc2.FactoryBeanService  ,       Spring     FactoryBeanService   Bean
   //              beanName 。          ?      getBeanNamesForType   

   String[] candidateNames = getBeanNamesForType(requiredType);
   //     BeanName,      BeanName
   if (candidateNames.length > 1) {
      List autowireCandidates = new ArrayList<>(candidateNames.length);
      for (String beanName : candidateNames) {
         if (!containsBeanDefinition(beanName) || getBeanDefinition(beanName).isAutowireCandidate()) {
            autowireCandidates.add(beanName);
         }
      }
      if (!autowireCandidates.isEmpty()) {
         candidateNames = StringUtils.toStringArray(autowireCandidates);
      }
   }
   //      BeanName     getBean     Bean      NamedBeanHolder 
   //    bean   beanName,beanType args   bean
   if (candidateNames.length == 1) {
      String beanName = candidateNames[0];//factoryBeanStudy
     //   getBean  ,      FactoryBean getObjectType  ,     factoryBeanService   
      return new NamedBeanHolder<>(beanName, (T) getBean(beanName, requiredType.toClass(), args));
   }
   //     BeanName       
   else if (candidateNames.length > 1) {
      Map candidates = new LinkedHashMap<>(candidateNames.length);
      for (String beanName : candidateNames) {
         //             Bean
         if (containsSingleton(beanName) && args == null) {
            Object beanInstance = getBean(beanName);
            candidates.put(beanName, (beanInstance instanceof NullBean ? null : beanInstance));
         }
         else {
            //  getType      Bean  
            candidates.put(beanName, getType(beanName));
         }
      }
      //   Bean         Primary      Primary   Bean
      String candidateName = determinePrimaryCandidate(candidates, requiredType.toClass());
      if (candidateName == null) {
         candidateName = determineHighestPriorityCandidate(candidates, requiredType.toClass());
      }
      if (candidateName != null) {
         Object beanInstance = candidates.get(candidateName);
         //Class         getBean    Bean  
         if (beanInstance == null || beanInstance instanceof Class) {
            beanInstance = getBean(candidateName, requiredType.toClass(), args);
         }
         return new NamedBeanHolder<>(candidateName, (T) beanInstance);
      }
      if (!nonUniqueAsNull) {
         //           
         throw new NoUniqueBeanDefinitionException(requiredType, candidates.keySet());
      }
   }
@Override
public String[] getBeanNamesForType(ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit) {
   Class> resolved = type.resolve();
   if (resolved != null && !type.hasGenerics()) {
      return getBeanNamesForType(resolved, includeNonSingletons, includeNonSingletons);
   }
   else {
      return doGetBeanNamesForType(type, includeNonSingletons, includeNonSingletons);
   }
}
@Override
public String[] getBeanNamesForType(@Nullable Class> type, boolean includeNonSingletons, boolean allowEagerInit) {
   if (!isConfigurationFrozen() || type == null || !allowEagerInit) {
      return doGetBeanNamesForType(ResolvableType.forRawClass(type), includeNonSingletons, allowEagerInit);
   }
   //       
   Map, String[]> cache =
         (includeNonSingletons ? this.allBeanNamesByType : this.singletonBeanNamesByType);
   String[] resolvedBeanNames = cache.get(type);
   if (resolvedBeanNames != null) {
      return resolvedBeanNames;
   }
   //  doGetBeanNamesForType    beanName
   resolvedBeanNames = doGetBeanNamesForType(ResolvableType.forRawClass(type), includeNonSingletons, true);
   //                
   if (ClassUtils.isCacheSafe(type, getBeanClassLoader())) {
      //      ,            
      cache.put(type, resolvedBeanNames);
   }
   return resolvedBeanNames;
}

 
private String[] doGetBeanNamesForType(ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit) {
   List result = new ArrayList<>();
   //     beanName     Spring      Bean        List  
   // Check all bean definitions.
   for (String beanName : this.beanDefinitionNames) {
      // Only consider bean as eligible if the bean name
      // is not defined as alias for some other bean.
      if (!isAlias(beanName)) {
         try {
            //  beanName  RootBeanDefinition
            RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
            // Only check bean definition if it is complete.
            //RootBeanDefinition  Bean     、      
            if (!mbd.isAbstract() && (allowEagerInit ||
                  (mbd.hasBeanClass() || !mbd.isLazyInit() || isAllowEagerClassLoading()) &&
                        !requiresEagerInitForType(mbd.getFactoryBeanName()))) {
               //   FactoryBean   
               boolean isFactoryBean = isFactoryBean(beanName, mbd);
               BeanDefinitionHolder dbd = mbd.getDecoratedDefinition();
               //                              isTypeMatch    
               //  isTypeMatch      true  ,      beanName factoryBeanStudy    result   
               boolean matchFound = false;
               boolean allowFactoryBeanInit = allowEagerInit || containsSingleton(beanName);
               boolean isNonLazyDecorated = dbd != null && !mbd.isLazyInit();
               if (!isFactoryBean) {
                  //     ,  FactoryBean        beanName   &beanName
                  if (includeNonSingletons || isSingleton(beanName, mbd, dbd)) {
                     //         
                     matchFound = isTypeMatch(beanName, type, allowFactoryBeanInit);
                  }
               }
               else  {
                  if (includeNonSingletons || isNonLazyDecorated ||
                        (allowFactoryBeanInit && isSingleton(beanName, mbd, dbd))) {
                     matchFound = isTypeMatch(beanName, type, allowFactoryBeanInit);
                  }
                  if (!matchFound) {
                     // In case of FactoryBean, try to match FactoryBean instance itself next.
                     beanName = FACTORY_BEAN_PREFIX + beanName;
                     matchFound = isTypeMatch(beanName, type, allowFactoryBeanInit);
                  }
               }
               if (matchFound) {
                  result.add(beanName);
               }
            }
         }
         catch (CannotLoadBeanClassException | BeanDefinitionStoreException ex) {
            if (allowEagerInit) {
               throw ex;
            }
            // Probably a placeholder: let's ignore it for type matching purposes.
            LogMessage message = (ex instanceof CannotLoadBeanClassException) ?
                  LogMessage.format("Ignoring bean class loading failure for bean '%s'", beanName) :
                  LogMessage.format("Ignoring unresolvable metadata in bean definition '%s'", beanName);
            logger.trace(message, ex);
            onSuppressedException(ex);
         }
      }
   }


   //   Bean Spring             Bean  Environment
   // Check manually registered singletons too.
   for (String beanName : this.manualSingletonNames) {
      try {
         // In case of FactoryBean, match object created by FactoryBean.
         if (isFactoryBean(beanName)) {
            if ((includeNonSingletons || isSingleton(beanName)) && isTypeMatch(beanName, type)) {
               result.add(beanName);
               // Match found for this bean: do not match FactoryBean itself anymore.
               continue;
            }
            // In case of FactoryBean, try to match FactoryBean itself next.
            beanName = FACTORY_BEAN_PREFIX + beanName;
         }
         // Match raw bean instance (might be raw FactoryBean).
         if (isTypeMatch(beanName, type)) {
            result.add(beanName);
         }
      }
      catch (NoSuchBeanDefinitionException ex) {
         // Shouldn't happen - probably a result of circular reference resolution...
         logger.trace(LogMessage.format("Failed to check manually registered singleton with name '%s'", beanName), ex);
      }
   }

   return StringUtils.toStringArray(result);
}
boolean isTypeMatch(String name, ResolvableType typeToMatch,
      boolean allowFactoryBeanInit) throws NoSuchBeanDefinitionException {
   //  beanName              beanName factoryBeanStudy         Spring       Bean
   String beanName = transformedBeanName(name);
   boolean isFactoryDereference = BeanFactoryUtils.isFactoryDereference(name);
   //         AbstractApplicationContext     Spring     Bean
   //  beanName factoryBeanStudy Bean           Bean   
   //       :  AbstractApplicationContext    Spring     Bean 
   //  BeanFactory         Bean     ?        

   // Check manually registered singletons.
   Object beanInstance = getSingleton(beanName, false);
   if (beanInstance != null && beanInstance.getClass() != NullBean.class) {
      //factoryBeanStudy FactoryBean      
      if (beanInstance instanceof FactoryBean) {
         //    beanName    &                         &   Bean
         if (!isFactoryDereference) {
            //     factoryBeanStudy  type                
            Class> type = getTypeForFactoryBean((FactoryBean>) beanInstance);
            // factoryBeanLearn     type                          
            return (type != null && typeToMatch.isAssignableFrom(type));
         }
         else {
            return typeToMatch.isInstance(beanInstance);
         }
      }
      else if (!isFactoryDereference) {
         if (typeToMatch.isInstance(beanInstance)) {
            // Direct match for exposed instance?
            return true;
         }
         else if (typeToMatch.hasGenerics() && containsBeanDefinition(beanName)) {
            // Generics potentially only match on the target class, not on the proxy...
            RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
            Class> targetType = mbd.getTargetType();
            if (targetType != null && targetType != ClassUtils.getUserClass(beanInstance)) {
               // Check raw class match as well, making sure it's exposed on the proxy.
               Class> classToMatch = typeToMatch.resolve();
               if (classToMatch != null && !classToMatch.isInstance(beanInstance)) {
                  return false;
               }
               if (typeToMatch.isAssignableFrom(targetType)) {
                  return true;
               }
            }
            ResolvableType resolvableType = mbd.targetType;
            if (resolvableType == null) {
               resolvableType = mbd.factoryMethodReturnType;
            }
            return (resolvableType != null && typeToMatch.isAssignableFrom(resolvableType));
         }
      }
      return false;
   }
   else if (containsSingleton(beanName) && !containsBeanDefinition(beanName)) {
      // null instance registered
      return false;
   }

   // No singleton instance found -> check bean definition.
   BeanFactory parentBeanFactory = getParentBeanFactory();
   if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
      // No bean definition found in this factory -> delegate to parent.
      return parentBeanFactory.isTypeMatch(originalBeanName(name), typeToMatch);
   }

   // Retrieve corresponding bean definition.
   RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
   BeanDefinitionHolder dbd = mbd.getDecoratedDefinition();

   // Setup the types that we want to match against
   Class> classToMatch = typeToMatch.resolve();
   if (classToMatch == null) {
      classToMatch = FactoryBean.class;
   }
   Class>[] typesToMatch = (FactoryBean.class == classToMatch ?
         new Class>[] {classToMatch} : new Class>[] {FactoryBean.class, classToMatch});


   // Attempt to predict the bean type
   Class> predictedType = null;

   // We're looking for a regular reference but we're a factory bean that has
   // a decorated bean definition. The target bean should be the same type
   // as FactoryBean would ultimately return.
   if (!isFactoryDereference && dbd != null && isFactoryBean(beanName, mbd)) {
      // We should only attempt if the user explicitly set lazy-init to true
      // and we know the merged bean definition is for a factory bean.
      if (!mbd.isLazyInit() || allowFactoryBeanInit) {
         RootBeanDefinition tbd = getMergedBeanDefinition(dbd.getBeanName(), dbd.getBeanDefinition(), mbd);
         Class> targetType = predictBeanType(dbd.getBeanName(), tbd, typesToMatch);
         if (targetType != null && !FactoryBean.class.isAssignableFrom(targetType)) {
            predictedType = targetType;
         }
      }
   }

   // If we couldn't use the target type, try regular prediction.
   if (predictedType == null) {
      predictedType = predictBeanType(beanName, mbd, typesToMatch);
      if (predictedType == null) {
         return false;
      }
   }

   // Attempt to get the actual ResolvableType for the bean.
   ResolvableType beanType = null;

   // If it's a FactoryBean, we want to look at what it creates, not the factory class.
   if (FactoryBean.class.isAssignableFrom(predictedType)) {
      if (beanInstance == null && !isFactoryDereference) {
         beanType = getTypeForFactoryBean(beanName, mbd, allowFactoryBeanInit);
         predictedType = beanType.resolve();
         if (predictedType == null) {
            return false;
         }
      }
   }
   else if (isFactoryDereference) {
      // Special case: A SmartInstantiationAwareBeanPostProcessor returned a non-FactoryBean
      // type but we nevertheless are being asked to dereference a FactoryBean...
      // Let's check the original bean class and proceed with it if it is a FactoryBean.
      predictedType = predictBeanType(beanName, mbd, FactoryBean.class);
      if (predictedType == null || !FactoryBean.class.isAssignableFrom(predictedType)) {
         return false;
      }
   }

   // We don't have an exact type but if bean definition target type or the factory
   // method return type matches the predicted type then we can use that.
   if (beanType == null) {
      ResolvableType definedType = mbd.targetType;
      if (definedType == null) {
         definedType = mbd.factoryMethodReturnType;
      }
      if (definedType != null && definedType.resolve() == predictedType) {
         beanType = definedType;
      }
   }

   // If we have a bean type use it so that generics are considered
   if (beanType != null) {
      return typeToMatch.isAssignableFrom(beanType);
   }

   // If we don't have a bean type, fallback to the predicted type
   return typeToMatch.isAssignableFrom(predictedType);
}

        위의 분석 은 다음 과 같다. 우리 가 getBean (Class required Type) 방법 을 사용 하여 용기 에 있 는 bean 을 유형 에 따라 가 져 올 때 대응 하 는 예 는 유형 Factory Bean Service 에 따라 Spring 용기 에서 Bean 을 가 져 오 는 것 이다.(우선 명확 한 것 은 Spring 용기 에 Factory BeanService 타 입의 BeanDefinition 이 없다 는 것 이다. 그러나 하나의 Bean 은 Factory BeanService 타 입 과 관련 이 있다.). Spring 은 type 에 따라 Bean 을 가 져 올 때 beanName 을 가 져 옵 니 다. beanName 을 가 져 오 는 과정 은 다음 과 같 습 니 다. Spring 용기 에 있 는 모든 beanName 을 순환 한 다음 beanName 에 따라 해당 하 는 BeanDefinition 을 가 져 옵 니 다. 현재 bean 이 Factory Bean 형식 이 라면 Spring 용기 에서 BeanName 에 따라 해당 하 는 Bean 인 스 턴 스 를 가 져 오고 가 져 온 Bean 인 스 턴 스 의 get 을 호출 합 니 다.Object Type 방법 은 Class 형식 을 가 져 옵 니 다. 이 Class 유형 이 우리 가 들 어 오 는 Class 와 같은 유형 인지 판단 합 니 다. 만약 그렇다면 beanName 을 되 돌려 주 십시오. 이에 대응 하 는 것 은 factory BeanStudy 에 따라 Factory BeanStudy 인 스 턴 스 를 가 져 옵 니 다. Factory BeanStudy 의 getObject Type 방법 으로 반환 값 Factory Bean Service. class 를 가 져 옵 니 다. 우리 가 들 어 오 는 유형 과 일치 합 니 다.여기 서 얻 은 beanName 을 factory BeanStudy 로 합 니 다. 다시 말 하면 factory BeanStudy 라 는 beanName 을 factory BeanService 유형 으로 표시 합 니 다. 즉, Factory BeanService 유형 에 대응 하 는 beanName 을 factory BeanStudy 로 표시 하 는 것 이 중요 합 니 다.
총화
         BeanFactory 에 서 는 Spring 용기 에 있 는 Bean 을 만 들 고 관리 할 수 있 습 니 다. Bean 을 만 드 는 데 통 일 된 절차 가 있 습 니 다. Factory Bean 은 공장 Bean 으로 특정한 유형의 Bean 인 스 턴 스 를 생 성 할 수 있 습 니 다. 가장 큰 역할 은 Bean 의 생 성 과정 을 사용자 정의 할 수 있 습 니 다.

좋은 웹페이지 즐겨찾기