/**
   * Instantiates a {@link ServiceProvider}.
   *
   * @param configClasses a specified configurable class or a set of specified configurable classes
   * @param argsType the argument types of specified constructor of configurable class
   * @param args the argument objects need to be passed to constructor of configurable class.
   * @return the service provider
   */
  @SuppressWarnings("unchecked")
  public static ServiceProvider buildServiceProvider(
      Class<?>[] argsType, Object[] args, Class<? extends Configurable>... configClasses) {

    /*
     * Khởi tạo services context
     */
    ServiceProvider result = (ServiceProvider) buildContext(true, argsType, args, configClasses);
    /*
     * Thực thi các xử lý trước khi khởi tạo CSC
     */
    List<Configurable> configInstances = result.getConfigInstances();
    for (BeforeInitContext obj : JGentle.beforeInitContextList) {
      obj.beforeInitContext(
          result, configInstances.toArray(new Configurable[configInstances.size()]));
    }
    // Thực thi init trên csc
    // Thực thi init method trên mỗi CSC của services context vừa khởi tạo.
    Collection<ComponentServiceContextType<Configurable>> csclist = result.getCSCList().values();
    for (ComponentServiceContextType<Configurable> csc : csclist) {
      invokeCSCInit(result, csc, configInstances);
    }
    /*
     * Thực thi các xử lý khởi tạo CSC
     */
    List<Class<? extends ComponentServiceContextType<?>>> cscClassList = null;
    cscClassList = new ArrayList<Class<? extends ComponentServiceContextType<?>>>();
    for (Configurable instance : configInstances) {
      cscClassList.addAll(instance.getCscClassList());
    }
    // Duyệt qua từng danh sách Object Class của danh sách các CSC class.
    for (Class<? extends ComponentServiceContextType<?>> clazz : cscClassList) {
      Definition defCSC = result.getDefinitionManager().getDefinition(clazz);
      // Khởi tạo CSC và thực thi init
      ComponentServiceContextType<Configurable> comp = null;
      comp = (ComponentServiceContextType<Configurable>) result.getBean(clazz);
      invokeCSCInit(result, comp, configInstances);
      /*
       * Xử lý thông tin chỉ định trong @ComponentServiceContext nếu có
       */
      ComponentServiceContext anno = null;
      if (defCSC.isAnnotationPresent(ComponentServiceContext.class)) {
        anno = defCSC.getAnnotation(ComponentServiceContext.class);
      }
      if (anno != null) {
        // Thực thi đăng kí annotation nếu có.
        if (!anno.beforeConfigure()) {
          JGentle.registerAnnotationInCSC(result.getServiceHandler(), anno, true, result);
        }
        // Khởi tạo và đăng kí service Class
        Class<? extends ServiceClass> scClazz = anno.serviceClass();
        if (!result.getDefinitionManager().containsDefinition(scClazz)) {
          result.getDefinitionManager().loadDefinition(scClazz);
        }
        if (result
            .getDefinitionManager()
            .getDefinition(scClazz)
            .isAnnotationPresent(BeanServices.class)) {
          throw new JGentleRuntimeException(
              "Service Class "
                  + scClazz.getName()
                  + " must be annotated with @BeanServices annotation !");
        }
        String domain =
            result
                .getDefinitionManager()
                .getDefinition(scClazz)
                .getAnnotation(BeanServices.class)
                .domain();
        ServiceHandler aoh = result.getServiceHandler();
        if (!aoh.containsDomain(domain)) {
          try {
            aoh.newDomain(domain);
          } catch (JGentleException e) {
            e.printStackTrace();
          }
        }
        aoh.addService(result, scClazz, domain);
      }
      // Thực thi add CSC vào ServiceProvider hiện hành.
      result.addCSContext(
          anno == null || (anno != null && anno.value().equals(NullClass.class))
              ? clazz
              : anno.value(),
          comp);
    }
    /*
     * Xóa bỏ toàn bộ các beforeInitContext object
     */
    beforeInitContextList.clear();
    return result;
  }
  /**
   * Builds the context.
   *
   * @param serviceProvider the service provider
   * @param argsType the args type
   * @param args the args
   * @param configClasses the config classes
   * @return the context
   */
  private static Context buildContext(
      boolean serviceProvider,
      Class<?>[] argsType,
      Object[] args,
      Class<? extends Configurable>... configClasses) {

    Assertor.notNull((Object[]) configClasses);
    if ((argsType == null && args != null) || (argsType != null && args == null)) {
      throw new JGentleRuntimeException("Property 'argsType' or 'args' is invalid !");
    }
    if (argsType != null && args != null) {
      if (argsType.length != args.length) {
        throw new JGentleRuntimeException("Property 'argsType' or 'args' is invalid !");
      }
      if (configClasses.length != 1) {
        throw new JGentleRuntimeException(
            "Lenght of array property 'configClasses' must be not greater than"
                + " one if property 'argsType' and 'args' are not null.");
      }
    }
    /*
     * Khởi tạo các config object
     */
    configObjClassList.put(BindingConfig.class, BindingConfigImpl.class);
    configObjClassList.put(SystemConfig.class, SystemConfigImpl.class);
    /*
     * Khởi tạo core services
     */
    AnnotationRegister annoRegister = new AnnotationRegisterImpl();
    DefinitionManager defManager = new DefinitionManagerImpl(annoRegister);
    ServiceHandler serviceHandler = new ServiceHandlerImpl(defManager);
    JGentle.registerAnnotations(serviceHandler);
    /*
     * Thực thi các tiền xử lý trước khi thực thi cấu hình (invoke configure
     * methods).
     */
    List<Class<? extends Configurable>> absCfgList = new ArrayList<Class<? extends Configurable>>();
    for (Class<? extends Configurable> clazz : configClasses) {
      absCfgList.add(clazz);
    }
    for (BeforeConfigure bcBean : JGentle.getBeforeConfigBeanList()) {
      bcBean.doProcessing(serviceHandler, defManager, annoRegister, absCfgList);
    }
    // Khởi tạo config instance
    List<Configurable> objectList = new ArrayList<Configurable>();
    for (Class<? extends Configurable> targetClass : absCfgList) {
      Configurable result = ConfigurationProxy.createProxy(targetClass, argsType, args);
      result.configure();
      // Tìm các imported configurable class nếu có
      List<ConfigurableImporter> importingList = result.getImportsCfgLst();
      List<Configurable> allResults = new ArrayList<Configurable>();
      if (importingList != null && importingList.size() != 0) {
        for (ConfigurableImporter ci : importingList) {
          allResults.add(
              ConfigurationProxy.createProxy(ci.getConfigurableClass(), ci.argsType(), ci.args()));
        }
      }
      allResults.add(result);
      for (Configurable objResult : allResults) {
        // Nếu context khởi tạo là một Services Context
        if (serviceProvider) {
          // Thực thi đăng kí annotation nếu trong config instance có
          // tồn tại một hoặc nhiều binding CSC
          List<Class<? extends ComponentServiceContextType<?>>> list;
          list = objResult.getCscClassList();
          for (Class<? extends ComponentServiceContextType<?>> cscClass : list) {
            Definition def = defManager.getDefinition(cscClass);
            ComponentServiceContext anno = null;
            if (def != null && def.isAnnotationPresent(ComponentServiceContext.class)) {
              anno = def.getAnnotation(ComponentServiceContext.class);
            }
            if (anno != null) {
              if (anno.beforeConfigure()) {
                // Thực thi đăng kí.
                JGentle.registerAnnotationInCSC(serviceHandler, anno, false, null);
              }
            }
          }
        }
        // invoke configure method
        if (objResult != result) objResult.configure();
        objectList.add(objResult);
      }
    }
    Context result = null;
    result =
        buildContext(
            serviceHandler,
            serviceProvider,
            objectList.toArray(new Configurable[objectList.size()]));
    /*
     * Clear toàn bộ config object
     */
    configObjClassList.clear();
    return result;
  }