Browse Source

青涩知夏->增加SPI

青涩知夏 4 years ago
parent
commit
342b68444f
28 changed files with 1245 additions and 14 deletions
  1. 42 0
      pom.xml
  2. 4 2
      src/main/java/cn/nosum/NoSumGateWayStart.java
  3. 91 0
      src/main/java/cn/nosum/common/annotation/Activate.java
  4. 38 0
      src/main/java/cn/nosum/common/annotation/Adaptive.java
  5. 9 0
      src/main/java/cn/nosum/common/annotation/DisableInject.java
  6. 68 0
      src/main/java/cn/nosum/common/annotation/Extension.java
  7. 15 0
      src/main/java/cn/nosum/common/annotation/SPI.java
  8. 17 0
      src/main/java/cn/nosum/common/extension/ExtensionFactory.java
  9. 450 0
      src/main/java/cn/nosum/common/extension/ExtensionLoader.java
  10. 39 0
      src/main/java/cn/nosum/common/extension/factory/AdaptiveExtensionFactory.java
  11. 20 0
      src/main/java/cn/nosum/common/extension/factory/SpiExtensionFactory.java
  12. 10 0
      src/main/java/cn/nosum/common/http/entity/Context.java
  13. 47 0
      src/main/java/cn/nosum/common/util/ArrayUtils.java
  14. 271 0
      src/main/java/cn/nosum/common/util/ClassUtils.java
  15. 12 0
      src/main/java/cn/nosum/common/util/CollectionUtils.java
  16. 15 0
      src/main/java/cn/nosum/common/util/Holder.java
  17. 36 0
      src/main/java/cn/nosum/common/util/LinuxCmd.java
  18. 1 1
      src/main/java/cn/nosum/common/util/NettyFileUtil.java
  19. 17 0
      src/main/java/cn/nosum/common/util/ReflectUtils.java
  20. 11 0
      src/main/java/cn/nosum/common/util/StringUtils.java
  21. 10 5
      src/main/java/cn/nosum/gateway/container/NettyGatewayContainer.java
  22. 9 0
      src/main/java/cn/nosum/gateway/container/spi/GateWayContainer.java
  23. 5 0
      src/main/java/cn/nosum/gateway/entity/FileInfo.java
  24. 2 5
      src/main/java/cn/nosum/gateway/handler/FinalProcessHandler.java
  25. 1 1
      src/main/java/cn/nosum/gateway/handler/SlotProcessHandler.java
  26. 2 0
      src/main/java/cn/nosum/gateway/slot/FileProcessorSlotChain.java
  27. 2 0
      src/main/resources/META-INF/gateway/cn.nosum.common.extension.ExtensionFactory
  28. 1 0
      src/main/resources/META-INF/gateway/cn.nosum.gateway.container.spi.GateWayContainer

+ 42 - 0
pom.xml

@@ -33,4 +33,46 @@
         </dependency>
     </dependencies>
 
+
+
+    <build>
+        <finalName>nosum-gateway-v1</finalName>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <version>3.5.1</version>
+                <configuration>
+                    <source>1.8</source>
+                    <target>1.8</target>
+                    <encoding>UTF-8</encoding>
+                </configuration>
+            </plugin>
+            <!-- 打包可运行jar包 -->
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-assembly-plugin</artifactId>
+                <version>3.1.0</version>
+                <configuration>
+                    <archive>
+                        <manifest>
+                            <mainClass>cn.nosum.NoSumGateWayStart</mainClass>
+                        </manifest>
+                    </archive>
+                    <descriptorRefs>
+                        <descriptorRef>jar-with-dependencies</descriptorRef>
+                    </descriptorRefs>
+                </configuration>
+                <executions>
+                    <execution>
+                        <id>make-assembly</id>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>single</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
 </project>

+ 4 - 2
src/main/java/cn/nosum/NoSumGateWayStart.java

@@ -1,9 +1,11 @@
 package cn.nosum;
 
-import cn.nosum.gateway.container.NettyGatewayContainer;
+import cn.nosum.common.extension.ExtensionLoader;
+import cn.nosum.gateway.container.spi.GateWayContainer;
 
 public class NoSumGateWayStart {
     public static void main(String[] args) {
-        new NettyGatewayContainer().start();
+        GateWayContainer container = ExtensionLoader.getExtensionLoader(GateWayContainer.class).getAdaptiveExtension();
+        container.start();
     }
 }

+ 91 - 0
src/main/java/cn/nosum/common/annotation/Activate.java

@@ -0,0 +1,91 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 cn.nosum.common.annotation;
+
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Activate. This annotation is useful for automatically activate certain extensions with the given criteria,
+ * for examples: <code>@Activate</code> can be used to load certain <code>Filter</code> extension when there are
+ * multiple implementations.
+ * <ol>
+ * <li>{@link Activate#group()} specifies group criteria. Framework SPI defines the valid group values.
+ * <li>{@link Activate#value()} specifies parameter key in {@link URL} criteria.
+ * </ol>
+ * SPI provider can call {@link ExtensionLoader#getActivateExtension(URL, String, String)} to find out all activated
+ * extensions with the given criteria.
+ *
+ * @see SPI
+ * @see URL
+ * @see ExtensionLoader
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE, ElementType.METHOD})
+public @interface Activate {
+    /**
+     * Activate the current extension when one of the groups matches. The group passed into
+     * {@link ExtensionLoader#getActivateExtension(URL, String, String)} will be used for matching.
+     *
+     * @return group names to match
+     * @see ExtensionLoader#getActivateExtension(URL, String, String)
+     */
+    String[] group() default {};
+
+    /**
+     * Activate the current extension when the specified keys appear in the URL's parameters.
+     * <p>
+     * For example, given <code>@Activate("cache, validation")</code>, the current extension will be return only when
+     * there's either <code>cache</code> or <code>validation</code> key appeared in the URL's parameters.
+     * </p>
+     *
+     * @return URL parameter keys
+     * @see ExtensionLoader#getActivateExtension(URL, String)
+     * @see ExtensionLoader#getActivateExtension(URL, String, String)
+     */
+    String[] value() default {};
+
+    /**
+     * Relative ordering info, optional
+     * Deprecated since 2.7.0
+     *
+     * @return extension list which should be put before the current one
+     */
+    @Deprecated
+    String[] before() default {};
+
+    /**
+     * Relative ordering info, optional
+     * Deprecated since 2.7.0
+     *
+     * @return extension list which should be put after the current one
+     */
+    @Deprecated
+    String[] after() default {};
+
+    /**
+     * Absolute ordering info, optional
+     *
+     * @return absolute ordering info
+     */
+    int order() default 0;
+}

+ 38 - 0
src/main/java/cn/nosum/common/annotation/Adaptive.java

@@ -0,0 +1,38 @@
+package cn.nosum.common.annotation;
+
+import java.lang.annotation.*;
+
+/**
+ * Provide helpful information for {@link ExtensionLoader} to inject dependency extension instance.
+ *
+ * @see ExtensionLoader
+ * @see URL
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE, ElementType.METHOD})
+public @interface Adaptive {
+    /**
+     * Decide which target extension to be injected. The name of the target extension is decided by the parameter passed
+     * in the URL, and the parameter names are given by this method.
+     * <p>
+     * If the specified parameters are not found from {@link URL}, then the default extension will be used for
+     * dependency injection (specified in its interface's {@link SPI}).
+     * <p>
+     * For example, given <code>String[] {"key1", "key2"}</code>:
+     * <ol>
+     * <li>find parameter 'key1' in URL, use its value as the extension's name</li>
+     * <li>try 'key2' for extension's name if 'key1' is not found (or its value is empty) in URL</li>
+     * <li>use default extension if 'key2' doesn't exist either</li>
+     * <li>otherwise, throw {@link IllegalStateException}</li>
+     * </ol>
+     * If the parameter names are empty, then a default parameter name is generated from interface's
+     * class name with the rule: divide classname from capital char into several parts, and separate the parts with
+     * dot '.', for example, for {@code org.apache.dubbo.xxx.YyyInvokerWrapper}, the generated name is
+     * <code>String[] {"yyy.invoker.wrapper"}</code>.
+     *
+     * @return parameter names in URL
+     */
+    String[] value() default {};
+
+}

+ 9 - 0
src/main/java/cn/nosum/common/annotation/DisableInject.java

@@ -0,0 +1,9 @@
+package cn.nosum.common.annotation;
+
+import java.lang.annotation.*;
+
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE, ElementType.METHOD})
+public @interface DisableInject {
+}

+ 68 - 0
src/main/java/cn/nosum/common/annotation/Extension.java

@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 cn.nosum.common.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Marker for extension interface
+ * <p/>
+ * Changes on extension configuration file <br/>
+ * Use <code>Protocol</code> as an example, its configuration file 'META-INF/dubbo/com.xxx.Protocol' is changes from: <br/>
+ * <pre>
+ *     com.foo.XxxProtocol
+ *     com.foo.YyyProtocol
+ * </pre>
+ * <p>
+ * to key-value pair <br/>
+ * <pre>
+ *     xxx=com.foo.XxxProtocol
+ *     yyy=com.foo.YyyProtocol
+ * </pre>
+ * <br/>
+ * The reason for this change is:
+ * <p>
+ * If there's third party library referenced by static field or by method in extension implementation, its class will
+ * fail to initialize if the third party library doesn't exist. In this case, dubbo cannot figure out extension's id
+ * therefore cannot be able to map the exception information with the extension, if the previous format is used.
+ * <p/>
+ * For example:
+ * <p>
+ * Fails to load Extension("mina"). When user configure to use mina, dubbo will complain the extension cannot be loaded,
+ * instead of reporting which extract extension implementation fails and the extract reason.
+ * </p>
+ *
+ * @deprecated because it's too general, switch to use {@link org.apache.dubbo.common.extension.SPI}
+ */
+@Deprecated
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE})
+public @interface Extension {
+
+    /**
+     * @deprecated
+     */
+    @Deprecated
+    String value() default "";
+
+}

+ 15 - 0
src/main/java/cn/nosum/common/annotation/SPI.java

@@ -0,0 +1,15 @@
+package cn.nosum.common.annotation;
+
+import java.lang.annotation.*;
+
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE})
+public @interface SPI {
+
+    /**
+     * default extension name
+     */
+    String value() default "";
+
+}

+ 17 - 0
src/main/java/cn/nosum/common/extension/ExtensionFactory.java

@@ -0,0 +1,17 @@
+package cn.nosum.common.extension;
+
+import cn.nosum.common.annotation.SPI;
+
+@SPI
+public interface ExtensionFactory {
+
+    /**
+     * Get extension.
+     *
+     * @param type object type.
+     * @param name object name.
+     * @return object instance.
+     */
+    <T> T getExtension(Class<T> type, String name);
+
+}

+ 450 - 0
src/main/java/cn/nosum/common/extension/ExtensionLoader.java

@@ -0,0 +1,450 @@
+package cn.nosum.common.extension;
+
+import cn.nosum.common.annotation.Activate;
+import cn.nosum.common.annotation.Adaptive;
+import cn.nosum.common.annotation.DisableInject;
+import cn.nosum.common.annotation.SPI;
+import cn.nosum.common.util.*;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.regex.Pattern;
+
+/**
+ * Load gateway ExtensionLoader
+ * @param <T>
+ */
+public class ExtensionLoader<T> {
+    private static final Logger logger= LoggerFactory.getLogger(ExtensionLoader.class);
+
+    // 需要扫描的路径
+    private static final String GATEWAY_DIRECTORY = "META-INF/gateway/";
+
+    private static final Pattern NAME_SEPARATOR = Pattern.compile("\\s*[,]+\\s*");
+
+    // 缓存
+    private static final ConcurrentMap<Class<?>, ExtensionLoader<?>> EXTENSION_LOADERS = new ConcurrentHashMap<>();
+    private static final ConcurrentMap<Class<?>, Object> EXTENSION_INSTANCES = new ConcurrentHashMap<>();
+    private final Holder<Map<String, Class<?>>> cachedClasses = new Holder<>();
+    private final ConcurrentMap<Class<?>, String> cachedNames = new ConcurrentHashMap<>();
+    private final Holder<Object> cachedAdaptiveInstance = new Holder<>();
+    private final Map<String, Object> cachedActivates = new ConcurrentHashMap<>();
+    private final ConcurrentMap<String, Holder<Object>> cachedInstances = new ConcurrentHashMap<>();
+    private Set<Class<?>> cachedWrapperClasses;
+
+    private final ExtensionFactory objectFactory;
+    private volatile Class<?> cachedAdaptiveClass = null;
+    private final Class<?> type;
+    private String cachedDefaultName;
+    // 记录错误信息
+    private Map<String, IllegalStateException> exceptions = new ConcurrentHashMap<>();
+    private volatile Throwable createAdaptiveInstanceError;
+
+    private ExtensionLoader(Class<?> type) {
+        this.type = type;
+        objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
+    }
+
+    @SuppressWarnings("unchecked")
+    public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {
+        if (type == null) {
+            throw new IllegalArgumentException("Extension type == null");
+        }
+        if (!type.isInterface()) {
+            throw new IllegalArgumentException("Extension type (" + type + ") is not an interface!");
+        }
+        if (!withExtensionAnnotation(type)) {
+            throw new IllegalArgumentException("Extension type (" + type +
+                    ") is not an extension, because it is NOT annotated with @" + SPI.class.getSimpleName() + "!");
+        }
+
+        ExtensionLoader<T> loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
+        if (loader == null) {
+            EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader<T>(type));
+            loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
+        }
+        return loader;
+    }
+
+    @SuppressWarnings("unchecked")
+    public T getExtension(String name) {
+        if (StringUtils.isEmpty(name)) {
+            throw new IllegalArgumentException("Extension name == null");
+        }
+        if ("true".equals(name)) {
+            return getDefaultExtension();
+        }
+        final Holder<Object> holder = getOrCreateHolder(name);
+        Object instance = holder.get();
+        if (instance == null) {
+            synchronized (holder) {
+                instance = holder.get();
+                if (instance == null) {
+                    instance = createExtension(name);
+                    holder.set(instance);
+                }
+            }
+        }
+        return (T) instance;
+    }
+
+    private Holder<Object> getOrCreateHolder(String name) {
+        Holder<Object> holder = cachedInstances.get(name);
+        if (holder == null) {
+            cachedInstances.putIfAbsent(name, new Holder<>());
+            holder = cachedInstances.get(name);
+        }
+        return holder;
+    }
+
+    private T createExtension(String name) {
+        Class<?> clazz = getExtensionClasses().get(name);
+        if (clazz == null) {
+            throw new NullPointerException(name);
+        }
+        try {
+            T instance = (T) EXTENSION_INSTANCES.get(clazz);
+            if (instance == null) {
+                EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.newInstance());
+                instance = (T) EXTENSION_INSTANCES.get(clazz);
+            }
+            injectExtension(instance);
+            Set<Class<?>> wrapperClasses = cachedWrapperClasses;
+            if (CollectionUtils.isNotEmpty(wrapperClasses)) {
+                for (Class<?> wrapperClass : wrapperClasses) {
+                    instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
+                }
+            }
+            return instance;
+        } catch (Throwable t) {
+            throw new IllegalStateException("Extension instance (name: " + name + ", class: " +
+                    type + ") couldn't be instantiated: " + t.getMessage(), t);
+        }
+    }
+
+    /**
+     * 实现依赖注入
+     * @param instance 需要进行依赖注入的实例
+     */
+    private T injectExtension(T instance) {
+        try {
+            if (objectFactory != null) {
+                for (Method method : instance.getClass().getMethods()) {
+                    if (isSetter(method)) {
+                        // 存在 @DisableInject 则跳过
+                        if (method.getAnnotation(DisableInject.class) != null) {
+                            continue;
+                        }
+                        Class<?> pt = method.getParameterTypes()[0];
+                        if (ReflectUtils.isPrimitives(pt)) {
+                            continue;
+                        }
+                        try {
+                            String property = getSetterProperty(method);
+                            Object object = objectFactory.getExtension(pt, property);
+                            if (object != null) {
+                                method.invoke(instance, object);
+                            }
+                        } catch (Exception e) {
+                            logger.error("Failed to inject via method " + method.getName()
+                                    + " of interface " + type.getName() + ": " + e.getMessage(), e);
+                        }
+                    }
+                }
+            }
+        } catch (Exception e) {
+            logger.error(e.getMessage(), e);
+        }
+        return instance;
+    }
+
+
+    /**
+     * @return 根据默认扩展名获取到的实例
+     */
+    public T getDefaultExtension() {
+        getExtensionClasses();
+        if (StringUtils.isEmpty(cachedDefaultName) || "true".equals(cachedDefaultName)) {
+            return null;
+        }
+        return getExtension(cachedDefaultName);
+    }
+
+    /**
+     * @return 获取自适应扩展点
+     */
+    @SuppressWarnings("unchecked")
+    public T getAdaptiveExtension() {
+        Object instance = cachedAdaptiveInstance.get();
+        if (instance == null) {
+            if (createAdaptiveInstanceError == null) {
+                synchronized (cachedAdaptiveInstance) {
+                    instance = cachedAdaptiveInstance.get();
+                    if (instance == null) {
+                        try {
+                            instance = createAdaptiveExtension();
+                            cachedAdaptiveInstance.set(instance);
+                        } catch (Throwable t) {
+                            createAdaptiveInstanceError = t;
+                            throw new IllegalStateException("Failed to create adaptive instance: " + t.toString(), t);
+                        }
+                    }
+                }
+            } else {
+                throw new IllegalStateException("Failed to create adaptive instance: " + createAdaptiveInstanceError.toString(), createAdaptiveInstanceError);
+            }
+        }
+
+        return (T) instance;
+    }
+
+    @SuppressWarnings("unchecked")
+    private T createAdaptiveExtension() {
+        try {
+            return injectExtension((T) getAdaptiveExtensionClass().newInstance());
+        } catch (Exception e) {
+            throw new IllegalStateException("Can't create adaptive extension " + type + ", cause: " + e.getMessage(), e);
+        }
+    }
+
+    /**
+     * 获取自适应扩展点
+     */
+    private Class<?> getAdaptiveExtensionClass() {
+        getExtensionClasses();
+        if (cachedAdaptiveClass != null) {
+            return cachedAdaptiveClass;
+        }
+        return null;
+    }
+
+    private Map<String, Class<?>> getExtensionClasses() {
+        Map<String, Class<?>> classes = cachedClasses.get();
+        if (classes == null) {
+            synchronized (cachedClasses) {
+                classes = cachedClasses.get();
+                if (classes == null) {
+                    classes = loadExtensionClasses();
+                    cachedClasses.set(classes);
+                }
+            }
+        }
+        return classes;
+    }
+
+
+    /**
+     * 如果存在默认扩展名,提取并且缓存
+     */
+    private void cacheDefaultExtensionName() {
+        final SPI defaultAnnotation = type.getAnnotation(SPI.class);
+        if (defaultAnnotation != null) {
+            String value = defaultAnnotation.value();
+            if ((value = value.trim()).length() > 0) {
+                String[] names = NAME_SEPARATOR.split(value);
+                if (names.length > 1) {
+                    throw new IllegalStateException("More than 1 default extension name on extension "
+                            + type.getName() + ": "
+                            + Arrays.toString(names));
+                }
+                if (names.length == 1) {
+                    cachedDefaultName = names[0];
+                }
+            }
+        }
+    }
+
+    // synchronized in getExtensionClasses
+    private Map<String, Class<?>> loadExtensionClasses() {
+        cacheDefaultExtensionName();
+        Map<String, Class<?>> extensionClasses = new HashMap<>();
+        loadDirectory(extensionClasses, GATEWAY_DIRECTORY, type.getName());
+        return extensionClasses;
+    }
+
+    private void loadDirectory(Map<String, Class<?>> extensionClasses, String dir, String type) {
+        String fileName = dir + type;
+        try {
+            Enumeration<URL> urls;
+            ClassLoader classLoader = findClassLoader();
+            if (classLoader != null) {
+                urls = classLoader.getResources(fileName);
+            } else {
+                urls = ClassLoader.getSystemResources(fileName);
+            }
+            if (urls != null) {
+                while (urls.hasMoreElements()) {
+                    java.net.URL resourceURL = urls.nextElement();
+                    loadResource(extensionClasses, classLoader, resourceURL);
+                }
+            }
+        } catch (Throwable t) {
+            logger.error("Exception occurred when loading extension class (interface: " +
+                    type + ", description file: " + fileName + ").", t);
+        }
+    }
+
+    private void loadResource(Map<String, Class<?>> extensionClasses, ClassLoader classLoader, java.net.URL resourceURL) {
+        try {
+            try (BufferedReader reader = new BufferedReader(new InputStreamReader(resourceURL.openStream(), StandardCharsets.UTF_8))) {
+                String line;
+                while ((line = reader.readLine()) != null) {
+                    final int ci = line.indexOf('#');
+                    if (ci >= 0) {
+                        line = line.substring(0, ci);
+                    }
+                    line = line.trim();
+                    if (line.length() > 0) {
+                        try {
+                            String name = null;
+                            int i = line.indexOf('=');
+                            if (i > 0) {
+                                name = line.substring(0, i).trim();
+                                line = line.substring(i + 1).trim();
+                            }
+                            if (line.length() > 0) {
+                                loadClass(extensionClasses, resourceURL, Class.forName(line, true, classLoader), name);
+                            }
+                        } catch (Throwable t) {
+                            IllegalStateException e = new IllegalStateException("Failed to load extension class (interface: " + type + ", class line: " + line + ") in " + resourceURL + ", cause: " + t.getMessage(), t);
+                            exceptions.put(line, e);
+                        }
+                    }
+                }
+            }
+        } catch (Throwable t) {
+            logger.error("Exception occurred when loading extension class (interface: " +
+                    type + ", class file: " + resourceURL + ") in " + resourceURL, t);
+        }
+    }
+
+    /**
+     * cache name
+     */
+    private void cacheName(Class<?> clazz, String name) {
+        if (!cachedNames.containsKey(clazz)) {
+            cachedNames.put(clazz, name);
+        }
+    }
+
+    private void loadClass(Map<String, Class<?>> extensionClasses, java.net.URL resourceURL, Class<?> clazz, String name) throws NoSuchMethodException {
+        if (!type.isAssignableFrom(clazz)) {
+            throw new IllegalStateException("Error occurred when loading extension class (interface: " +
+                    type + ", class line: " + clazz.getName() + "), class "
+                    + clazz.getName() + " is not subtype of interface.");
+        }
+        if (clazz.isAnnotationPresent(Adaptive.class)) {
+            cacheAdaptiveClass(clazz);
+        } else if (isWrapperClass(clazz)) {
+            cacheWrapperClass(clazz);
+        } else {
+            clazz.getConstructor();
+            if (StringUtils.isEmpty(name)) {
+                name = findAnnotationName(clazz);
+                if (name.length() == 0) {
+                    throw new IllegalStateException("No such extension name for the class " + clazz.getName() + " in the config " + resourceURL);
+                }
+            }
+
+            String[] names = NAME_SEPARATOR.split(name);
+            if (ArrayUtils.isNotEmpty(names)) {
+                cacheActivateClass(clazz, names[0]);
+                for (String n : names) {
+                    cacheName(clazz, n);
+                    saveInExtensionClass(extensionClasses, clazz, n);
+                }
+            }
+        }
+    }
+
+    private void saveInExtensionClass(Map<String, Class<?>> extensionClasses, Class<?> clazz, String name) {
+        Class<?> c = extensionClasses.get(name);
+        if (c == null) {
+            extensionClasses.put(name, clazz);
+        } else if (c != clazz) {
+            throw new IllegalStateException("Duplicate extension " + type.getName() + " name " + name + " on " + c.getName() + " and " + clazz.getName());
+        }
+    }
+    @SuppressWarnings("deprecation")
+    private String findAnnotationName(Class<?> clazz) {
+        cn.nosum.common.annotation.Extension extension = clazz.getAnnotation(cn.nosum.common.annotation.Extension.class);
+        if (extension == null) {
+            String name = clazz.getSimpleName();
+            if (name.endsWith(type.getSimpleName())) {
+                name = name.substring(0, name.length() - type.getSimpleName().length());
+            }
+            return name.toLowerCase();
+        }
+        return extension.value();
+    }
+
+    private void cacheActivateClass(Class<?> clazz, String name) {
+        Activate activate = clazz.getAnnotation(Activate.class);
+        if (activate != null) {
+            cachedActivates.put(name, activate);
+        } else {
+            cn.nosum.common.annotation.Activate oldActivate = clazz.getAnnotation( cn.nosum.common.annotation.Activate.class);
+            if (oldActivate != null) {
+                cachedActivates.put(name, oldActivate);
+            }
+        }
+    }
+
+    private void cacheAdaptiveClass(Class<?> clazz) {
+        if (cachedAdaptiveClass == null) {
+            cachedAdaptiveClass = clazz;
+        } else if (!cachedAdaptiveClass.equals(clazz)) {
+            throw new IllegalStateException("More than 1 adaptive class found: "
+                    + cachedAdaptiveClass.getClass().getName()
+                    + ", " + clazz.getClass().getName());
+        }
+    }
+
+    private void cacheWrapperClass(Class<?> clazz) {
+        if (cachedWrapperClasses == null) {
+            cachedWrapperClasses = new HashSet<>();
+        }
+        cachedWrapperClasses.add(clazz);
+    }
+
+    private boolean isWrapperClass(Class<?> clazz) {
+        try {
+            clazz.getConstructor(type);
+            return true;
+        } catch (NoSuchMethodException e) {
+            return false;
+        }
+    }
+
+    private boolean isSetter(Method method) {
+        return method.getName().startsWith("set")
+                && method.getParameterTypes().length == 1
+                && Modifier.isPublic(method.getModifiers());
+    }
+
+    private static ClassLoader findClassLoader() {
+        return ClassUtils.getClassLoader(ExtensionLoader.class);
+    }
+
+    private static <T> boolean withExtensionAnnotation(Class<T> type) {
+        return type.isAnnotationPresent(SPI.class);
+    }
+
+    private String getSetterProperty(Method method) {
+        return method.getName().length() > 3 ? method.getName().substring(3, 4).toLowerCase() + method.getName().substring(4) : "";
+    }
+
+    public Set<String> getSupportedExtensions() {
+        Map<String, Class<?>> clazzes = getExtensionClasses();
+        return Collections.unmodifiableSet(new TreeSet<>(clazzes.keySet()));
+    }
+}

+ 39 - 0
src/main/java/cn/nosum/common/extension/factory/AdaptiveExtensionFactory.java

@@ -0,0 +1,39 @@
+package cn.nosum.common.extension.factory;
+
+import cn.nosum.common.annotation.Adaptive;
+import cn.nosum.common.extension.ExtensionFactory;
+import cn.nosum.common.extension.ExtensionLoader;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * AdaptiveExtensionFactory
+ */
+@Adaptive
+public class AdaptiveExtensionFactory implements ExtensionFactory {
+
+    private final List<ExtensionFactory> factories;
+
+    public AdaptiveExtensionFactory() {
+        ExtensionLoader<ExtensionFactory> loader = ExtensionLoader.getExtensionLoader(ExtensionFactory.class);
+        List<ExtensionFactory> list = new ArrayList<ExtensionFactory>();
+        for (String name : loader.getSupportedExtensions()) {
+            list.add(loader.getExtension(name));
+        }
+        factories = Collections.unmodifiableList(list);
+    }
+
+    @Override
+    public <T> T getExtension(Class<T> type, String name) {
+        for (ExtensionFactory factory : factories) {
+            T extension = factory.getExtension(type, name);
+            if (extension != null) {
+                return extension;
+            }
+        }
+        return null;
+    }
+
+}

+ 20 - 0
src/main/java/cn/nosum/common/extension/factory/SpiExtensionFactory.java

@@ -0,0 +1,20 @@
+package cn.nosum.common.extension.factory;
+
+import cn.nosum.common.annotation.SPI;
+import cn.nosum.common.extension.ExtensionFactory;
+import cn.nosum.common.extension.ExtensionLoader;
+
+public class SpiExtensionFactory implements ExtensionFactory {
+
+    @Override
+    public <T> T getExtension(Class<T> type, String name) {
+        if (type.isInterface() && type.isAnnotationPresent(SPI.class)) {
+            ExtensionLoader<T> loader = ExtensionLoader.getExtensionLoader(type);
+            if (!loader.getSupportedExtensions().isEmpty()) {
+                return loader.getAdaptiveExtension();
+            }
+        }
+        return null;
+    }
+
+}

+ 10 - 0
src/main/java/cn/nosum/common/http/entity/Context.java

@@ -1,9 +1,11 @@
 package cn.nosum.common.http.entity;
 
 
+
 public class Context {
     private Request request;
     private Response response;
+    private Object result;
 
     public Context(Request request, Response response) {
         this.request = request;
@@ -25,4 +27,12 @@ public class Context {
     public void setResponse(Response response) {
         this.response = response;
     }
+
+    public Object getResult() {
+        return result;
+    }
+
+    public void setResult(Object result) {
+        this.result = result;
+    }
 }

+ 47 - 0
src/main/java/cn/nosum/common/util/ArrayUtils.java

@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 cn.nosum.common.util;
+
+/**
+ * Contains some methods to check array.
+ */
+public final class ArrayUtils {
+
+    private ArrayUtils() {
+    }
+
+    /**
+     * <p>Checks if the array is null or empty. <p/>
+     *
+     * @param array th array to check
+     * @return {@code true} if the array is null or empty.
+     */
+    public static boolean isEmpty(final Object[] array) {
+        return array == null || array.length == 0;
+    }
+
+    /**
+     * <p>Checks if the array is not null or empty. <p/>
+     *
+     * @param array th array to check
+     * @return {@code true} if the array is not null or empty.
+     */
+    public static boolean isNotEmpty(final Object[] array) {
+        return !isEmpty(array);
+    }
+}

+ 271 - 0
src/main/java/cn/nosum/common/util/ClassUtils.java

@@ -0,0 +1,271 @@
+package cn.nosum.common.util;
+
+import java.lang.reflect.Array;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+public class ClassUtils {
+    /**
+     * Suffix for array class names: "[]"
+     */
+    public static final String ARRAY_SUFFIX = "[]";
+    /**
+     * Prefix for internal array class names: "[L"
+     */
+    private static final String INTERNAL_ARRAY_PREFIX = "[L";
+    /**
+     * Map with primitive type name as key and corresponding primitive type as
+     * value, for example: "int" -> "int.class".
+     */
+    private static final Map<String, Class<?>> PRIMITIVE_TYPE_NAME_MAP = new HashMap<String, Class<?>>(16);
+    /**
+     * Map with primitive wrapper type as key and corresponding primitive type
+     * as value, for example: Integer.class -> int.class.
+     */
+    private static final Map<Class<?>, Class<?>> PRIMITIVE_WRAPPER_TYPE_MAP = new HashMap<Class<?>, Class<?>>(8);
+
+    private static final char PACKAGE_SEPARATOR_CHAR = '.';
+
+    static {
+        PRIMITIVE_WRAPPER_TYPE_MAP.put(Boolean.class, boolean.class);
+        PRIMITIVE_WRAPPER_TYPE_MAP.put(Byte.class, byte.class);
+        PRIMITIVE_WRAPPER_TYPE_MAP.put(Character.class, char.class);
+        PRIMITIVE_WRAPPER_TYPE_MAP.put(Double.class, double.class);
+        PRIMITIVE_WRAPPER_TYPE_MAP.put(Float.class, float.class);
+        PRIMITIVE_WRAPPER_TYPE_MAP.put(Integer.class, int.class);
+        PRIMITIVE_WRAPPER_TYPE_MAP.put(Long.class, long.class);
+        PRIMITIVE_WRAPPER_TYPE_MAP.put(Short.class, short.class);
+
+        Set<Class<?>> primitiveTypeNames = new HashSet<>(16);
+        primitiveTypeNames.addAll(PRIMITIVE_WRAPPER_TYPE_MAP.values());
+        primitiveTypeNames.addAll(Arrays
+                .asList(boolean[].class, byte[].class, char[].class, double[].class,
+                        float[].class, int[].class, long[].class, short[].class));
+        for (Class<?> primitiveTypeName : primitiveTypeNames) {
+            PRIMITIVE_TYPE_NAME_MAP.put(primitiveTypeName.getName(), primitiveTypeName);
+        }
+    }
+
+    public static Class<?> forNameWithThreadContextClassLoader(String name)
+            throws ClassNotFoundException {
+        return forName(name, Thread.currentThread().getContextClassLoader());
+    }
+
+    public static Class<?> forNameWithCallerClassLoader(String name, Class<?> caller)
+            throws ClassNotFoundException {
+        return forName(name, caller.getClassLoader());
+    }
+
+    public static ClassLoader getCallerClassLoader(Class<?> caller) {
+        return caller.getClassLoader();
+    }
+
+    /**
+     * get class loader
+     *
+     * @param clazz
+     * @return class loader
+     */
+    public static ClassLoader getClassLoader(Class<?> clazz) {
+        ClassLoader cl = null;
+        try {
+            cl = Thread.currentThread().getContextClassLoader();
+        } catch (Throwable ex) {
+            // Cannot access thread context ClassLoader - falling back to system class loader...
+        }
+        if (cl == null) {
+            // No thread context class loader -> use class loader of this class.
+            cl = clazz.getClassLoader();
+            if (cl == null) {
+                // getClassLoader() returning null indicates the bootstrap ClassLoader
+                try {
+                    cl = ClassLoader.getSystemClassLoader();
+                } catch (Throwable ex) {
+                    // Cannot access system ClassLoader - oh well, maybe the caller can live with null...
+                }
+            }
+        }
+
+        return cl;
+    }
+
+    /**
+     * Return the default ClassLoader to use: typically the thread context
+     * ClassLoader, if available; the ClassLoader that loaded the ClassUtils
+     * class will be used as fallback.
+     * <p>
+     * Call this method if you intend to use the thread context ClassLoader in a
+     * scenario where you absolutely need a non-null ClassLoader reference: for
+     * example, for class path resource loading (but not necessarily for
+     * <code>Class.forName</code>, which accepts a <code>null</code> ClassLoader
+     * reference as well).
+     *
+     * @return the default ClassLoader (never <code>null</code>)
+     * @see java.lang.Thread#getContextClassLoader()
+     */
+    public static ClassLoader getClassLoader() {
+        return getClassLoader(ClassUtils.class);
+    }
+
+    /**
+     * Same as <code>Class.forName()</code>, except that it works for primitive
+     * types.
+     */
+    public static Class<?> forName(String name) throws ClassNotFoundException {
+        return forName(name, getClassLoader());
+    }
+
+    /**
+     * Replacement for <code>Class.forName()</code> that also returns Class
+     * instances for primitives (like "int") and array class names (like
+     * "String[]").
+     *
+     * @param name        the name of the Class
+     * @param classLoader the class loader to use (may be <code>null</code>,
+     *                    which indicates the default class loader)
+     * @return Class instance for the supplied name
+     * @throws ClassNotFoundException if the class was not found
+     * @throws LinkageError           if the class file could not be loaded
+     * @see Class#forName(String, boolean, ClassLoader)
+     */
+    public static Class<?> forName(String name, ClassLoader classLoader)
+            throws ClassNotFoundException, LinkageError {
+
+        Class<?> clazz = resolvePrimitiveClassName(name);
+        if (clazz != null) {
+            return clazz;
+        }
+
+        // "java.lang.String[]" style arrays
+        if (name.endsWith(ARRAY_SUFFIX)) {
+            String elementClassName = name.substring(0, name.length() - ARRAY_SUFFIX.length());
+            Class<?> elementClass = forName(elementClassName, classLoader);
+            return Array.newInstance(elementClass, 0).getClass();
+        }
+
+        // "[Ljava.lang.String;" style arrays
+        int internalArrayMarker = name.indexOf(INTERNAL_ARRAY_PREFIX);
+        if (internalArrayMarker != -1 && name.endsWith(";")) {
+            String elementClassName = null;
+            if (internalArrayMarker == 0) {
+                elementClassName = name
+                        .substring(INTERNAL_ARRAY_PREFIX.length(), name.length() - 1);
+            } else if (name.startsWith("[")) {
+                elementClassName = name.substring(1);
+            }
+            Class<?> elementClass = forName(elementClassName, classLoader);
+            return Array.newInstance(elementClass, 0).getClass();
+        }
+
+        ClassLoader classLoaderToUse = classLoader;
+        if (classLoaderToUse == null) {
+            classLoaderToUse = getClassLoader();
+        }
+        return classLoaderToUse.loadClass(name);
+    }
+
+    /**
+     * Resolve the given class name as primitive class, if appropriate,
+     * according to the JVM's naming rules for primitive classes.
+     * <p>
+     * Also supports the JVM's internal class names for primitive arrays. Does
+     * <i>not</i> support the "[]" suffix notation for primitive arrays; this is
+     * only supported by {@link #forName}.
+     *
+     * @param name the name of the potentially primitive class
+     * @return the primitive class, or <code>null</code> if the name does not
+     * denote a primitive class or primitive array class
+     */
+    public static Class<?> resolvePrimitiveClassName(String name) {
+        Class<?> result = null;
+        // Most class names will be quite long, considering that they
+        // SHOULD sit in a package, so a length check is worthwhile.
+        if (name != null && name.length() <= 8) {
+            // Could be a primitive - likely.
+            result = (Class<?>) PRIMITIVE_TYPE_NAME_MAP.get(name);
+        }
+        return result;
+    }
+
+    public static String toShortString(Object obj) {
+        if (obj == null) {
+            return "null";
+        }
+        return obj.getClass().getSimpleName() + "@" + System.identityHashCode(obj);
+
+    }
+
+    public static String simpleClassName(Class<?> clazz) {
+        if (clazz == null) {
+            throw new NullPointerException("clazz");
+        }
+        String className = clazz.getName();
+        final int lastDotIdx = className.lastIndexOf(PACKAGE_SEPARATOR_CHAR);
+        if (lastDotIdx > -1) {
+            return className.substring(lastDotIdx + 1);
+        }
+        return className;
+    }
+
+
+    public static boolean isPrimitive(Class<?> type) {
+        return type.isPrimitive()
+                || type == String.class
+                || type == Character.class
+                || type == Boolean.class
+                || type == Byte.class
+                || type == Short.class
+                || type == Integer.class
+                || type == Long.class
+                || type == Float.class
+                || type == Double.class
+                || type == Object.class;
+    }
+
+    public static Object convertPrimitive(Class<?> type, String value) {
+        if (value == null) {
+            return null;
+        } else if (type == char.class || type == Character.class) {
+            return value.length() > 0 ? value.charAt(0) : '\0';
+        } else if (type == boolean.class || type == Boolean.class) {
+            return Boolean.valueOf(value);
+        }
+        try {
+            if (type == byte.class || type == Byte.class) {
+                return Byte.valueOf(value);
+            } else if (type == short.class || type == Short.class) {
+                return Short.valueOf(value);
+            } else if (type == int.class || type == Integer.class) {
+                return Integer.valueOf(value);
+            } else if (type == long.class || type == Long.class) {
+                return Long.valueOf(value);
+            } else if (type == float.class || type == Float.class) {
+                return Float.valueOf(value);
+            } else if (type == double.class || type == Double.class) {
+                return Double.valueOf(value);
+            }
+        } catch (NumberFormatException e) {
+            return null;
+        }
+        return value;
+    }
+
+
+    /**
+     * We only check boolean value at this moment.
+     *
+     * @param type
+     * @param value
+     * @return
+     */
+    public static boolean isTypeMatch(Class<?> type, String value) {
+        if ((type == boolean.class || type == Boolean.class)
+                && !("true".equals(value) || "false".equals(value))) {
+            return false;
+        }
+        return true;
+    }
+}

+ 12 - 0
src/main/java/cn/nosum/common/util/CollectionUtils.java

@@ -0,0 +1,12 @@
+package cn.nosum.common.util;
+
+import java.util.Collection;
+
+public class CollectionUtils {
+    public static boolean isEmpty(Collection<?> collection) {
+        return collection == null || collection.isEmpty();
+    }
+    public static boolean isNotEmpty(Collection<?> collection) {
+        return !isEmpty(collection);
+    }
+}

+ 15 - 0
src/main/java/cn/nosum/common/util/Holder.java

@@ -0,0 +1,15 @@
+package cn.nosum.common.util;
+
+public class Holder<T> {
+
+    private volatile T value;
+
+    public void set(T value) {
+        this.value = value;
+    }
+
+    public T get() {
+        return value;
+    }
+
+}

+ 36 - 0
src/main/java/cn/nosum/common/util/LinuxCmd.java

@@ -0,0 +1,36 @@
+package cn.nosum.common.util;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+
+public class LinuxCmd {
+    public static Logger logger= LoggerFactory.getLogger(LinuxCmd.class);
+
+    public static String executeLinuxCmd(String cmd) {
+        logger.debug("执行命令:{}",cmd);
+        Runtime run = Runtime.getRuntime();
+        try {
+            Process process = run.exec(cmd);
+            String line;
+            BufferedReader stdoutReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
+            StringBuffer out = new StringBuffer();
+            while ((line = stdoutReader.readLine()) != null ) {
+                out.append(line);
+            }
+            try {
+                process.waitFor();
+            } catch (InterruptedException e) {
+                e.printStackTrace();
+            }
+            process.destroy();
+            return out.toString();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+}

+ 1 - 1
src/main/java/cn/nosum/common/util/NettyFileUtil.java

@@ -53,7 +53,7 @@ public class NettyFileUtil {
     }
 
     /**
-     * 读取文件信息
+     * 读取文件内容
      * @param filePath 目标文件路径
      * @return 文件内容
      */

+ 17 - 0
src/main/java/cn/nosum/common/util/ReflectUtils.java

@@ -0,0 +1,17 @@
+package cn.nosum.common.util;
+
+import java.util.Date;
+
+public final class ReflectUtils {
+    public static boolean isPrimitives(Class<?> cls) {
+        if (cls.isArray()) {
+            return isPrimitive(cls.getComponentType());
+        }
+        return isPrimitive(cls);
+    }
+
+    public static boolean isPrimitive(Class<?> cls) {
+        return cls.isPrimitive() || cls == String.class || cls == Boolean.class || cls == Character.class
+                || Number.class.isAssignableFrom(cls) || Date.class.isAssignableFrom(cls);
+    }
+}

+ 11 - 0
src/main/java/cn/nosum/common/util/StringUtils.java

@@ -0,0 +1,11 @@
+
+package cn.nosum.common.util;
+
+public final class StringUtils {
+    private StringUtils(){}
+
+    public static boolean isEmpty(String str) {
+        return str == null || str.isEmpty();
+    }
+
+}

+ 10 - 5
src/main/java/cn/nosum/gateway/container/NettyGatewayContainer.java

@@ -1,5 +1,7 @@
 package cn.nosum.gateway.container;
 
+import cn.nosum.common.annotation.Adaptive;
+import cn.nosum.gateway.container.spi.GateWayContainer;
 import cn.nosum.gateway.handler.FinalProcessHandler;
 import cn.nosum.gateway.handler.FullHttpRequestHandler;
 import cn.nosum.gateway.handler.PreProcessHandler;
@@ -12,16 +14,19 @@ import io.netty.channel.socket.nio.NioServerSocketChannel;
 import io.netty.handler.codec.http.HttpObjectAggregator;
 import io.netty.handler.codec.http.HttpRequestDecoder;
 import io.netty.handler.codec.http.HttpResponseEncoder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 
-//Netty就是一个同时支持多协议的网络通信框架
-public class NettyGatewayContainer {
+@Adaptive
+public class NettyGateWayContainer implements GateWayContainer {
+	Logger logger= LoggerFactory.getLogger(NettyGateWayContainer.class);
 	private int port = 8888;
 	public void start(){
 		// Boss线程
-		EventLoopGroup bossGroup = new NioEventLoopGroup(6);
+		EventLoopGroup bossGroup = new NioEventLoopGroup();
 		// Worker线程
-		EventLoopGroup workerGroup = new NioEventLoopGroup(12);
+		EventLoopGroup workerGroup = new NioEventLoopGroup();
 		try {
 			ServerBootstrap server = new ServerBootstrap();
 			server.group(bossGroup, workerGroup)
@@ -48,7 +53,7 @@ public class NettyGatewayContainer {
 
 			// 启动服务器
 			ChannelFuture f = server.bind(port).sync();
-			System.out.println("已启动,监听的端口是:" + port);
+			logger.debug("NettyGateWayContainer启动成功,访问端口号是:{}",port);
 			f.channel().closeFuture().sync();
 		}catch (Exception e){
 			e.printStackTrace();

+ 9 - 0
src/main/java/cn/nosum/gateway/container/spi/GateWayContainer.java

@@ -0,0 +1,9 @@
+package cn.nosum.gateway.container.spi;
+
+
+import cn.nosum.common.annotation.SPI;
+
+@SPI("netty")
+public interface GateWayContainer {
+    public void start();
+}

+ 5 - 0
src/main/java/cn/nosum/gateway/entity/FileInfo.java

@@ -0,0 +1,5 @@
+package cn.nosum.gateway.entity;
+
+public class FileInfo {
+
+}

+ 2 - 5
src/main/java/cn/nosum/gateway/handler/FinalProcessHandler.java

@@ -1,9 +1,7 @@
 package cn.nosum.gateway.handler;
 
 import cn.nosum.common.dto.ResultInfo;
-import cn.nosum.common.enums.ResultEnum;
 import cn.nosum.common.http.entity.Context;
-import cn.nosum.common.http.entity.Response;
 import io.netty.channel.ChannelHandlerContext;
 import io.netty.channel.SimpleChannelInboundHandler;
 
@@ -11,9 +9,8 @@ public class FinalProcessHandler extends SimpleChannelInboundHandler<Context> {
 
     @Override
     protected void channelRead0(ChannelHandlerContext ctx, Context context) throws Exception {
-        Response response = context.getResponse();
-        // 实际业务处理
-        response.write(ResultInfo.valueOf(ResultEnum.SUCCESS));
+        // TODO 这里直接使用了 stat 脚本返回值作为输出,实际处理应该更为复杂
+        context.getResponse().write(ResultInfo.valueOf(context.getResult()));
     }
 
     @Override

+ 1 - 1
src/main/java/cn/nosum/gateway/handler/SlotProcessHandler.java

@@ -16,7 +16,7 @@ public class SlotProcessHandler extends SimpleChannelInboundHandler<Context> {
 
     @Override
     protected void channelRead0(ChannelHandlerContext ctx, Context context) throws Exception {
-        // TODO 进行过滤链的执行
+        // TODO 进行过滤链的执行,应该使用扩展点实现获取
         ProcessorSlot<Context> chain = SlotChainProvider.newSlotChain();
         try {
             chain.exec(context);

+ 2 - 0
src/main/java/cn/nosum/gateway/slot/FileProcessorSlotChain.java

@@ -1,6 +1,7 @@
 package cn.nosum.gateway.slot;
 
 import cn.nosum.common.http.entity.Context;
+import cn.nosum.common.util.LinuxCmd;
 import cn.nosum.common.util.NettyFileUtil;
 import cn.nosum.gateway.chain.AbstractLinkedProcessorSlot;
 import com.alibaba.fastjson.JSON;
@@ -12,6 +13,7 @@ public class FileProcessorSlotChain extends AbstractLinkedProcessorSlot<Context>
     @Override
     public void exec(Context context) throws Throwable {
         NettyFileUtil.dataToFile(JSON.toJSONString(context.getRequest().getParameters()), context.getRequest().getUrl(), true);
+        context.setResult(LinuxCmd.executeLinuxCmd("stat "+context.getRequest().getUrl()));
         fireExec(context);
     }
 }

+ 2 - 0
src/main/resources/META-INF/gateway/cn.nosum.common.extension.ExtensionFactory

@@ -0,0 +1,2 @@
+adaptive=cn.nosum.common.extension.factory.AdaptiveExtensionFactory
+spi=cn.nosum.common.extension.factory.SpiExtensionFactory

+ 1 - 0
src/main/resources/META-INF/gateway/cn.nosum.gateway.container.spi.GateWayContainer

@@ -0,0 +1 @@
+netty=cn.nosum.gateway.container.NettyGateWayContainer