Java反射使用总结
最近公司招了几名刚毕业的大学生,在给他们培训的过程中,讲到反射,他们有些人听不懂,对反射的概念云里雾里的,不知道反射有什么用。
因此就有了本文的诞生。
反射是java提供的一个重要功能,可以在运行时检查类、接口、方法和变量等信息,无需知道类的名字,方法名等。还可以在运行时实例化新对象,调用方法以及设置和获取变量值。
反射非常强大和有用,很多java框架中都有反射的影子,例如spring、mybatis等等,
JDBC利用反射将数据库的表字段映射到java对象的getter/setter方法。
Jackson, GSON, Boon等类库也是利用反射将JSON文件的属性映射到java对的象getter/setter方法。
可见,只要使用java,反射就无处不在。
Class对象
检查一个类之前,必须获取到java.lang.Class对象,java中的所有类型,包括long,int,数组等基本数据类型,都和Class对象有关系。
我们很多人去医院参加体检的时候,都做过B超检查,医生只需把一个探头在我们身上滑动就可以将我们体内的肝、胆、肾等器官反射到B超设备上显示。
Class类对象就相当于B超的探头,将一个类的方法、变量、接口、类名、类修饰符等信息告诉运行的程序。
Java提供了两种方式获取Class对象,一种是使用.class,另外一种是使用Class.forName()。
.class方式适用于在编译时已经知道具体的类。
Class alunbarClass = Alunbar.class;
Class.forName()方式适用于运行时动态获取Class对象,只需将类名作为forName方法的参数:
try{
Class alunbarClass1 = Class.forName("Alunbar");
}
catch(ClassNotFoundException e){
System.out.println("找不到Alunbar类");
}
这个方法会出现类找不到的情况,因此使用这个方法获取Class对象时,必须捕获ClassNotFoundException异常。
获取类名
package cn.alunbar;
public class Alunbar {
public static void main(String arts[]){
Class alunbarClass = Alunbar.class;
System.out.println(alunbarClass.getName());
System.out.println(alunbarClass.getSimpleName());
}
}
上面代码运行结果如下:
cn.alunbar.Alunbar
Alunbar
getName()方法获取的类名包含包信息。getSimpleName()方法只是获取类名,不包含包信息。
获取类修饰符
public class Alunbar {
public static void main(String arts[]){
Class alunbarClass = Alunbar.class;
System.out.println(alunbarClass.getModifiers());
System.out.println(Modifier.isPublic(alunbarClass.getModifiers()));
Class birdClass = Bird.class;
System.out.println(birdClass.getModifiers());
System.out.println(Modifier.isPublic(birdClass.getModifiers()));
}
private class Bird{
}
}
类修饰符有public、private等类型,getModifiers()可以获取一个类的修饰符,但是返回的结果是int,结合Modifier提供的方法,就可以确认修饰符的类型。
Modifier.isAbstract(int modifiers)
Modifier.isFinal(int modifiers)
Modifier.isInterface(int modifiers)
Modifier.isNative(int modifiers)
Modifier.isPrivate(int modifiers)
Modifier.isProtected(int modifiers)
Modifier.isPublic(int modifiers)
Modifier.isStatic(int modifiers)
Modifier.isStrict(int modifiers)
Modifier.isSynchronized(int modifiers)
Modifier.isTransient(int modifiers)
Modifier.isVolatile(int modifiers)
获取包信息
package cn.alunbar;
public class Alunbar {
public static void main(String arts[]){
Class birdClass = Bird.class;
System.out.println(birdClass.getPackage());
}
private class Bird{
}
}
getPackage()方法获取包信息。上面代码运行的结果:
package cn.alunbar
获取父类的Class对象
public class Alunbar {
public static void main(String arts[]){
Class birdClass = Bird.class;
Class superclass = birdClass.getSuperclass();
System.out.println(superclass.getSimpleName());
}
private class Bird extends Animal{
}
private class Animal{
}
}
上面代码运行的结果:
Animal
getSuperclass()方法返回的父类的Class对象。
获取接口信息
获取接口信息的方法:
Class[] interfaces = birdClass.getInterfaces();
一个类可以实现多个接口,所以getInterfaces()方法返回的是Class[]数组。
注意:getInterfaces()只返回指定类实现的接口,不会返父类实现的接口。
获取构造函数Constructor
获取构造函数的方法:
Class birdClass = Bird.class;
Constructor[] constructors = birdClass.getConstructors();
一个类会有多个构造函数,getConstructors()返回的是Constructor[]数组,包含了所有声明的用public修饰的构造函数。
如果你已经知道了某个构造的参数,可以通过下面的方法获取到回应的构造函数对象:
public class Alunbar {
public static void main(String arts[]){
Class birdClass = Bird.class;
try{
Constructor constructors = birdClass.getConstructor(new Class[]{String.class});
}catch(NoSuchMethodException e){
}
}
private class Bird {
public Bird(){
}
public Bird(String eat){
}
}
}
上面获取构造函数的方式有2点需要注意:
1、只能获取到public修饰的构造函数。
2、需要捕获NoSuchMethodException异常。
获取构造函数的参数
获取到构造函数的对象之后,可以通过getParameterTypes()获取到构造函数的参数。
Constructor constructors = birdClass.getConstructor(new Class[]{String.class});
Class[] parameterTypes = constructors.getParameterTypes();
初始化对象
通过反射获取到构造器之后,通过newInstance()方法就可以生成类对象。
public class Alunbar {
public static void main(String arts[]){
Class birdClass = Bird.class;
try{
Constructor constructors = birdClass.getConstructor(new Class[]{String.class});
Bird bird = (Bird)constructors.newInstance("eat tea");
}catch(Exception e){
System.out.println("没有对应的构造函数");
}
}
class Bird {
public Bird(){
}
protected Bird(String eat){
}
}
}
newinstance()方法接受可选数量的参数,必须为所调用的构造函数提供准确的参数。如果构造函数要求String的参数,在调用newinstance()方法是,必须提供String类型的参数。
获取Methods方法信息
下面代码是通过反射可以获取到该类的声明的成员方法信息:
Method[] metchods = birdClass.getMethods();
Method[] metchods1 = birdClass.getDeclaredMethods();
Method eatMetchod = birdClass.getMethod("eat", new Class[]{int.class});
Method eatMetchod1 = birdClass.getDeclaredMethod("eat", new Class[]{int.class});
无参的getMethods()获取到所有public修饰的方法,返回的是Method[]数组。
无参的getDeclaredMethods()方法到的是所有的成员方法,和修饰符无关。
对于有参的getMethods()方法,必须提供要获取的方法名以及方法名的参数。如果要获取的方法没有参数,则用null替代:
Method eatMetchod = birdClass.getMethod("eat", null);
无参的getMethods()和getDeclaredMethods()都只能获取到类声明的成员方法,不能获取到继承父类的方法。
获取成员方法参数
Class birdClass = Bird.class;
Class[] parameterTypes = eatMetchod1.getParameterTypes();
获取成员方法返回类型
Class birdClass = Bird.class;
Class returnType = eatMetchod1.getReturnType();
invoke()方法
java反射提供invoke()方法,在运行时根据业务需要调用相应的方法,这种情况在运行时非常常见,只要通过反射获取到方法名之后,就可以调用对应的方法:
Class birdClass = Bird.class;
Constructor constructors1 = birdClass.getConstructor();
Method eatMetchod = birdClass.getMethod("eat", new Class[]{int.class});
System.out.println(eatMetchod.invoke(constructors1.newInstance(), 2));
invoke方法有两个参数,第一个参数是要调用方法的对象,上面的代码中就是Bird的对象,第二个参数是调用方法要传入的参数。如果有多个参数,则用数组。
如果调用的是static方法,invoke()方法第一个参数就用null代替:
public class Alunbar {
public static void main(String arts[]){
try{
Class birdClass = Bird.class;
Constructor constructors1 = birdClass.getConstructor();
Method eatMetchod = birdClass.getMethod("eat", new Class[]{int.class});
System.out.println(eatMetchod.invoke(null, 2));
}catch(Exception e){
e.printStackTrace();
System.out.println("没有对应的构造函数");
}
}
}
class Bird{
public static int eat(int eat){
return eat;
}
public Bird(){
}
public Bird(String eat){
}
private void talk(){}
}
class Animal{
public void run(){
}
}
使用反射可以在运行时检查和调用类声明的成员方法,可以用来检测某个类是否有getter和setter方法。getter和setter是java bean必须有的方法。
getter和setter方法有下面的一些规律:
getter方法以get为前缀,无参,有返回值
setter方法以set为前缀,有一个参数,返回值可有可无,
下面的代码提供了检测一个类是否有getter和setter方法:
public static void printGettersSetters(Class aClass){
Method[] methods = aClass.getMethods();
for(Method method : methods){
if(isGetter(method)) System.out.println("getter: " + method);
if(isSetter(method)) System.out.println("setter: " + method);
}
}
public static boolean isGetter(Method method){
if(!method.getName().startsWith("get")) return false;
if(method.getParameterTypes().length != 0) return false;
if(void.class.equals(method.getReturnType()) return false;
return true;
}
public static boolean isSetter(Method method){
if(!method.getName().startsWith("set")) return false;
if(method.getParameterTypes().length != 1) return false;
return true;
}
获取成员变量
通过反射可以在运行时获取到类的所有成员变量,还可以给成员变量赋值和获取成员变量的值。
Class birdClass = Bird.class;
Field[] fields1 = birdClass.getFields();
Field[] fields2 = birdClass.getDeclaredFields();
Field fields3 = birdClass.getField("age");
Field fields4 = birdClass.getDeclaredField("age");
getFields()方法获取所有public修饰的成员变量,getField()方法需要传入变量名,并且变量必须是public修饰符修饰。
getDeclaredFields方法获取所有生命的成员变量,不管是public还是private。
获取成员变量类型
Field fields4 = birdClass.getDeclaredField("age");
Object fieldType = fields4.getType();
成员变量赋值和取值
一旦获取到成员变量的Field引用,就可以获取通过get()方法获取变量值,通过set()方法给变量赋值:
Class birdClass = Bird.class;
Field fields3 = birdClass.getField("age");
Bird bird = new Bird();
Object value = fields3.get(bird);
fields3.set(bird, value);
访问私有变量
有很多文章讨论禁止通过反射访问一个对象的私有变量,但是到目前为止所有的jdk还是允许通过反射访问私有变量。
使用 Class.getDeclaredField(String name)或者Class.getDeclaredFields()才能获取到私有变量。
package field;
import java.lang.reflect.Field;
public class PrivateField {
protected String name;
public PrivateField(String name){
this.name = name;
}
}
public class PrivateFieldTest {
public static void main(String args[])throws Exception{
Class privateFieldClass = PrivateField.class;
Field privateName = privateFieldClass.getDeclaredField("name");
privateName.setAccessible(false);
PrivateField privateField = new PrivateField("Alunbar");
String privateFieldValue = (String) privateName.get(privateField);
System.out.println("私有变量值:" + privateFieldValue);
}
}
上面的代码有点需要注意:必须调用setAccessible(true)方法,这是针对私有变量而言,public和protected等都不需要。这个方法是允许通过反射访问类的私有变量。
访问私有方法
和私有变量一样,私有方法也是不允许其他的类随意调用的,但是通过反射可以饶过这一限制。
使用Class.getDeclaredMethod(String name, Class[] parameterTypes)或者Class.getDeclaredMethods()方法获取到私有方法。
public class PrivateMethod {
private String accesPrivateMethod(){
return "成功访问私有方法";
}
}
public class PrivateMethodTest {
public static void main(String args[])throws Exception{
Class privateMethodClass = PrivateMethod.class;
Method privateStringMethod = privateMethodClass.getDeclaredMethod("accesPrivateMethod", null);
privateStringMethod.setAccessible(true);
String returnValue = (String)privateStringMethod.invoke(new PrivateMethod(), null);
System.out.println("returnValue = " + returnValue);
}
}
和访问私有变量一样,也要调用setAccessible(true)方法,允许通过反射访问类的私有方法。
访问类注解信息
通过反射可以在运行时获取到类、方法、变量和参数的注解信息。
访问类的所有注解信息:
Class aClass = TheClass.class;
Annotation[] annotations = aClass.getAnnotations();
for(Annotation annotation : annotations){
if(annotation instanceof MyAnnotation){
MyAnnotation myAnnotation = (MyAnnotation) annotation;
System.out.println("name: " + myAnnotation.name());
System.out.println("value: " + myAnnotation.value());
}
}
访问类特定的注解信息:
Class aClass = TheClass.class;
Annotation annotation = aClass.getAnnotation(MyAnnotation.class);
if(annotation instanceof MyAnnotation){
MyAnnotation myAnnotation = (MyAnnotation) annotation;
System.out.println("name: " + myAnnotation.name());
System.out.println("value: " + myAnnotation.value());
}
访问方法注解信息:
Method method = ... //obtain method object
Annotation[] annotations = method.getDeclaredAnnotations();
for(Annotation annotation : annotations){
if(annotation instanceof MyAnnotation){
MyAnnotation myAnnotation = (MyAnnotation) annotation;
System.out.println("name: " + myAnnotation.name());
System.out.println("value: " + myAnnotation.value());
}
}
访问特定方法注解信息:
Method method = ... // obtain method object
Annotation annotation = method.getAnnotation(MyAnnotation.class);
if(annotation instanceof MyAnnotation){
MyAnnotation myAnnotation = (MyAnnotation) annotation;
System.out.println("name: " + myAnnotation.name());
System.out.println("value: " + myAnnotation.value());
}
访问参数注解信息:
Method method = ... //obtain method object
Annotation[][] parameterAnnotations = method.getParameterAnnotations();
Class[] parameterTypes = method.getParameterTypes();
int i=0;
for(Annotation[] annotations : parameterAnnotations){
Class parameterType = parameterTypes[i++];
for(Annotation annotation : annotations){
if(annotation instanceof MyAnnotation){
MyAnnotation myAnnotation = (MyAnnotation) annotation;
System.out.println("param: " + parameterType.getName());
System.out.println("name : " + myAnnotation.name());
System.out.println("value: " + myAnnotation.value());
}
}
}
Method.getParameterAnnotations()方法返回的是一个二维的Annotation数组,其中包含每个方法参数的注解数组。
访问类所有变量注解信息:
Field field = ... //obtain field object
Annotation[] annotations = field.getDeclaredAnnotations();
for(Annotation annotation : annotations){
if(annotation instanceof MyAnnotation){
MyAnnotation myAnnotation = (MyAnnotation) annotation;
System.out.println("name: " + myAnnotation.name());
System.out.println("value: " + myAnnotation.value());
}
}
访问类某个特定变量的注解信息:
Field field = ... // obtain method object
Annotation annotation = field.getAnnotation(MyAnnotation.class);
if(annotation instanceof MyAnnotation){
MyAnnotation myAnnotation = (MyAnnotation) annotation;
System.out.println("name: " + myAnnotation.name());
System.out.println("value: " + myAnnotation.value());
}
获取泛型信息
很多人认为java类在编译的时候会把泛型信息给擦除掉,所以在运行时是无法获取到泛型信息的。其实在某些情况下,还是可以通过反射在运行时获取到泛型信息的。
获取到java.lang.reflect.Method
对象,就有可能获取到某个方法的泛型返回信息。
泛型方法返回类型
下面的类中定义了一个返回值中有泛型的方法:
public class MyClass {
protected List<String> stringList = ...;
public List<String> getStringList(){
return this.stringList;
}
}
下面的代码使用反射检测getStringList()方法返回的是 List<String>
而不是List
Method method = MyClass.class.getMethod("getStringList", null);
Type returnType = method.getGenericReturnType();
if(returnType instanceof ParameterizedType){
ParameterizedType type = (ParameterizedType) returnType;
Type[] typeArguments = type.getActualTypeArguments();
for(Type typeArgument : typeArguments){
Class typeArgClass = (Class) typeArgument;
System.out.println("typeArgClass = " + typeArgClass);
}
}
上面这段代码会打印:typeArgClass = java.lang.String
泛型方法参数类型
下面的类定义了一个有泛型参数的方法setStringList():
public class MyClass {
protected List<String> stringList = ...;
public void setStringList(List<String> list){
this.stringList = list;
}
}
Method类提供了getGenericParameterTypes()方法获取方法的泛型参数。
method = Myclass.class.getMethod("setStringList", List.class);
Type[] genericParameterTypes = method.getGenericParameterTypes();
for(Type genericParameterType : genericParameterTypes){
if(genericParameterType instanceof ParameterizedType){
ParameterizedType aType = (ParameterizedType) genericParameterType;
Type[] parameterArgTypes = aType.getActualTypeArguments();
for(Type parameterArgType : parameterArgTypes){
Class parameterArgClass = (Class) parameterArgType;
System.out.println("parameterArgClass = " + parameterArgClass);
}
}
}
上面的代码会打印出parameterArgType = java.lang.String
泛型变量类型
通过反射也可以获取到类的成员泛型变量信息——静态变量或实例变量。下面的类定义了一个泛型变量:
public class MyClass {
public List<String> stringList = ...;
}
通过反射的Filed对象获取到泛型变量的类型信息:
Field field = MyClass.class.getField("stringList");
Type genericFieldType = field.getGenericType();
if(genericFieldType instanceof ParameterizedType){
ParameterizedType aType = (ParameterizedType) genericFieldType;
Type[] fieldArgTypes = aType.getActualTypeArguments();
for(Type fieldArgType : fieldArgTypes){
Class fieldArgClass = (Class) fieldArgType;
System.out.println("fieldArgClass = " + fieldArgClass);
}
}
Field对象提供了getGenericType()方法获取到泛型变量。
上面的代码会打印出:fieldArgClass = java.lang.String
动态代理
使用反射可以在运行时创建接口的动态实现,java.lang.reflect.Proxy类提供了创建动态实现的功能。我们把运行时创建接口的动态实现称为动态代理。
动态代理可以用于许多不同的目的,例如数据库连接和事务管理、用于单元测试的动态模拟对象以及其他类似aop的方法拦截等。
创建代理
调用java.lang.reflect.Proxy类的newProxyInstance()方法就可以常见动态代理,newProxyInstance()方法有三个参数:
1、用于“加载”动态代理类的类加载器。
2、要实现的接口数组。
3、将代理上的所有方法调用转发到InvocationHandler的对象。
代码如下:
InvocationHandler handler = new MyInvocationHandler();
MyInterface proxy = (MyInterface) Proxy.newProxyInstance(
MyInterface.class.getClassLoader(),
new Class[] { MyInterface.class },
handler);
运行上面代码后,proxy变量包含了MyInterface接口的动态实现。
对代理的所有调用都将由到实现了InvocationHandler接口的handler 对象来处理。
InvocationHandler
如上面说的一样,必须将InvocationHandler的实现传递给Proxy.newProxyInstance()方法。对动态代理的所有方法调用都转发到实现接口的InvocationHandler对象。
InvocationHandler代码:
public interface InvocationHandler{
Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
}
实现InvocationHandler接口的类:
public class MyInvocationHandler implements InvocationHandler{
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
//do something "dynamic"
}
}
下面详细介绍传递给invoke方法的三个参数。
Object proxy参数,实现接口的动态代理对象。通常不需要这个对象。
Method method参数,表示在动态代理实现的接口上调用的方法。通过Method对象,可以获取到方法名,参数类型,返回类型等信息。
Object[] args参数,包含调用接口中实现的方法时传递给代理的参数值。注意:如果接口中的参数是int、long等基本数据时,这里的args必须使用Integer, Long等包装类型。
上面代码中会生成一个MyInterface接口的对象proxy,通过proxy对象调用的方法都会由MyInvocationHandler类的invoke方法处理。
动态代理使用场景:
1、数据库连接和事务管理。例如Spring框架有一个事务代理,可以启动和提交/回滚事务
2、用于单元测试的动态模拟对象
3、类似AOP的方法拦截。
本文重点介绍了如何通过反射获取到某个类的方法、成员变量、构造函数等信息,同时也介绍动态代理的用法,这些都是反射的基础功能,反射的其他功能里就不一一介绍了。
Java反射使用总结的更多相关文章
- 第28章 java反射机制
java反射机制 1.类加载机制 1.1.jvm和类 运行Java程序:java 带有main方法的类名 之后java会启动jvm,并加载字节码(字节码就是一个类在内存空间的状态) 当调用java命令 ...
- Java反射机制
Java反射机制 一:什么事反射机制 简单地说,就是程序运行时能够通过反射的到类的所有信息,只需要获得类名,方法名,属性名. 二:为什么要用反射: 静态编译:在编译时确定类型,绑定对象,即通过 ...
- java反射(基础了解)
package cn.itcast_01; /** *Person类 */ public class Person { /** 姓名 */ private String name; ...
- java基础知识(十一)java反射机制(上)
java.lang.Class类详解 java Class类详解 一.class类 Class类是java语言定义的特定类的实现,在java中每个类都有一个相应的Class对象,以便java程序运行时 ...
- java基础知识(十一)java反射机制(下)
1.什么是反射机制? java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法,对于任意一个对象都能够调用他的属性和方法,这种动态获取属性和方法的功能称为java的反射机制. ...
- java反射学习之二万能EXCEL导出
一.EXCEL导出的实现过程 假设有一个对象的集合,现在需要将此集合内的所有对象导出到EXCEL中,对象有N个属性:那么我们实现的方式是这样的: 循环这个集合,在循环集合中某个对象的所有属性,将这个对 ...
- java反射学习之一反射机制概述
一.反射机制背景概述 1.反射(reflection)是java被视为动态语言的一个关键性质 2.反射机制指的是程序在运行时能获取任何类的内部所有信息 二.反射机制实现功能概述 1.只要给定类的全名, ...
- java反射 之 反射基础
一.反射 反射:JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的功能称为 ...
- java反射 cglib asm相关资料
有篇文章对java反射的调用的效率做了测试,写的比较好.猛击下面地址 http://www.blogjava.net/stone2083/archive/2010/09/15/332065.html ...
- 超详细的java反射教程
看技术博客时,看到关于java反射的博文,写的非常好.猛击下面的地址,开始java反射之旅 中文翻译地址:http://ifeve.com/java-reflection/ 英文原版地址:http:/ ...
随机推荐
- jmter快速安装
一.简介 Apache JMeter是Apache组织开发的基于Java的压力测试工具,用于接口和压力测试,所以前提是一定更要安装jdk. 二.下载安装 下载:官网下载 下载完成后运行包里的jmete ...
- 使用Docker运行SQL Server
现在.net core已经跨平台了,大家也都用上了linux用上了docker.跟.net经常配套使用的SQL SERVER以前一直是windows only,但是从SQL Server 2017开始 ...
- SpringBoot(18)---通过Lua脚本批量插入数据到Redis布隆过滤器
通过Lua脚本批量插入数据到布隆过滤器 有关布隆过滤器的原理之前写过一篇博客: 算法(3)---布隆过滤器原理 在实际开发过程中经常会做的一步操作,就是判断当前的key是否存在. 那这篇博客主要分为三 ...
- jsp数据交互(二).2
1.application对象 application对象类似于系统的“全局变量”,用于同一个服务器内的所有用户之间的数据共享,对于整个Web服务器,application对象有且只有一个实例. (1 ...
- IO流4
IO流的分类 根据处理数据类型的不同分为:字符流和字节流 根据数据流向不同分为:输入流和输出流 字符流和字节流 字符流的由来: 因为数据编码的不同,而有了对字符进行高效操作的流对象.本质其实就是基于字 ...
- GitLab与Git的结合
作为一名刚入职的大数据初级开发工程师,来到公司后发现代码是部署在GItLab上,之前一直认为代码可以放在码云.github上面,然后就很迷惑就对GitLab进行了了解,将git 和gitlab结合起来 ...
- 洛谷 P5150 题解
题面 因为 n=lcm(a,b)n = lcm(a, b)n=lcm(a,b) ,可以得出: a 和 b 的质因数都是 n 的质因数 对于 n 的每个质因数 x ,在 n 中的次数为 y ,那么 ...
- 检测人脸及眼睛【OpenCV-Python实现 源码+打包.exe文件】
之前用opencv做的一个人脸及双眼检测,在此分享给大家 链接:https://pan.baidu.com/s/1BsKBH3wOF9TmdbRlPagEVQ 提取码:cqkv 效果如下:
- SpringBoot 集成Jedis操作set
题外话: Redis是个有趣的东西,相信搞java的或多或少都会用到,面试时也总离不开问Redis,之前觉得redis只是用做缓存,飞快!也因为最初在封装底层的时候,使用Redisson,所以大部分都 ...
- SpringBoot第一天
一,SpringBoot 介绍 1,如果使用 Spring 开发一个"HelloWorld"的 web 应用: • 创建一个 web 项目并且导入相关 jar 包.SpringMV ...