動態增刪Controller
1、方式一:注冊一個Controller中的指定方法
在spring4.0以后,spring官方已經提供了動態注冊刪除controller,我們直接代碼演示
@Component
public class MappingService {
@Autowired
private RequestMappingHandlerMapping requestMappingHandlerMapping;
RequestMappingInfo requestMappingInfo;
public void addMapping() throws Exception {
// 這里的path和請求方式都和我們在jar包中那個類定義的是一樣的,不然照樣會出現404,還有其他參數,這里就先不設置了
requestMappingInfo = RequestMappingInfo
.paths("/one/demo")
.methods(RequestMethod.GET)
.build();
URLClassLoader classLoader = new URLClassLoader(new URL[]{new URL(MappingService.class.getResource("/") + "1.jar")});
Class<?> myController = classLoader.loadClass("com.example.dynamicmap.MyController");
Object obj = myController.newInstance();
// 這里就注冊了我們的handlermapping,但是這里只能一個一個方法進行注冊(而且不限制你重復注冊,但是如果重復注冊的話,請求的時候會報錯)
requestMappingHandlerMapping.registerMapping(requestMappingInfo, obj, myController.getDeclaredMethod("getOneName",String.class));
}
public void removeMapping() {
requestMappingHandlerMapping.unregisterMapping(requestMappingInfo);
}
}
缺點:就是有些地方限制的比較死,而且這里的地址和請求方式之類的還要我們自己去手動設置,不好!同時針對一些請求,假設你必須加上特定注解才能訪問成功。所以和真正的在spring中寫請求還是有一定去別的
有點:這里我們需要哪些類就映射那些類,這種壓力相對較小
2、方式二:注冊整個Controller類
同樣直接看代碼
@Component
// 這里我們需要用到ApplicationContext,但是這個類又不能直接注入,這里就是用這種方法set進來
public class AutoService implements ApplicationContextAware {
private RequestMappingHandlerMapping requestMappingHandlerMapping;
private ApplicationContext applicationContext;
public void addMapping() throws Exception {
requestMappingHandlerMapping=(RequestMappingHandlerMapping)applicationContext.getBean("requestMappingHandlerMapping");
DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) applicationContext.getAutowireCapableBeanFactory();
URLClassLoader classLoader = new URLClassLoader(new URL[]{new URL(com.example.dynamicmap.one.MappingService.class.getResource("/") + "1.jar")});
Class<?> myController = classLoader.loadClass("com.example.dynamicmap.MyController");
// 這里通過builder直接生成了mycontrooler的definition,然后注冊進去
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(myController);
defaultListableBeanFactory.registerBeanDefinition("myc", beanDefinitionBuilder.getBeanDefinition());
Method method=requestMappingHandlerMapping.getClass().getSuperclass().getSuperclass().getDeclaredMethod("detectHandlerMethods",Object.class);
method.setAccessible(true);
method.invoke(requestMappingHandlerMapping,"myc");
}
public void removeMapping() {
requestMappingHandlerMapping=(RequestMappingHandlerMapping)applicationContext.getBean("requestMappingHandlerMapping");
Object controller= applicationContext.getBean("myc");
if (controller==null) {
System.out.println("spring容器中已不存在該實體");
}
Class<?> targetClass = controller.getClass();
ReflectionUtils.doWithMethods(targetClass, new ReflectionUtils.MethodCallback() {
@Override
public void doWith(Method method) {
Method specificMethod = ClassUtils.getMostSpecificMethod(method, targetClass);
try {
Method createMappingMethod = RequestMappingHandlerMapping.class.
getDeclaredMethod("getMappingForMethod", Method.class, Class.class);
createMappingMethod.setAccessible(true);
RequestMappingInfo requestMappingInfo =(RequestMappingInfo)
createMappingMethod.invoke(requestMappingHandlerMapping,specificMethod,targetClass);
if(requestMappingInfo != null) {
requestMappingHandlerMapping.unregisterMapping(requestMappingInfo);
}
}catch (Exception e){
e.printStackTrace();
}
}
}, ReflectionUtils.USER_DECLARED_METHODS);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
優點:可以直接加載一個類,和我們正常些Controller是一樣的,而且不用去解析什么方法了,很方便
缺點:一家在整個類就會加載起來,如果一個類中接口過多,會有一定影響
