3、方法的执行
第三个难点,就是前端传过来的参数都是字符串,比如:
com.xingoo.test.Provider1Impl 是对应的class
test1 是对应的方法
100 是对应的参数
java.lang.Long 是参数对应的类型
怎么能把请求通过正确的dubbo provider执行呢?——答案 就是Bean
因为在Spring的项目中,dubbo的provider都是一个单例的bean。因此可以直接通过applicationContext获得对应的bean,只要保证bean的名字能规律的映射过来就行。
可以参考下面的获取bean的方法:
import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.stereotype.Component; @Component public class SpringUtils implements ApplicationContextAware { private static ApplicationContext applicationContext = null; // 非@import显式注入,@Component是必须的,且该类必须与main同包或子包 // 若非同包或子包,则需手动import 注入,有没有@Component都一样 // 可复制到Test同包测试 @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { if(SpringUtils.applicationContext == null){ SpringUtils.applicationContext = applicationContext; } } //获取applicationContext public static ApplicationContext getApplicationContext() { return applicationContext; } //通过name获取 Bean. public static Object getBean(String name){ return getApplicationContext().getBean(name); } //通过class获取Bean. public static <T> T getBean(Class<T> clazz){ return getApplicationContext().getBean(clazz); } //通过name,以及Clazz返回指定的Bean public static <T> T getBean(String name,Class<T> clazz){ return getApplicationContext().getBean(name, clazz); } } |
在真正的实现类上,需要指定bean的名字:
@Service("Provider1Impl") public class Provider1Impl implements ProviderApi { ... } 然后利用反射,就可以执行这个bean的特定方法了: // 反射拿到对应的class Class cla = Thread.currentThread().getContextClassLoader().loadClass(clazz); // 在appContext中拿到对应的bean Object bean = SpringUtils.getBean(cla.getSimpleName()); // 格式化参数与参数类型 Class<?>[] parameterTypes = DubboApiUtils.paramTypeFormat(types); Object[] parameters = DubboApiUtils.paramsFormat(params,types); // 通过反射调用对应的方法 return cla.getMethod(method, parameterTypes).invoke(bean,parameters); |
对应参数处理的两个方法是:
/** * 根据字符串拼接,获得对应的参数类型数组 * @param types * @return */ public static Class<?>[] paramTypeFormat(String types){ List<Class<?>> paramsClasses = new ArrayList<>(); for(String type : types.split(",")){ try { paramsClasses.add(Class.forName(type)); } catch (ClassNotFoundException e) { e.printStackTrace(); } } return paramsClasses.toArray(new Class[]{}); } /** * 根据参数类型,转换类型 * @param paramStr * @param types * @return */ public static Object[] paramsFormat(String paramStr,String types){ Class<?>[] classes = paramTypeFormat(types); List<Object> formats = new ArrayList<>(); String[] params = paramStr.split(","); for(int i =0;i<classes.length; i++){ //todo 简单粗暴,有其他的需要再加吧 if("Long".equals(classes[i].getSimpleName())){ formats.add(Long.valueOf(params[i])); }else{ formats.add(params[i]); } } return formats.toArray(); } |
4、商品自动请求描述信息
最后就是jquery基于ajax请求,查询对应的接口结果就行了。需要注意ajax的同步问题:
$.ajax({ type : "post", url : "xxxxx", data : {xxx:xxx}, async : false, success : function(r){ //todo } }); |
总结
总结来说,下面是遇到的问题和简单的对应办法:
1、如何扫描工程或者普通web项目 某个包下的class——通过classloader获得路径,直接遍历file即可
2、如何扫描jar中某个包下的class——通过JarFile获得对应的JarEntry
3、如何获取Spring Boot中的Bean——通过实现ApplicationContextAware接口,获取applicationContext的引用
4、如何动态执行某个对象的特定方法——基于反射method.invoke,需要注意传入的参数与类型问题
通过这样一个小工具,又对反射有了更进一步的了解。:-)))))))))
上文内容不用于商业目的,如涉及知识产权问题,请权利人联系博为峰小编(021-64471599-8017),我们将立即处理。