反射原理说明:
当一个CLass文件加载到内存的时候,jvm就会对class文件进行解剖,然后创建一个Class对象,把该类的所有成员信息封装到该对象中。
反射作用:通过指定的Class文操作整个类的成员变量,方法,构造方法
在反射技术中,一个类的任何成员都有相应的类进行描述
构造方法——Constructor类
成员函数——Method类
成员变量——Field类
object获取Class
Class<? extends Object> classInfo = object.getClass();
一。String获取Class类的三种方式
public void test1() throws Exception {
// 方式一
Class clazz1 = Class.forName("cn.itcast.gz.reflect.Person");
// 方式二
Class clazz2 = Person.class;
// 方式三
Person p1 = new Person();
Class clazz3 = p1.getClass();
//反射创建对象
String str = "com.xxx.xxx.ICBCImpl";
Class clazz = Class.forName(String);
return (ICBCPayImpl)clazz.newInstance(); //或者 return (Stragegy)clazz.newInstnce();
}
二 获取Class类信息
有加decalre表示所有,没有加decalre表示仅公有不包括私有
1.获取类名称和修饰符 类的包名
String name = clazz1.getName(); //类的全称
String name = clazz1.getSimpleName(); //类的简单名称
int modifiers = clazz1.getModifiers(); //类的修改符
method.getDeclaringClass().getName() //通过方法获取包名+类名
method.getReturnType() //获取方法的返回值类型 if (Collection.class.isAssignableFrom(method.getReturnType())){
2.方法method
Method[] methods = clazz1.getMethods(); //获取公共方法包括继承的父类的方法
getMethod("setName", String.class); //获取指定参数的公共方法
Method[] getDeclaredMethods() //获得所有的方法,包括私有
getDeclaredMethod(String name, Class<?>... parameterTypes) //获取所有指定参数的方法,包括私有
//构造方法
Constructor[] declaredConstructors = clazz.getDeclaredConstructors(); //获取该类的所有构造方法
Constructor[] constructors = clazz.getConstructors(); //获取该类的所有公共构造方法
Constructor constructor = clazz.getConstructor(null); //获取单个无参公共构造方法
Constructor declaredConstructor = clazz.getDeclaredConstructor(int.class,String.class); //获取单个有参私有构造方法
declaredConstructor .setAccessible(true); //暴力反射,将构造方法由私有改为公共
// 获取指定名称的方法
Method method1 = clazz1.getMethod("eat", null);
method1.invoke(new Person(), null);
//获取指定方法名且有参数的方法
Method method = clazz1.getMethod("eat", String.class);
method.invoke(new Person(), "包子");
//获取静态方法
Method method = clazz1.getMethod("play", null);
method.invoke(null, null);
//获取私有方法 method.setAccessible(true);
Method method = clazz1.getDeclaredMethod("movie", String.class);
method.setAccessible(true);
method.invoke(new Person(), "苍老师");
3.属性field
Field[] getFields() //获取公共字段
Field getField(String name) //指定参数的公共字段
Field[] getDeclaredFields() //获取所有的字段
Field getDeclaredField(String name) //获取所有指定参数的字段
//获取类的属性的注解值
public static void main(String[] args) {
//获取类所有属性
Field[] fields = TradeDetailDTO.class.getDeclaredFields();
for (Field field : fields) {
//属性类型 String
Class classtType = field.getType();
//属性名称 userName
String fieldName = field.getName();
//属性所有注解
Annotation[] annotations = field.getAnnotations();
//属性指定注解
ApiModelProperty apiModelPropertyAnnotation = field.getAnnotation(ApiModelProperty.class);
String name = apiModelPropertyAnnotation.name();
String value = apiModelPropertyAnnotation.value();
}
}
//判断成员变量是否可访问并设置成可访问
public static void makeAccessible(Field field) {
if ((!Modifier.isPublic(field.getModifiers()) || //成员变量修改时符不是public
!Modifier.isPublic(field.getDeclaringClass().getModifiers()) || //内部类修饰符不是public
Modifier.isFinal(field.getModifiers())) && !field.isAccessible()) { //修饰符是final但是不可访问
field.setAccessible(true);
}
}
三。通过反射创建对象案例
//方式一:newInstance
String str = "com.xxx.xxx.ICBCImpl";
Class clazz = Class.forName(String);
return (ICBCPayImpl)clazz.newInstance(); //或者 return (Stragegy)clazz.newInstnce();
//方式二:使用构造方法创建
Constructor<?> con = clazz1.getConstructor(String.class, int.class); //获取指定参数的构造方法
Object p1 = con.newInstance("jack", 28);
四。baseServiceImpl
@PostConstruct//在构造方法后,初化前执行
protected void initBaseMapper() throws Exception{
System.out.println("=======this :"+this);
System.out.println("=======父类基本信息:"+this.getClass().getSuperclass());
System.out.println("=======父类和泛型的信息:"+this.getClass().getGenericSuperclass());
ParameterizedType type =(ParameterizedType) this.getClass().getGenericSuperclass(); //父类和泛型的信息
Class clazz = (Class)type.getActualTypeArguments()[0]; //泛型 Supplier
//通过泛型拼装为 supplierMapper
String localField = clazz.getSimpleName().substring(0,1).toLowerCase()+clazz.getSimpleName().substring(1)+"Mapper";
Field field=this.getClass().getSuperclass().getDeclaredField(localField); // 获取指定名称的全员变量 supplierMapper
Field baseField = this.getClass().getSuperclass().getDeclaredField("baseMapper"); // 获取指定名称的全员变量 baseMapper
//有了这句话,后面的baseMapper就自动转为supplierMapper
baseField.set(this, field.get(this));
}
五。反射调用某一个类的方法
public static void main(String[] args) throws Exception {
Class<?> clazz = AppController.class;
Method method = clazz.getDeclaredMethod("test1", String.class, String.class);
//getDeclaredMethod不管公有还是私有都可以,getMethod只能公有
method.invoke(clazz.newInstance(), "111", "222");
}
private void test1(String str1, String str2) {
System.out.println(str1);
System.out.println(str2);
}
Class<?> clazz = Class.forName(rpcInfo.getPackageName() + "." + rpcInfo.getClazzName()); //利用反射创建类:UserDao
Class[] classes = new Class[rpcInfo.getArgs().length]; //classes是serve这个方法所有的参数类型(从客户端传过来)
for (int i = 0 ;i<classes.length;i++){
classes[i] = rpcInfo.getArgs()[i].getClass();
}
Method method = clazz.getMethod(rpcInfo.getMethodName(), classes);
method.invoke(clazz.newInstance(),rpcInfo.getArgs());
六。反射设置值
field.set(bean, value);
七。风控项目多个Contrller接口抽取
1、控制器接收参数实体类
public class VerifyReqDto {
@Schema(name="method", description = "取值参考 @RiskMethodEnums")
private String method;
@Schema(name="methodReq",description = "参数类型由verifyPay,verifyWithdraw,verifyTransfer等接口对应的类型")
private Object methodReq;
}
2、Service处理
public GuardianServiceImpl() {
methodMap = new HashMap<>();
methodMap.put(RiskMethodEnums.VERIFY_PAY.name(), new MethodMeta(StrategyEnums.PAY.getName(), PayReqDto.class));
methodMap.put(RiskMethodEnums.VERIFY_WITHDRAW.name(), new MethodMeta(StrategyEnums.WITHDRAW.getName(), WithdrawReqDto.class));
methodMap.put(RiskMethodEnums.VERIFY_RECHARGE.name(), new MethodMeta(StrategyEnums.RECHARGE.getName(), RechargeReqDto.class));
methodMap.put(RiskMethodEnums.VERIFY_TRANSFER.name(), new MethodMeta(StrategyEnums.TRANSFER.getName(), TransferReqDto.class));
methodMap.put(RiskMethodEnums.VERIFY_ADJUST_ACCOUNT.name(), new MethodMeta(StrategyEnums.CHANNEL.getName(), AdjustAccReqDto.class));
methodMap.put(RiskMethodEnums.VERIFY_REGISTER.name(), new MethodMeta(StrategyEnums.REGISTER.getName(), RegisterReqDto.class));
methodMap.put(RiskMethodEnums.VERIFY_LOGIN.name(), new MethodMeta(StrategyEnums.LOGIN.getName(), LoginReqDto.class));
methodMap.put(RiskMethodEnums.VERIFY_SETTING.name(), new MethodMeta(StrategyEnums.SETTINGS.getName(), SettingReqDto.class));
methodMap.put(RiskMethodEnums.VERIFY_BIND_CARD.name(), new MethodMeta(StrategyEnums.BIND.getName(), BindCardReqDto.class));
/**担心调用方,把失败放过**/
errorRsp = new GuardianRspDto();
errorRsp.setCode(200);
errorRsp.setAction(ActionEnums.REJECT.name());
errorRsp.setMsg("Method Error");
errorRsp.setReason("Method Error");
}
@Override
public GuardianRspDto verify(VerifyReqDto reqDto) {
MethodMeta meta = methodMap.get(reqDto.getMethod());
if (meta == null) {
log.warn("Find none such method:{}", reqDto.getMethod());
return errorRsp;
}
Object dto = meta.to(reqDto.getMethodReq());
return riskExec(dto, meta.getStrategy());
}
public class MethodMeta {
private String strategy;
private Class<?> clazz;
public MethodMeta(String strategy, Class<?> clazz) {
this.strategy = strategy;
this.clazz = clazz;
}
public String getStrategy() {
return strategy;
}
public Object to(Object req) {
return JSON.parseObject(JSONObject.toJSONString(req), clazz);
}
}