1.使用ApplicationContextAware获取spring容器中的Bean
在spring项目中,只有都是容器中的bean才可以互取(即依赖注入),比如说userController和userService都是容器中的实例bean,所以在userController中可以注入userService。
但是也会有一些特殊场景需求,自己不是容器中的bean,但是却要注入bean来实现调用这个bean中的方法;
对于系统中非Spring框架管理的类,如果需要获取Spring管理的类,或者,程序中需要动态的根据Bean的id来获取Bean实例,不可能事先为该类提供所有需要的Bean属性的setter方法,在类似这样的情况下,需要获取Spring框架管理的类实例;
package com.ttbank.flep.util; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.stereotype.Component; /** * @Author lucky * @Date 2022/4/7 19:09 */ @Slf4j @Component public class SpringUtil implements ApplicationContextAware { //上下文对象实例 private static ApplicationContext applicationContext; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { if (SpringUtil.applicationContext == null) { SpringUtil.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); } }
之所以方法类SpringUtil能够灵活自如地获取ApplicationContext,就是因为spring能够为我们自动地执行了setApplicationContext。但是,spring不会无缘无故地为某个类执行它的方法的,所以,就很有必要通过注册方法类SpringUtil的方式告知spring有这样子一个类的存在。这里我们使用
@Component
来进行注册;
2.利用反射调用某个类的某个方法
package com.ttbank.flep.controller; import com.ttbank.flep.util.SpringUtil; import org.apache.commons.lang.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * @Author lucky * @Date 2022/4/7 16:36 */ @RestController @RequestMapping("/reflectiontest") public class ReflectionController { @Autowired SpringUtil springUtil; @PostMapping("/getQuartzInfo") public void getQuartzInfo(String jobName,String jobGroupName,String className,String methodName){ try { // Class<?> clazz = Class.forName("com.ttbank.flep.controller.QuartzController"); // Object o = clazz.newInstance(); //01 获取spring容器中的Bean className=StringUtils.uncapitalize(className); //类名首字母小写 Object proxyObject = springUtil.getBean(className); //02 利用bean获取class对象,进而获取本类以及父类或者父接口中所有的公共方法(public修饰符修饰的) Method[] methods = proxyObject.getClass().getMethods(); //03 获取指定的方法 Method method1=null; for (Method method : methods) { if(method.getName().equalsIgnoreCase(methodName)){ method1=method; break; } } //04 封装方法需要的参数 List<Object> paramsList=new ArrayList<>(); paramsList.add(jobName); paramsList.add(jobGroupName); method1.invoke(proxyObject,paramsList.toArray()); } catch (Exception e) { e.printStackTrace(); } } }
postman发起请求:
测试前:
测试后:
3.获取某个类的某个方法的形参变量名
3.1 相关知识补充
(1) ConvertUtils
ConvertUtils 进行数据转换
<dependency> <groupId>commons-beanutils</groupId> <artifactId>commons-beanutils</artifactId> <version>1.9.4</version> </dependency>
ConvertUtils 是 Commons-BeanUtils 包中的一个数据类型转换工具类,主要用来在字符串和各种类型数据间进行转换,还包括对数组的转换。
Object convert = ConvertUtils.convert("2343", Integer.class);
3.2 使用案例
package com.ttbank.flep.controller; import com.alibaba.fastjson.JSONObject; import com.sun.media.jfxmedia.logging.Logger; import com.ttbank.flep.entity.Param; import com.ttbank.flep.util.SpringUtil; import lombok.extern.slf4j.Slf4j; import org.apache.commons.beanutils.ConvertUtils; import org.apache.commons.lang.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.DefaultParameterNameDiscoverer; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.*; /** * @Author lucky * @Date 2022/4/7 16:36 */ @Slf4j @RestController @RequestMapping("/reflectiontest") public class ReflectionController { private static final List<Class> WRAP_CLASS= Arrays.asList(Integer.class,Boolean.class,Double.class,Byte.class,Short.class,Long.class,Float.class,Double.class,String.class); @Autowired SpringUtil springUtil; /** * 根据指定的方法名获取方法; */ private Method getMethod(Object proxyObject, String methodName) { //01 利用bean获取class对象,进而获取本类以及父类或者父接口中所有的公共方法(public修饰符修饰的) Method[] methods = proxyObject.getClass().getMethods(); //02 循环遍历,获取指定方法名的方法 for (Method method : methods) { if(method.getName().equalsIgnoreCase(methodName)){ return method; } } return null; } @PostMapping("/getMethodParamList") public void getMethodParamList(String className,String methodName){ //01 获取spring容器中的Bean className=StringUtils.uncapitalize(className); //类名首字母小写 Object proxyObject = springUtil.getBean(className); //02 利用bean获取class对象,进而获取本类以及父类或者父接口中所有的公共方法(public修饰符修饰的) Method method1=getMethod(proxyObject,methodName); //03 利用spring提供的类获取方法的形参名 DefaultParameterNameDiscoverer nameDiscoverer=new DefaultParameterNameDiscoverer(); String[] params = nameDiscoverer.getParameterNames(method1); Map<String, Object> paramMap = getParamMap(); List<Object> paramValueList=new ArrayList<>(); //04 遍历方法的各个形参,获取Map中的参数值; for (int i = 0; i <method1.getParameterTypes().length ; i++) { Class<?> parameterType = method1.getParameterTypes()[i]; Object object=null; if(WRAP_CLASS.contains(parameterType)){ if(paramMap.containsKey(params[i])){ object=paramMap.get(params[i]); object=ConvertUtils.convert(object,parameterType); log.info("2222"); } }else if(!parameterType.isPrimitive()){ String value=(String) paramMap.get(params[i]); object=JSONObject.parseObject(value,parameterType); log.info("3333"); } paramValueList.add(object); } log.info("OK"); try { method1.invoke(proxyObject,paramValueList.toArray()); } catch (Exception e) { e.printStackTrace(); } } public Map<String,Object> getParamMap(){ Map<String,Object> paramMap=new HashMap<>(); paramMap.put("location","D:\\data" ); Param param=new Param(); param.setSubsysCode("STPM"); param.setContentId("10000001"); String paramStr = JSONObject.toJSONString(param); paramMap.put("params",paramStr ); return paramMap; } }
反射目标调用的方法: