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; } }
反射目標調用的方法: