diff --git a/README.md b/README.md
index 38ab7bce0a48d56257c908ac7e7919eeed2d2c60..82d6e55e787aaabc809bd5430f40a6f9ed22c908 100644
--- a/README.md
+++ b/README.md
@@ -22,7 +22,7 @@
com.gitee.wb04307201
loader-util
- 1.1.2
+ 1.1.3
```
@@ -136,52 +136,7 @@ Accept: application/json
Hello,world!
```
-#### 如需在controller种调用其他bean,请使用MethodUtils.invokeBean("demoService", "testMethod", name)
-```java
- @GetMapping(value = "/loadControllerAndBean")
- public String loadControllerAndBean() {
- String fullClassName1 = "cn.wubo.loaderutiltest.DemoService";
- String javaSourceCode1 = """
- package cn.wubo.loaderutiltest;
-
- import org.springframework.stereotype.Service;
-
- @Service
- public class DemoService {
-
- public String testMethod(String name) {
- return String.format("Hello,%s!", name);
- }
- }
- """;
-
- String beanName = DynamicBean.init(DynamicClass.init(javaSourceCode1, fullClassName1)).load();
-
- String fullClassName2 = "cn.wubo.loaderutiltest.DemoController";
- String javaSourceCode2 = """
- package cn.wubo.loaderutiltest;
-
-import cn.wubo.loader.util.MethodUtils;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.bind.annotation.RestController;
-
-@RestController
-@RequestMapping(value = "test")
-public class DemoController {
-
- @GetMapping(value = "hello")
- public String testMethod(@RequestParam(value = "name") String name) {
- return MethodUtils.invokeBean("demoService", "testMethod", name);
- }
-}
- """;
-
- return DynamicController.init(DynamicClass.init(javaSourceCode2, fullClassName2)).load();
- }
-```
## 6. proxy 动态代理切面
```java
@GetMapping(value = "/testAspect")
diff --git a/src/main/java/cn/wubo/loader/util/SpringContextUtils.java b/src/main/java/cn/wubo/loader/util/SpringContextUtils.java
index 358a2b45f659bd83e3c1ca7c7b220c2f68fd516b..969d7051a56295bdd25406f624a18993dbfc4a76 100644
--- a/src/main/java/cn/wubo/loader/util/SpringContextUtils.java
+++ b/src/main/java/cn/wubo/loader/util/SpringContextUtils.java
@@ -1,11 +1,18 @@
package cn.wubo.loader.util;
+import cn.wubo.loader.util.exception.LoaderRuntimeException;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.stereotype.Component;
+import org.springframework.util.ClassUtils;
+import org.springframework.util.ReflectionUtils;
+import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
+import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
import java.util.Map;
@Component(value = "loaderUtilSpringContextUtils")
@@ -18,24 +25,134 @@ public class SpringContextUtils implements BeanFactoryAware {
listableBeanFactory = (DefaultListableBeanFactory) beanFactory;
}
+ /**
+ * 注册单例Bean
+ *
+ * @param type Bean的类型
+ */
public static void registerSingleton(Class type) {
+ registerSingleton(beanName(type.getName()), type);
+ }
+
+ /**
+ * 注册单例Bean
+ *
+ * @param beanName Bean的名称
+ * @param type Bean的类型
+ */
+ public static void registerSingleton(String beanName, Class type) {
+ // 创建Bean实例
T obj = listableBeanFactory.createBean(type);
- String beanName = beanName(type.getName());
+ // 自动装配Bean依赖
+ listableBeanFactory.autowireBean(obj);
+ // 注册单例Bean
listableBeanFactory.registerSingleton(beanName, obj);
}
- public static void destroy(String className) {
- String beanName = beanName(className);
+ /**
+ * 注册控制器
+ *
+ * @param beanName 控制器的bean名称
+ * @param type 控制器的类型
+ */
+ public static void registerController(String beanName, Class type) {
+ registerSingleton(beanName, type);
+ // 获取RequestMappingHandlerMapping对象
+ RequestMappingHandlerMapping requestMappingHandlerMapping = getBean("requestMappingHandlerMapping");
+ try {
+ // 获取detectHandlerMethods方法
+ Method method = requestMappingHandlerMapping.getClass().getSuperclass().getSuperclass().getDeclaredMethod("detectHandlerMethods", Object.class);
+ // 设置detectHandlerMethods方法可访问
+ method.setAccessible(true);
+ // 调用detectHandlerMethods方法,将控制器对象作为参数传入
+ method.invoke(requestMappingHandlerMapping, beanName);
+ } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
+ // 抛出异常
+ throw new LoaderRuntimeException(e.getMessage(), e);
+ }
+ }
+
+ /**
+ * 注销控制器
+ *
+ * @param beanName 控制器的bean名称
+ */
+ public static void unregisterController(String beanName) {
+ // 获取控制器对象
+ Object obj = getBean(beanName);
+ // 获取控制器的类型
+ Class> type = obj.getClass();
+ // 获取RequestMappingHandlerMapping对象
+ RequestMappingHandlerMapping requestMappingHandlerMapping = getBean("requestMappingHandlerMapping");
+ // 遍历控制器的方法
+ ReflectionUtils.doWithMethods(type, method -> {
+ // 获取最具体的实现方法
+ Method mostSpecificMethod = ClassUtils.getMostSpecificMethod(method, type);
+ try {
+ // 获取RequestMappingInfo实例
+ Method declaredMethod = requestMappingHandlerMapping.getClass().getDeclaredMethod("getMappingForMethod", Method.class, Class.class);
+ declaredMethod.setAccessible(true);
+ RequestMappingInfo requestMappingInfo = (RequestMappingInfo) declaredMethod.invoke(requestMappingHandlerMapping, mostSpecificMethod, type);
+ // 如果RequestMappingInfo不为空,则注销对应的映射
+ if (requestMappingInfo != null) requestMappingHandlerMapping.unregisterMapping(requestMappingInfo);
+ } catch (InvocationTargetException | NoSuchMethodException | IllegalAccessException e) {
+ throw new LoaderRuntimeException(e.getMessage(), e);
+ }
+ });
+ // 销毁控制器的bean
listableBeanFactory.destroySingleton(beanName);
}
+ /**
+ * 判断是否包含指定类型的bean
+ *
+ * @param type 要判断的bean类型
+ * @return 如果包含指定类型的bean则返回true,否则返回false
+ */
+ public static Boolean containsBean(Class type) {
+ return listableBeanFactory.containsBean(beanName(type.getName()));
+ }
+
+ /**
+ * 判断给定的bean名称是否存在于listableBeanFactory中
+ *
+ * @param beanName 要判断的bean名称
+ * @return 如果bean名称存在于listableBeanFactory中,则返回true;否则返回false
+ */
+ public static Boolean containsBean(String beanName) {
+ return listableBeanFactory.containsBean(beanName);
+ }
+
+ /**
+ * 销毁指定名称的单例对象。
+ *
+ * @param beanName 要销毁的单例对象的名称
+ */
+ public static void destroy(String beanName) {
+ listableBeanFactory.destroySingleton(beanName);
+ }
+
+ /**
+ * 销毁指定类型的单例对象。
+ *
+ * @param type 指定的类型
+ */
+ public static void destroy(Class type) {
+ listableBeanFactory.destroySingleton(beanName(type.getName()));
+ }
+
+ /**
+ * 生成bean的名称
+ *
+ * @param className 类名
+ * @return bean的名称
+ */
public static String beanName(String className) {
String[] path = className.split("\\.");
String beanName = path[path.length - 1];
return Character.toLowerCase(beanName.charAt(0)) + beanName.substring(1);
}
- @SuppressWarnings("unchecked")
public static T getBean(String name) {
return (T) listableBeanFactory.getBean(name);
}
diff --git a/src/main/java/cn/wubo/loader/util/bean_loader/DynamicBean.java b/src/main/java/cn/wubo/loader/util/bean_loader/DynamicBean.java
index ae061158d77a65b702c2208775ea841778425bb9..8d4c50b326d67bc16d45f5711b156d7cea381eec 100644
--- a/src/main/java/cn/wubo/loader/util/bean_loader/DynamicBean.java
+++ b/src/main/java/cn/wubo/loader/util/bean_loader/DynamicBean.java
@@ -1,7 +1,7 @@
package cn.wubo.loader.util.bean_loader;
-import cn.wubo.loader.util.class_loader.DynamicClass;
import cn.wubo.loader.util.SpringContextUtils;
+import cn.wubo.loader.util.class_loader.DynamicClass;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@@ -24,20 +24,23 @@ public class DynamicBean {
return new DynamicBean(dynamicClass);
}
-
/**
- * 加载动态生成的类并将其注册为单例Bean,
- * 销毁同名的Bean对象,返回新加载类的Bean名称
- * @return 新加载类的Bean名称
+ * 加载动态类并注册到Spring容器中
+ *
+ * @return 注册的bean名称
*/
public String load() {
+ // 获取动态类的bean名称
String beanName = SpringContextUtils.beanName(dynamicClass.getFullClassName());
- // 销毁Bean
- SpringContextUtils.destroy(beanName);
- // 每次都是new新的ClassLoader对象
+ // 如果Spring容器中已存在该bean,则销毁该bean
+ if (Boolean.TRUE.equals(SpringContextUtils.containsBean(beanName))) SpringContextUtils.destroy(beanName);
+ // 加载动态类并获取其Class对象
Class> type = dynamicClass.compiler().load();
- SpringContextUtils.registerSingleton(type);
+ // 将该Class对象注册为Spring容器中的单例bean
+ SpringContextUtils.registerSingleton(beanName, type);
+ // 返回注册的bean名称
return beanName;
}
+
}
diff --git a/src/main/java/cn/wubo/loader/util/class_loader/DynamicClassLoader.java b/src/main/java/cn/wubo/loader/util/class_loader/DynamicClassLoader.java
index 68b667e93cde5e6c284b8622c77cb72280570cae..1050cc4b026087900f0685dbf5f91b7693cc9bec 100644
--- a/src/main/java/cn/wubo/loader/util/class_loader/DynamicClassLoader.java
+++ b/src/main/java/cn/wubo/loader/util/class_loader/DynamicClassLoader.java
@@ -20,6 +20,12 @@ public class DynamicClassLoader extends SecureClassLoader {
super(parent);
}
+ /**
+ * 添加类信息
+ *
+ * @param fullClassName 类的完全限定名
+ * @param classData 类的数据
+ */
public void addClass(String fullClassName, byte[] classData) {
classBytes.put(fullClassName, classData);
}
diff --git a/src/main/java/cn/wubo/loader/util/controller_loader/DynamicController.java b/src/main/java/cn/wubo/loader/util/controller_loader/DynamicController.java
index 746ca0cccea2b5b9917bd4b7471f3542fd70533b..2eb43a206b74ec8917bece2e32fbec96c9f0f0c1 100644
--- a/src/main/java/cn/wubo/loader/util/controller_loader/DynamicController.java
+++ b/src/main/java/cn/wubo/loader/util/controller_loader/DynamicController.java
@@ -2,15 +2,7 @@ package cn.wubo.loader.util.controller_loader;
import cn.wubo.loader.util.SpringContextUtils;
import cn.wubo.loader.util.class_loader.DynamicClass;
-import cn.wubo.loader.util.exception.LoaderRuntimeException;
import lombok.extern.slf4j.Slf4j;
-import org.springframework.util.ClassUtils;
-import org.springframework.util.ReflectionUtils;
-import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
-import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
-
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
@Slf4j
public class DynamicController {
@@ -27,41 +19,20 @@ public class DynamicController {
}
/**
- * 加载方法
- * @return bean名称
+ * 加载动态类并注册到Spring容器中
+ *
+ * @return 注册的bean名称
*/
public String load() {
- // 获取bean名称
+ // 获取动态类的bean名称
String beanName = SpringContextUtils.beanName(dynamicClass.getFullClassName());
- // 获取RequestMappingHandlerMapping实例
- RequestMappingHandlerMapping requestMappingHandlerMapping = SpringContextUtils.getBean("requestMappingHandlerMapping");
- // 加载类
+ // 如果Spring容器中已存在该bean,则注销该bean
+ if (Boolean.TRUE.equals(SpringContextUtils.containsBean(beanName))) SpringContextUtils.unregisterController(beanName);
+ // 加载动态类并获取其Class对象
Class> type = dynamicClass.compiler().load();
- // 遍历类的方法
- ReflectionUtils.doWithMethods(type, method -> {
- // 获取最具体的实现方法
- Method mostSpecificMethod = ClassUtils.getMostSpecificMethod(method, type);
- try {
- // 获取RequestMappingInfo实例
- Method declaredMethod = requestMappingHandlerMapping.getClass().getDeclaredMethod("getMappingForMethod", Method.class, Class.class);
- declaredMethod.setAccessible(true);
- RequestMappingInfo requestMappingInfo = (RequestMappingInfo) declaredMethod.invoke(requestMappingHandlerMapping, mostSpecificMethod, type);
- // 如果RequestMappingInfo不为空,则注销对应的映射
- if (requestMappingInfo != null) requestMappingHandlerMapping.unregisterMapping(requestMappingInfo);
- } catch (InvocationTargetException | NoSuchMethodException | IllegalAccessException e) {
- throw new LoaderRuntimeException(e.getMessage(), e);
- }
- });
- // 销毁bean
- SpringContextUtils.destroy(beanName);
- try {
- // 检测HandlerMethods
- Method method = requestMappingHandlerMapping.getClass().getSuperclass().getSuperclass().getDeclaredMethod("detectHandlerMethods", Object.class);
- method.setAccessible(true);
- method.invoke(requestMappingHandlerMapping, type.getConstructor().newInstance());
- } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException | InstantiationException e) {
- throw new LoaderRuntimeException(e.getMessage(), e);
- }
+ // 将该Class对象注册为Spring容器中的控制器
+ SpringContextUtils.registerController(beanName, type);
+ // 返回注册的bean名称
return beanName;
}