浅谈Spring6中的反射机制
作者:@每天都要敲代码 发布时间:2022-06-04 13:23:33
一:回顾反射机制
这种重点回顾一下反射Method!
为什么要回顾反射机制呢?因为我们后面要手写一个简易的Spring框架,便于我们理解其中的核心原理!
1. 分析方法四要素
我们先来看一下,不使用反射机制调用一个方法需要几个要素的参与!
定义一个SomeService方法
package com.bjpowernode.reflect;
public class SomeService {
// 没有参数、没有返回值的方法
public void doSome(){
System.out.println("public void doSome()执行。");
}
// 一个参数,返回String的方法
public String doSome(String s){
System.out.println("public String doSome(String s)执行。");
return s;
}
// 两个参数,返回String的方法
public String doSome(String s, int i){
System.out.println("public String doSome(String s, int i)执行。");
return s + i;
}
}
进行测试,分析方法的要素
package com.bjpowernode.reflect;
public class Test {
public static void main(String[] args) {
// 不使用反射机制调用这些方法
SomeService someService = new SomeService();
// 无参数
someService.doSome();
// 一个参数
String s1 = someService.doSome("张三");
System.out.println(s1);
// 两个参数
String s2 = someService.doSome("李四", 250);
System.out.println(s2);
}
}
通过以上测试代码,我们可以得出调用一个方法,一般涉及到4个要素:
①调用哪个对象的(SomeService)
②哪个方法(doSome)
③传什么参数("张三")
④返回什么值(String类型)
总结:调用哪个对象的哪个方法?传什么值?返回什么值?
2. 获取Method
要使用反射机制调用一个方法,首先你要获取到这个方法。
在反射机制中Method实例代表的是一个方法,那么怎么获取Method实例呢?
编写测试
(1)要想调用方法,首先我们要先获取对应的类,使用Class.forName,参数是全限定类名
(2)然后调用这个类的getDeclaredMethod方法,参数一个是方法名、另一个参数是可变可变长度参数,类型是class;这样就能获取到方法。
(3)方法获取到,我们就可以调用invoke(调用)方法,参数一个是obj,就是要把对象传过来,所以我们就需要先创建一个对象、另一个参数也是可变长度参数,传具体的值。
例如以下程序的四要素:调用哪个对象、哪个方法、传什么参数、返回什么值?
①obj 要素:哪个对象
②doSomeMethod 要素:哪个方法
③"李四", 250 要素:传什么参数
④retValue 要素:返回什么值
package com.bjpowernode.reflect;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
public class Test2 {
public static void main(String[] args) throws Exception{
// 使用反射机制调用方法
// 第一步:获取类
Class<?> clazz = Class.forName("com.bjpowernode.reflect.SomeService");
// 第二步:获取方法
Method doSomeMethod = clazz.getDeclaredMethod("doSome", String.class, int.class);
// 第三步:调用方法,四要素
// 创建对象
Object obj = clazz.newInstance(); // 这个方法已经过时,也可以采用其它方式
// 也可以先获取到无参数构造方法,然后在创建对象
Constructor<?> declaredConstructor = clazz.getDeclaredConstructor();
Object obj1 = declaredConstructor.newInstance();
// 调用invoke方法
Object retValue = doSomeMethod.invoke(obj, "李四", 250);
System.out.println(retValue);
}
}
3. SpringDI核心实现原理
我们在看一下下面这种需求,假设你现在已知以下信息: ①有这样一个类,类名叫做:com.powernode.reflect.User ②这个类符合javabean规范。属性私有化,对外提供公开的setter和getter方法。 ③你还知道这个类当中有一个属性,属性的名字叫做 age ④并且你还知道age属性的类型是int类型。要求:请使用反射机制调用set方法,给User对象的age属性赋值!
User类
package com.bjpowernode.reflect;
public class User {
private String name;
private int age;
public User() {
}
public User(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
使用反射机制进行赋值,通用代码
第一步:还是通过反射机制先获取类,Class.forName
第二步:调用getDeclaredMethod方法获取方法,参数有两个,怎么样动态获取呢?
①已知了属性名是age,又符合javabean规范,所以我们可以动态拼接出方法名:先拼接上“set”,再调用toUpperCase方法全部转换成大写,然后调用charAt方法截取第一个字符;最后在调用substring方法拼接上后面的字符串;得到完整的方法名:getAge
②已知了属性名是age,调用类的getDeclaredField方法,参数是属性名age,就可以获取对应的属性类型,但是我们需要的是.class,所以在调用参数类型的getType方法;得到完整的属性类型(.class形式):int.class
第三步:最后就可以创建对象,调用invoke方法,给属性赋值,这个方法没有返回值类型,所以什么都不要返回;最后输出这个对象即可!
package com.bjpowernode.reflect;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Locale;
public class Test4 {
public static void main(String[] args) throws Exception {
// 已知类名和属性名
String className = "com.bjpowernode.reflect.User";
String propertyName = "age";
// 使用反射机制,给age属性赋值
// 第一步:获取类
Class<?> clazz = Class.forName(className);
// 第二步:获取方法
// 根据属性获取方法名---字符串拼接
String setMethodName = "set"+propertyName.toUpperCase().charAt(0)+propertyName.substring(1);
// 根据属性获取属性的类型
Field filedType = clazz.getDeclaredField(propertyName);
// 获取方法
Method setMethod = clazz.getDeclaredMethod(setMethodName, filedType.getType());
// 第三步:调用
// 创建对象
Object obj = clazz.newInstance();
setMethod.invoke(obj,18); // 没有返回值类型
// 输出打印这个对象
System.out.println(obj);
}
}
执行结果:age属性成功赋值
看到这里我们是不是想到了Spring容器的注入?我们在看一下我们配置的spring.xml文件,就是指定了类名和属性名;然后底层通过反射机制进行了对象的创建!
总结:有了上面我们对反射机制的回顾学习,后面我们就尝试手写一个简易的Spring框架!
来源:https://blog.csdn.net/m0_61933976/article/details/128703792


猜你喜欢
- 目录业务场景:解决方案:总结业务场景:一个用户数据接口,要求在20ms内返回数据,它的调用逻辑复杂,关联接口多,需要从3个接口汇总数据,这些
- 本文旨在通过重写Comparator接口的compare()方法实现对List的升序、降序、倒序排序。首先明确一点:compare(Inte
- 方案一.使用国内的镜像阿里仓库等首先通过maven的路径找到setting.xml的文件然后在其中修改mirror和profile保存一下就
- 最近项目需要用到可以滑动删除并且带有上拉加载下拉刷新的Listview,查阅了一些资料,大多都是在SwipeMenuListView的基础上
- 最近在开发关于java读取ftp中TXT文件,其中有些坑踩了一下,再次做个记录1、读取文件时我会根据文件名称去生成数据库表,oracle数据
- 1.在实体类中添加@TableId注解:2.在navicat中设置id自动增长:3.测试一下,当我们再次插入的时候,就会看到id4.对注解中
- 功能描述1、创建扑克牌。包括四种花色(黑桃,红心,梅花,方块),十三种点数(2-10,J,Q,K),不考虑大小王。2、创建两个玩家。包括玩家
- 本文实例讲述了spring多数据源配置实现方法。分享给大家供大家参考,具体如下:在网上找到的配置多数据源的方法。1.扩展 org.sprin
- FROM子句一、简单FROM子句获取数据源:var queryAllCustomers = &nb
- 一、strcmp函数适用对象char*类型字符串函数介绍strcmp函数是cstring库中的函数,包含在string.h头文件中用法str
- 先给大家展示下效果图,如果感觉不错,请参考实现思路详解Android开发中关于短息验证码的设计层出不穷,越来越多的应用为了更好的提高软件的安
- Retrofit 基本使用implementation 'com.squareup.retrofit2:retrofit:2.9.0
- @Aspect中有5种通知@Before:前置通知, 在方法执行之前执行@Aroud:环绕通知, 围绕着方法执行@After:后置通知, 在
- 使用了Android的系统API实现了多点触控功能,多点触控对设备的硬件有一定的要求,目前市面上的手机几乎都能实现多点触控了。实现多点触控最
- C#实现的获取路由器MAC地址,路由器外网地址。对于要获取路由器MAC地址,一定需要知道路由器web管理系统的用户名和密码。至于获取路由器的
- 本文实例讲述了Java网络编程实现的简单端口扫描器。分享给大家供大家参考,具体如下:在计算机网络的学习中,不由得觉得这门课的零碎知识点异常之
- 目录效果展示实现原理实现步骤完整代码展示效果展示实现原理首先需要生成绘制小花的坐标点,坐标点的横坐标是根据控件的宽度随机生成的,而纵坐标则设
- 使用AS创建ADIL文件时AS会在main文件夹下给我们生成一个aidl文件夹和一个相同包名的包,通常我们会把所有和ADIL相关的类或文件放
- 本文实例讲述了C#中TreeView节点的自定义绘制方法。分享给大家供大家参考。具体如下:if ((e.State & TreeNo
- JWT本文代码截取自实际项目。jwt(Json Web Token),一个token,令牌。简单流程:用户登录成功后,后端返回一个token