
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