diff --git a/.gitignore b/.gitignore
index a1c2a238a965f004ff76978ac1086aa6fe95caea..68943664002a1e1fed1cb2d19b757d37702ea5b2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,7 +3,9 @@
# Log file
*.log
-
+target
+.idea
+*.iml
# BlueJ files
*.ctxt
diff --git a/HELP.md b/HELP.md
new file mode 100644
index 0000000000000000000000000000000000000000..95b578085588c3767d5f2b3c5d7c717fe37445d5
--- /dev/null
+++ b/HELP.md
@@ -0,0 +1,19 @@
+# Getting Started
+
+### Reference Documentation
+
+For further reference, please consider the following sections:
+
+* [Official Apache Maven documentation](https://maven.apache.org/guides/index.html)
+* [Spring Boot Maven Plugin Reference Guide](https://docs.spring.io/spring-boot/docs/2.6.13/maven-plugin/reference/html/)
+* [Create an OCI image](https://docs.spring.io/spring-boot/docs/2.6.13/maven-plugin/reference/html/#build-image)
+* [Spring Web](https://docs.spring.io/spring-boot/docs/2.6.13/reference/htmlsingle/#web)
+
+### Guides
+
+The following guides illustrate how to use some features concretely:
+
+* [Building a RESTful Web Service](https://spring.io/guides/gs/rest-service/)
+* [Serving Web Content with Spring MVC](https://spring.io/guides/gs/serving-web-content/)
+* [Building REST services with Spring](https://spring.io/guides/tutorials/rest/)
+
diff --git a/plugin/lib/jar.txt b/plugin/lib/jar.txt
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000000000000000000000000000000000000..2f9352660c0dbf553a114168d58e1be9614ed993
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,108 @@
+
+
+ 4.0.0
+ com.example
+ plugin-manager
+ 0.0.1-SNAPSHOT
+ plugin-manager
+ plugin-manager
+
+ 1.8
+ UTF-8
+ UTF-8
+ 2.6.13
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.springframework.boot
+ spring-boot-configuration-processor
+ true
+ provided
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+ org.example
+ plugin-core
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-dependencies
+ ${spring-boot.version}
+ pom
+ import
+
+
+ org.example
+ plugin-core
+ 1.0-SNAPSHOT
+
+
+
+
+
+ dev
+
+ dev
+
+
+
+ test
+
+ test
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.8.1
+
+ 1.8
+ 1.8
+ UTF-8
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+ ${spring-boot.version}
+
+ com.example.plugin.PluginManagerApplication
+
+
+
+ repackage
+
+ repackage
+
+
+
+
+
+
+
+ src/main/resources
+ true
+
+ **/*.yml
+
+
+
+
+
+
diff --git a/src/main/java/com/example/plugin/PluginManagerApplication.java b/src/main/java/com/example/plugin/PluginManagerApplication.java
new file mode 100644
index 0000000000000000000000000000000000000000..a8d2d4569ecedd4810ce70da0535b4313c0ce314
--- /dev/null
+++ b/src/main/java/com/example/plugin/PluginManagerApplication.java
@@ -0,0 +1,33 @@
+package com.example.plugin;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.ConfigurableApplicationContext;
+
+import java.net.Inet4Address;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+@SpringBootApplication
+public class PluginManagerApplication {
+
+ public static void main(String[] args) {
+ ConfigurableApplicationContext context = SpringApplication.run(PluginManagerApplication.class, args);
+ try {
+ InetAddress localhost = Inet4Address.getLocalHost();
+ String port = context.getEnvironment().getProperty("server.port");
+ System.out.println("**************************************************");
+ System.out.println("** 系统启动成功! **");
+ System.out.printf("** 访问地址:http://%s:%s **\n"
+ ,localhost.getHostAddress(),port);
+ System.out.printf("** http://127.0.0.1:%s **\n",port);
+ System.out.println("**************************************************");
+
+ } catch (UnknownHostException e) {
+ e.printStackTrace();
+ }
+
+
+ }
+}
diff --git a/src/main/java/com/example/plugin/controller/Controller.java b/src/main/java/com/example/plugin/controller/Controller.java
new file mode 100644
index 0000000000000000000000000000000000000000..2d73bae6cbcc29306a204826b4bc86dbbfe00186
--- /dev/null
+++ b/src/main/java/com/example/plugin/controller/Controller.java
@@ -0,0 +1,39 @@
+package com.example.plugin.controller;
+
+import cn.lyz.plugin.IHello;
+import com.example.plugin.utils.PluginClassLoader;
+import com.example.plugin.utils.PluginUtils;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.lang.reflect.InvocationTargetException;
+
+@RestController
+@RequestMapping("plugin")
+public class Controller {
+
+ private static final String JAR_PATH ="plugin/lib/hello.jar";
+
+ @GetMapping("load")
+ public Object jarLoad() {
+ PluginUtils.load(JAR_PATH);
+ return "插件加载完成";
+ }
+
+ @GetMapping("unload")
+ public Object unloadJar() {
+ PluginUtils.unload(JAR_PATH);
+ return "插件卸载成功";
+ }
+
+ @GetMapping("run")
+ public Object classExists() throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
+ PluginClassLoader classLoader = PluginUtils.get(JAR_PATH);
+ Class> helloClass = classLoader.loadClass("org.example.plugin.Hello");
+ IHello hello = (IHello) helloClass.getDeclaredConstructor().newInstance();
+ hello.say();
+ hello.say("plugin");
+ return "插件执行完成";
+ }
+}
diff --git a/src/main/java/com/example/plugin/demos/web/BasicController.java b/src/main/java/com/example/plugin/demos/web/BasicController.java
new file mode 100644
index 0000000000000000000000000000000000000000..e14c2dab3c9909b3a1f538cbc5eb7c8df4d033fa
--- /dev/null
+++ b/src/main/java/com/example/plugin/demos/web/BasicController.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2013-2018 the original author or authors.
+ *
+ * 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
+ *
+ * https://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.example.plugin.demos.web;
+
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.ModelAttribute;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+/**
+ * @author theonefx
+ */
+@Controller
+public class BasicController {
+
+ // http://127.0.0.1:8080/hello?name=lisi
+ @RequestMapping("/hello")
+ @ResponseBody
+ public String hello(@RequestParam(name = "name", defaultValue = "unknown user") String name) {
+ return "Hello " + name;
+ }
+
+ // http://127.0.0.1:8080/user
+ @RequestMapping("/user")
+ @ResponseBody
+ public User user() {
+ User user = new User();
+ user.setName("theonefx");
+ user.setAge(666);
+ return user;
+ }
+
+ // http://127.0.0.1:8080/save_user?name=newName&age=11
+ @RequestMapping("/save_user")
+ @ResponseBody
+ public String saveUser(User u) {
+ return "user will save: name=" + u.getName() + ", age=" + u.getAge();
+ }
+
+ // http://127.0.0.1:8080/html
+ @RequestMapping("/html")
+ public String html() {
+ return "index.html";
+ }
+
+ @ModelAttribute
+ public void parseUser(@RequestParam(name = "name", defaultValue = "unknown user") String name
+ , @RequestParam(name = "age", defaultValue = "12") Integer age, User user) {
+ user.setName("zhangsan");
+ user.setAge(18);
+ }
+}
diff --git a/src/main/java/com/example/plugin/demos/web/PathVariableController.java b/src/main/java/com/example/plugin/demos/web/PathVariableController.java
new file mode 100644
index 0000000000000000000000000000000000000000..05bdfa30edba25b8b4d7b5610e418ccfa97d6bd2
--- /dev/null
+++ b/src/main/java/com/example/plugin/demos/web/PathVariableController.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2013-2018 the original author or authors.
+ *
+ * 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
+ *
+ * https://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.example.plugin.demos.web;
+
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+/**
+ * @author theonefx
+ */
+@Controller
+public class PathVariableController {
+
+ // http://127.0.0.1:8080/user/123/roles/222
+ @RequestMapping(value = "/user/{userId}/roles/{roleId}", method = RequestMethod.GET)
+ @ResponseBody
+ public String getLogin(@PathVariable("userId") String userId, @PathVariable("roleId") String roleId) {
+ return "User Id : " + userId + " Role Id : " + roleId;
+ }
+
+ // http://127.0.0.1:8080/javabeat/somewords
+ @RequestMapping(value = "/javabeat/{regexp1:[a-z-]+}", method = RequestMethod.GET)
+ @ResponseBody
+ public String getRegExp(@PathVariable("regexp1") String regexp1) {
+ return "URI Part : " + regexp1;
+ }
+}
diff --git a/src/main/java/com/example/plugin/demos/web/User.java b/src/main/java/com/example/plugin/demos/web/User.java
new file mode 100644
index 0000000000000000000000000000000000000000..549b744e5dd77af836d6164a2f14c2fe55f9ed75
--- /dev/null
+++ b/src/main/java/com/example/plugin/demos/web/User.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2013-2018 the original author or authors.
+ *
+ * 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
+ *
+ * https://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.example.plugin.demos.web;
+
+/**
+ * @author theonefx
+ */
+public class User {
+
+ private String name;
+
+ private Integer age;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public Integer getAge() {
+ return age;
+ }
+
+ public void setAge(Integer age) {
+ this.age = age;
+ }
+}
diff --git a/src/main/java/com/example/plugin/properties/SystemEnv.java b/src/main/java/com/example/plugin/properties/SystemEnv.java
new file mode 100644
index 0000000000000000000000000000000000000000..73e0ea0b9d313b9920f16e19d612eb1aee479051
--- /dev/null
+++ b/src/main/java/com/example/plugin/properties/SystemEnv.java
@@ -0,0 +1,19 @@
+package com.example.plugin.properties;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+@Component
+@ConfigurationProperties(prefix = "env")
+public class SystemEnv {
+
+ public String name;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+}
diff --git a/src/main/java/com/example/plugin/run/StartInit.java b/src/main/java/com/example/plugin/run/StartInit.java
new file mode 100644
index 0000000000000000000000000000000000000000..2b5157051fc58dd2260db0d8b29c36bc1eab7bb4
--- /dev/null
+++ b/src/main/java/com/example/plugin/run/StartInit.java
@@ -0,0 +1,21 @@
+package com.example.plugin.run;
+
+import com.example.plugin.properties.SystemEnv;
+import org.springframework.boot.ApplicationArguments;
+import org.springframework.boot.ApplicationRunner;
+import org.springframework.stereotype.Component;
+
+@Component
+public class StartInit implements ApplicationRunner {
+
+ private final SystemEnv systemEnv;
+
+ public StartInit(SystemEnv systemEnv) {
+ this.systemEnv = systemEnv;
+ }
+
+ @Override
+ public void run(ApplicationArguments args) throws Exception {
+ System.out.println("当前环境:"+systemEnv.getName());
+ }
+}
diff --git a/src/main/java/com/example/plugin/utils/PluginClassLoader.java b/src/main/java/com/example/plugin/utils/PluginClassLoader.java
new file mode 100644
index 0000000000000000000000000000000000000000..9a58672951b30e5a67835f2cd4148dc8d916e80a
--- /dev/null
+++ b/src/main/java/com/example/plugin/utils/PluginClassLoader.java
@@ -0,0 +1,16 @@
+package com.example.plugin.utils;
+
+import java.net.URL;
+import java.net.URLClassLoader;
+
+public class PluginClassLoader extends URLClassLoader {
+
+ public PluginClassLoader(URL[] urls) {
+ super(urls);
+ }
+
+ @Override
+ protected void addURL(URL url) {
+ super.addURL(url);
+ }
+}
diff --git a/src/main/java/com/example/plugin/utils/PluginUtils.java b/src/main/java/com/example/plugin/utils/PluginUtils.java
new file mode 100644
index 0000000000000000000000000000000000000000..d119bec3d7454142a5bc59fcfd90bb4e77a14a1d
--- /dev/null
+++ b/src/main/java/com/example/plugin/utils/PluginUtils.java
@@ -0,0 +1,66 @@
+package com.example.plugin.utils;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Map;
+
+public class PluginUtils {
+
+ private static final Map classloaders = new HashMap<>();
+
+ /**
+ * 加载JAR
+ * @param url 相对路径
+ */
+ public static PluginClassLoader load(String url) {
+ File jarFile = new File(url);
+ if(!jarFile.exists()){
+ try {
+ throw new RuntimeException(String.format("%s插件不存在",jarFile.toURI().toURL()));
+ } catch (MalformedURLException e) {
+ e.printStackTrace();
+ }
+ }
+ PluginClassLoader loader = new PluginClassLoader(new URL[]{});
+ try {
+ loader.addURL(jarFile.toURI().toURL());
+ } catch (MalformedURLException e) {
+ e.printStackTrace();
+ }
+ classloaders.put(url,loader);
+ return loader;
+ }
+
+ /**
+ * 获取对应的classloader
+ * @param url 相对路径
+ * @return PluginClassLoader
+ */
+ public static PluginClassLoader get(String url){
+ if(!classloaders.containsKey(url)){
+ throw new RuntimeException("插件未加载");
+ }
+ return classloaders.get(url);
+ }
+
+ /**
+ * 卸载jar
+ * @param url 相对路径
+ */
+ public static void unload(String url){
+ if(classloaders.containsKey(url)){
+ PluginClassLoader classLoader = classloaders.get(url);
+ try {
+ classLoader.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ classloaders.remove(url);
+ }else{
+ throw new RuntimeException(String.format("插件“%s”未加载",url));
+ }
+ }
+}
diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml
new file mode 100644
index 0000000000000000000000000000000000000000..6655beefac0ea38466c12a5d18e1c30909ad082f
--- /dev/null
+++ b/src/main/resources/application-dev.yml
@@ -0,0 +1,3 @@
+# 应用服务 WEB 访问端口
+env:
+ name: dev
\ No newline at end of file
diff --git a/src/main/resources/application-test.yml b/src/main/resources/application-test.yml
new file mode 100644
index 0000000000000000000000000000000000000000..e0dcaef2fd3acb992a805919da4a5cc1a9926910
--- /dev/null
+++ b/src/main/resources/application-test.yml
@@ -0,0 +1,3 @@
+# 应用服务 WEB 访问端口
+env:
+ name: test
\ No newline at end of file
diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml
new file mode 100644
index 0000000000000000000000000000000000000000..9cfdb048e65b08f2e69b5f14ebe5efe9cbf8f1ba
--- /dev/null
+++ b/src/main/resources/application.yml
@@ -0,0 +1,14 @@
+# 应用服务 WEB 访问端口
+spring:
+ profiles:
+ active: @profiles.active@
+
+server:
+ port: 8080
+ ssl:
+ enabled: false
+ key-store: file:E:/demo.old.jks
+ key-store-type: JKS
+ key-alias: demo
+ key-password: 123456@key
+ key-store-password: 123456@store
\ No newline at end of file
diff --git a/src/main/resources/static/index.html b/src/main/resources/static/index.html
new file mode 100644
index 0000000000000000000000000000000000000000..89bb8ba4ff248cd6e3b8b5e2f89af4e3062a37a8
--- /dev/null
+++ b/src/main/resources/static/index.html
@@ -0,0 +1,6 @@
+
+
+hello word!!!
+this is a html page
+
+
\ No newline at end of file
diff --git a/src/test/java/com/example/plugin/PluginManagerApplicationTests.java b/src/test/java/com/example/plugin/PluginManagerApplicationTests.java
new file mode 100644
index 0000000000000000000000000000000000000000..0aad6430bb78bb3f619bde461b2d48f4630fb87a
--- /dev/null
+++ b/src/test/java/com/example/plugin/PluginManagerApplicationTests.java
@@ -0,0 +1,13 @@
+package com.example.plugin;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+
+class PluginManagerApplicationTests {
+
+ @Test
+ void contextLoads() {
+ System.out.println(String.format("%03d",12345));
+ }
+
+}