Reflections扫描classpath, 缓存metadata, 以备运行期间使用.
优点
具备Java原生反射技术, 所不具有的功能, 反射扫描.
缺点
底层实现, 会遍历classpath, 以及遍历jar包中的类, 太耗时间.
只能在启动时, 做些初始化的功能.
模型
package demo.java.reflections.model;
import java.io.Serializable;
public class BaseModel implements Serializable {
}
public class Account extends BaseModel {
}
public class User extends BaseModel {
}
测试 (Java Main)
package demo.java.reflections;
import demo.java.reflections.model.BaseModel;
import org.reflections.Reflections;
import org.reflections.scanners.SubTypesScanner;
import org.reflections.util.ClasspathHelper;
import org.reflections.util.ConfigurationBuilder;
import org.reflections.util.FilterBuilder;
public class ReflectionsTest {
/**
* 如下示例
* 1. 基本使用 和 高级使用 的方式是等价的
* 2. 运行耗时主要在new Reflections()
* 3. Reflections(Scanner:扫描器, URL:扫描路径), 扫描器和扫码路径 越少越好, 这个非常影响耗时!!!
* 4. 这种反射扫描框架, 还是少用为好. 可以考虑用 "Spring IOC", "Java SPI", "配置文件解析" 等方式解决.
* @param args
*/
public static void main(String[] args) {
// 基本使用
Reflections reflections1 = new Reflections("demo.java.reflections.model");
System.out.println(reflections1.getSubTypesOf(BaseModel.class));
// 高级使用
Reflections reflections2 = new Reflections(new ConfigurationBuilder()
.setUrls(ClasspathHelper.forPackage("demo.java.reflections.model"))
.setScanners(new SubTypesScanner())
.filterInputsBy(new FilterBuilder().includePackage("demo.java.reflections.model"))
);
System.out.println(reflections2.getSubTypesOf(BaseModel.class));
}
}
package demo.java.reflections;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class ReflectionsApp {
public static void main(String[] args) {
SpringApplication.run(ReflectionsApp.class, args);
ReflectionsTest.main(args);
}
}
问题现象
idea跑java main方法正常, idea跑springboot main方法正常. cmd跑springboot fat-jar, 报如下异常
解决方案
目前: 把reflections从0.9.12降到0.9.11. 详细参考issues
Exception in thread "main" java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:49)
at org.springframework.boot.loader.Launcher.launch(Launcher.java:107)
at org.springframework.boot.loader.Launcher.launch(Launcher.java:58)
at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:88)
Caused by: org.reflections.ReflectionsException: Scanner SubTypesScanner was not configured
at org.reflections.Store.get(Store.java:39)
at org.reflections.Store.get(Store.java:61)
at org.reflections.Store.get(Store.java:46)
at org.reflections.Store.getAll(Store.java:93)
at org.reflections.Reflections.getSubTypesOf(Reflections.java:404)
at demo.java.reflections.ReflectionsTest.main(ReflectionsTest.java:32)
at demo.java.reflections.ReflectionsApp.main(ReflectionsApp.java:11)
... 8 more
错误 (尝试获取所有java.lang.Number的子类, 失败)
问题现象
idea跑java main方法正常, idea跑springboot main方法正常. cmd跑springboot fat-jar异常
问题原因
idea跑项目时, 会带上classpath, 这方便reflections从jar包中查找java.lang.Number的子类
另, springboot入口org.springframework.boot.loader.JarLauncher#main
有自定义的ClassLoader(LaunchedURLClassLoader)