All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.jianggujin.modulelink.impl.spring.JSpringModuleManager Maven / Gradle / Ivy

/**
 * Copyright 2018 jianggujin (www.jianggujin.com).
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.jianggujin.modulelink.impl.spring;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Set;

import org.springframework.beans.BeansException;
import org.springframework.beans.CachedIntrospectionResults;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;

import com.jianggujin.modulelink.JModule;
import com.jianggujin.modulelink.JModuleConfig;
import com.jianggujin.modulelink.impl.JAbstractModuleManager;
import com.jianggujin.modulelink.impl.JModuleImpl;
import com.jianggujin.modulelink.util.JAssert;
import com.jianggujin.modulelink.util.JLogFactory;
import com.jianggujin.modulelink.util.JLogFactory.JLog;
import com.jianggujin.modulelink.util.JStringUtils;

/**
 * Spring模块管理器
 * 
 * @author jianggujin
 *
 */
public class JSpringModuleManager extends JAbstractModuleManager implements ApplicationContextAware {
   private static final JLog logger = JLogFactory.getLog(JSpringModuleManager.class);
   /**
    * Spring bean文件所在目录,不同的路径确保能取到资源
    */
   public final static String[] SPRING_XML_PATTERN = { "classpath*:META-INF/spring/*.xml",
         "classpath*:*META-INF/spring/*.xml" };
   /**
    * 注入父applicationContext
    */
   private ApplicationContext applicationContext;

   @Override
   protected ClassLoader getParentClassLoader() {
      return applicationContext.getClassLoader();
   }

   @Override
   protected JModule load(JModuleConfig moduleConfig, ClassLoader moduleClassLoader) throws Exception {
      // 只有使用SpringConfig的模块才使用Spring进行加载
      if (moduleConfig instanceof JSpringModuleConfig) {
         JSpringModuleConfig springModuleConfig = (JSpringModuleConfig) moduleConfig;
         ConfigurableApplicationContext context;
         Properties properties = getProperties(springModuleConfig);
         Set scanBase = springModuleConfig.getScanPackages();
         // 注解方式加载bean
         if (!scanBase.isEmpty()) {
            context = new JModuleAnnotationApplicationContext(properties);
            ((JModuleAnnotationApplicationContext) context).scan(scanBase.toArray(new String[0]));
         } else {
            // XML方式加载bean
            context = new JModuleXmlApplicationContext();
            ((JModuleXmlApplicationContext) context).setProperties(properties);

            String[] locations = findSpringConfigs(springModuleConfig, moduleClassLoader);
            ((JModuleXmlApplicationContext) context).setConfigLocations(locations);
         }
         context.setParent(applicationContext);
         if (logger.isInfoEnabled()) {
            logger.info("module " + moduleConfig.getName() + ":" + moduleConfig.getVersion()
                  + " allow current process to override bean in module");
         }
         ((DefaultResourceLoader) context).setClassLoader(moduleClassLoader);
         context.refresh();

         return new JSpringModule(moduleConfig, context);
      } else {
         return new JModuleImpl(moduleConfig, moduleClassLoader);
      }
   }

   @Override
   protected void loadModuleError(ClassLoader moduleClassLoader) {
      super.loadModuleError(moduleClassLoader);
      CachedIntrospectionResults.clearClassLoader(moduleClassLoader);
   }

   /**
    * 获得模块的配置
    *
    * @param moduleConfig
    * @return
    */
   private Properties getProperties(JSpringModuleConfig moduleConfig) {
      Properties properties = toProperties(moduleConfig.getProperties());
      if (logger.isInfoEnabled()) {
         logger.info("module Properties: " + properties);
      }
      return properties;
   }

   /**
    * 查找资源(JAR)中的Spring配置文件
    *
    * @param tempFileJarURLs
    * @param moduleClassLoader
    * @return
    */
   private String[] findSpringConfigs(JSpringModuleConfig moduleConfig, ClassLoader moduleClassLoader) {
      List tempFileJarURLs = moduleConfig.getModuleUrlPath();
      try {
         PathMatchingResourcePatternResolver pmr = new PathMatchingResourcePatternResolver(moduleClassLoader);
         List list = new ArrayList();
         Set xmlPatterns = moduleConfig.getXmlPatterns();
         if (xmlPatterns.isEmpty()) {
            for (String locationPattern : SPRING_XML_PATTERN) {
               list.addAll(Arrays.asList(pmr.getResources(locationPattern)));
            }
         } else {
            for (String locationPattern : xmlPatterns) {
               list.addAll(Arrays.asList(pmr.getResources(locationPattern)));
            }
         }
         Resource[] resources = list.toArray(new Resource[] {});

         JAssert.checkArgument(resources.length > 0, "resources length is 0");
         // 因为ClassLoader是树形结构,这里会找到ModuleClassLoader以及其父类中所有符合规范的spring配置文件,所以这里需要过滤,只需要Module
         // Jar中的
         return filterURLsIncludedResources(tempFileJarURLs, resources, moduleConfig.getExclusions());
      } catch (IOException e) {
         throw new IllegalStateException("failed to find spring configs from " + tempFileJarURLs, e);
      }
   }

   /**
    * 过滤查找到的spring配置文件资源,只查找tempFileJarURLs中的spring配置文件
    *
    * @param tempFileJarURLs
    * @param resources
    * @param exclusionConfigeNameList
    * @return
    * @throws IOException
    */
   private String[] filterURLsIncludedResources(List tempFileJarURLs, Resource[] resources,
         Set exclusionConfigeNameList) throws IOException {
      List configLocations = new ArrayList();
      for (Resource resource : resources) {
         String configLocation = resource.getURL().toString();
         for (String url : tempFileJarURLs) {
            if (isExclusionConfig(configLocation, exclusionConfigeNameList)) {
               if (logger.isInfoEnabled()) {
                  logger.info("exclusion url: " + configLocation);
               }
               continue;
            }
            if (configLocation.contains(url)) {
               configLocations.add(configLocation);
            }
         }
      }
      if (logger.isInfoEnabled()) {
         logger.info("config locations: " + configLocations);
      }
      return configLocations.toArray(new String[0]);
   }

   /**
    * 是否是需要不载入的spring配置
    *
    * @param url
    * @param exclusionConfigeNameList
    * @return
    */
   private boolean isExclusionConfig(String url, Set exclusionConfigeNameList) {
      for (String tmp : exclusionConfigeNameList) {
         if (url.contains(tmp)) {
            return true;
         }
      }
      return false;
   }

   /**
    * Map 转换为Properties
    *
    * @param map
    * @return
    */
   private static Properties toProperties(Map map) {
      Properties properties = new Properties();
      for (Entry each : map.entrySet()) {
         if (each.getKey() == null || each.getValue() == null) {
            if (logger.isWarnEnabled()) {
               logger.warn("ignore null properties: " + each.getKey() + "=" + each.getValue());
            }
            continue;
         }
         if (JStringUtils.isBlank(each.getKey())) {
            continue;
         }
         properties.setProperty(each.getKey(), each.getValue().toString());
      }
      return properties;
   }

   @Override
   public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
      this.applicationContext = applicationContext;
   }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy