/* * Copyright 2013 The Skfiy Open Association. * * 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 org.skfiy.typhon.container; import com.google.common.collect.Lists; import org.skfiy.typhon.Container; import com.google.inject.AbstractModule; import com.google.inject.Binding; import com.google.inject.Guice; import com.google.inject.Injector; import com.google.inject.Key; import com.google.inject.binder.ScopedBindingBuilder; import com.google.inject.multibindings.Multibinder; import com.google.inject.name.Names; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Set; import java.util.regex.Pattern; import javax.inject.Inject; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import org.apache.commons.modeler.Registry; import org.reflections.Reflections; import org.reflections.scanners.ResourcesScanner; import org.reflections.util.ConfigurationBuilder; import org.skfiy.typhon.Component; import org.skfiy.typhon.ConfigurationException; import org.skfiy.typhon.util.MBeanUtils; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; /** * Guice IoC Bean容器实现. * * @author Kevin Zou <<kevinz@skfiy.org>> */ public class GuiceContainer implements Component, Container { @Inject private Injector injector; @Override public void init() { Injector inj = Guice.createInjector(new AbstractModule() { @Override protected void configure() { bind(Container.class).toInstance(GuiceContainer.this); } }, new Jsr250Module(), new XmlModule() ); MBeanUtils.registerComponent(this, OBJECT_NAME, null); } @Override public void reload() { throw new UnsupportedOperationException("Not supported yet."); } @Override public void destroy() { Destroyable destroyable = injector.getInstance(Destroyable.class); Set<Map.Entry<Key<?>, Binding<?>>> entries = injector.getAllBindings().entrySet(); for (Map.Entry<Key<?>, Binding<?>> entry : entries) { Binding<?> binding = entry.getValue(); destroyable.destroy(binding.getSource()); } injector = null; // 注销Container MBean Registry.getRegistry(null, null).unregisterComponent(OBJECT_NAME); } @Override public <T> T getInstance(final Class<T> clazz) { if (injector == null) { throw new IllegalStateException("Don't init container."); } return injector.getInstance(clazz); } @Override public Collection<Class> getAllBindingClasses() { List<Class> classes = Lists.newArrayList(); Set<Map.Entry<Key<?>, Binding<?>>> entries = injector.getAllBindings().entrySet(); for (Map.Entry<Key<?>, Binding<?>> entry : entries) { Key<?> key = entry.getKey(); classes.add(key.getTypeLiteral().getRawType()); } return classes; } @Override public void injectMembers(final Object obj) { if (injector == null) { throw new IllegalStateException("Don't init container."); } injector.injectMembers(obj); } /** * 获取Guice Injector实例. * * @return Injector实例 */ public Injector getInjector() { return injector; } class XmlModule extends AbstractModule { @Override protected void configure() { // 加载classpath环境下所有bean-*.xml文件 ClassLoader classLoader = getClass().getClassLoader(); ConfigurationBuilder builder = ConfigurationBuilder.build( new ResourcesScanner(), classLoader); Reflections refs = new Reflections(builder); Set<String> resources = refs.getResources(Pattern.compile("beans-.*\\.xml")); for (String res : resources) { URL url = classLoader.getResource(res); InputStream in = null; try { in = url.openStream(); configure0(in); } catch (IOException ex) { throw new ConfigurationException(ex); } catch (Exception ex) { throw new ConfigurationException("解析" + url + "文件失败", ex); } finally { if (in != null) { try { in.close(); } catch (IOException ex) { } } } } } private void configure0(InputStream stream) throws Exception { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); Document document = builder.parse(stream); Element root = document.getDocumentElement(); NodeList nodes = root.getChildNodes(); for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); switch (node.getNodeName()) { case "property": bindProperty(node); break; case "bean": bindBean(node); break; case "multi-set": bindSetBean(node); break; default: // throw new ConfigurationException( // "beans.xml中没有定义[" + node.getNodeName() + "]节点"); } } } private void bindProperty(Node node) { NamedNodeMap attrMap = node.getAttributes(); Node nameNode = attrMap.getNamedItem("name"); Node valueNode = attrMap.getNamedItem("value"); Node typeNode = attrMap.getNamedItem("type"); String name = nameNode.getNodeValue(); String value = valueNode.getNodeValue(); String typeName = typeNode.getNodeValue(); switch (typeName) { case "byte": case "java.lang.Byte": bind(Byte.class).annotatedWith(Names.named(name)) .toInstance(Byte.valueOf(value)); break; case "boolean": case "java.lang.Boolean": bind(Boolean.class).annotatedWith(Names.named(name)) .toInstance(Boolean.valueOf(value)); break; case "int": case "java.lang.Integer": bind(Integer.class).annotatedWith(Names.named(name)) .toInstance(Integer.valueOf(value)); break; case "long": case "java.lang.Long": bind(Long.class).annotatedWith(Names.named(name)) .toInstance(Long.valueOf(value)); break; case "short": case "java.lang.Short": bind(Short.class).annotatedWith(Names.named(name)) .toInstance(Short.valueOf(value)); break; case "double": case "java.lang.Double": bind(Double.class).annotatedWith(Names.named(name)) .toInstance(Double.valueOf(value)); break; default: bind(String.class).annotatedWith(Names.named(name)) .toInstance(value); break; } } protected void bindBean(Node node) { NamedNodeMap attrMap = node.getAttributes(); Node typeAttr = attrMap.getNamedItem("type"); Node classAttr = attrMap.getNamedItem("class"); Node lazyAttr = attrMap.getNamedItem("lazy"); boolean lazy = false; if (lazyAttr != null) { try { lazy = Boolean.valueOf(lazyAttr.getNodeValue()); } catch (Exception e) { } } Class type = null; if (typeAttr != null) { try { type = Class.forName(typeAttr.getNodeValue()); } catch (ClassNotFoundException ex) { throw new ConfigurationException( typeAttr.getNodeName() + " > type 属性值配置错误[" + typeAttr.getNodeValue() + "]", ex); } } Class clazz = null; try { clazz = Class.forName(classAttr.getNodeValue()); } catch (ClassNotFoundException ex) { throw new ConfigurationException( classAttr.getNodeName() + " > class 属性值配置错误[" + classAttr.getNodeValue() + "]", ex); } // 如果没有接口,则直接绑定实现类 ScopedBindingBuilder sbber; if (type == null) { sbber = bind(clazz); } else { sbber = bind(type).to(clazz); } if (!lazy) { sbber.asEagerSingleton(); } } protected void bindSetBean(Node node) { String typeStr = node.getAttributes().getNamedItem("type").getNodeValue(); Class type = null; try { type = Class.forName(typeStr); } catch (ClassNotFoundException ex) { throw new ConfigurationException( node.getNodeName() + " > type 属性值配置错误[" + typeStr + "]", ex); } Multibinder multibinder = Multibinder.newSetBinder(binder(), type); NodeList nodeList = node.getChildNodes(); for (int i = 0; i < nodeList.getLength(); i++) { Node elementNode = nodeList.item(i); if ("element".equals(elementNode.getNodeName())) { String clazzStr = elementNode.getAttributes() .getNamedItem("class").getNodeValue(); try { Class clazz = Class.forName(clazzStr); multibinder.addBinding().to(clazz); } catch (ClassNotFoundException ex) { throw new ConfigurationException( node.getNodeName() + " > " + elementNode.getNodeName() + " > class 属性值配置错误[" + typeStr + "]", ex); } } } } } }