[编织消息框架][JAVA核心技术]动态代理应用9-扫描class

之前介绍的annotationProcessor能在编译时生成自定义class,但有个缺点,只能每次添加/删除java文件才会执行,那天换了个人不清楚就坑大了

还记得之前介绍的编译时处理,懒处理,还有个预处理没介绍对吧

预处理:应用程序启动前做的处理,如setup

扫描class处理

1.从ClassLoader 和 System.getProperty("java.class.path") 读取所有classPath

2.解释每个classPath ,用正则匹配jar/class 文件

3.正则提取class文件类名,转换成class给上层处理

 1 public class PackageScanner {
 2     private static final Logger LOGGER = LoggerFactory.getLogger(PackageScanner.class);
 3
 4     /**
 5      * @param packageNames
 6      *            过滤的包名,如果为NULL即扫描所有类
 7      */
 8     public static void scan(Consumer<Class<?>> atcion, final String... packageNames) {
 9         Set<String> classPath = new HashSet<>();
10         Set<String> filterPackage = new HashSet<>();
11         if (packageNames == null || packageNames.length == 0) {
12             String classpathProp = System.getProperty("java.class.path");
13             if (classpathProp != null) {
14             String[] classpathEntries = classpathProp.split(File.pathSeparator);
15             for (String cpe : classpathEntries) {
16                 cpe = trimr(cpe, ‘/‘);
17                 classPath.add(new File(cpe).getAbsolutePath());
18             }
19             }
20             ClassLoader cl = ClassLoader.getSystemClassLoader();
21             URL[] urls = ((URLClassLoader) cl).getURLs();
22             for (URL url : urls) {
23             String path = trimr(url.getPath(), ‘/‘);
24             classPath.add(new File(path).getAbsolutePath());
25             }
26         } else {
27             Collections.addAll(classPath, packageNames);
28             Collections.addAll(filterPackage, packageNames);
29         }
30
31         /***
32          * 扫描有三种策略
33          * 1.jar文件
34          * 2.class文件
35          * 3.classPath目录
36          * */
37
38         for (String path : classPath) {
39             try {
40                 if (path.endsWith(".jar")) {
41                     parseJar(path, filterPackage, atcion);
42                 }else if (new File(path).isDirectory()) {
43                     parseFile(path, null, filterPackage, atcion);
44                 } else {
45                     final String packageDirectory = path.replace(‘.‘, ‘/‘);
46                     final Enumeration<URL> urls = Thread.currentThread().getContextClassLoader().getResources(packageDirectory);
47                     while (urls.hasMoreElements()) {
48                         final URL url = urls.nextElement();
49                         if ("file".equals(url.getProtocol())) {
50                             parseFile(url.getPath(), url.getPath().replace(packageDirectory, ""), filterPackage,atcion);
51                         } else if ("jar".equals(url.getProtocol())) {
52                             parseJar(url.getPath(),filterPackage, atcion);
53                         }
54                     }
55                 }
56             } catch (Exception exception) {
57                 throw new RuntimeException(exception);
58             }
59         }
60     }
61 }

parseJar,parseFile 比较长,感兴趣读者可查源码分析

有的JAR里的类读会出错,原因是没有依赖完整的包

测试:

 1 public class TestScanClass {
 2
 3     @Test
 4     public void testAll() {
 5         PackageScanner.scan((clz) -> {
 6             // System.out.println(clz);
 7         });
 8     }
 9
10     @Test
11     public void testFilter1() {
12         PackageScanner.scan((clz) -> {
13             System.out.println(clz);
14         } , "com.eyu.onequeue");
15     }
16
17     @Test
18     public void testFilter() {
19         Set<Class<?>> values = new HashSet<>();
20         PackageScanner.scan((clz) -> {
21             QModel modelAnno = ReflectUtil.getAnno(clz, QModel.class);
22             if (modelAnno == null) {
23                 return;
24             }
25             values.add(clz);
26         } , "com.eyu.onequeue");
27         for (Class<?> clz : values) {
28             if (clz.isInterface()) {
29                 QRpcFactory.registerSendProxy(clz);
30                 System.out.println("registerSendProxy : " + clz);
31             } else {
32                 try {
33                     QRpcFactory.registerReceiveProxy(clz.newInstance());
34                     System.out.println("registerReceiveProxy : " + clz);
35                 } catch (Exception e) {
36                     e.printStackTrace();
37                 }
38             }
39         }
40     }
41 }
时间: 2024-10-29 19:06:31

[编织消息框架][JAVA核心技术]动态代理应用9-扫描class的相关文章

[编织消息框架][JAVA核心技术]动态代理介绍

由于java是种强类型静态语言,在执行时无法动态生成代码,静态语言基本都有这特性 动态生成代码有几种好处,也是弱类型语言的优点 1.部份逻辑可以实现热更新 2.远程调用实现非常适合 3.能动态生成扩展类,屏蔽复杂性,在原来基础上扩展功能,无破坏源码特性 静态语言也不是没有方案去解决,解决方案很多. 其中嵌入一个脚本引擎语言,就能弥补,还有动态代理技术 jdk 自带的动态代理是一种解决方案 cglib动态代理 spring默认使用 javassit 能在执行期修改class 顺便说下scala语言

[编织消息框架][JAVA核心技术]动态代理应用7-实现设计

根据设计生成两个接口,IRpcSend send方法返回数据要求包装成QResult对象 public interface IRpcSend { public <T> QResult<T> send(byte command, Object... args); } public interface IRpcReceive { public <T> T receive(byte command, Object... args); } public interface IR

[编织消息框架][JAVA核心技术]动态代理应用8-IRpcReceive实现

1 private static Map<Short, Map<Byte, Method>> RECEIVE_METHOD_INFO = new HashMap<>(); 2 3 public static <T> T registerReceiveProxy(Object obj) { 4 Class<?> target = obj.getClass(); 5 if (target.isInterface()) { 6 throw new Ru

[编织消息框架][JAVA核心技术]动态代理应用2

接下来如何实现 第一步:先把服务类,调用方法转换成数字,方便传输 第二步:提取元信息,提取又有三种方式,三种各有优点,最优方式是第一种 1.编译java时处理 2.程序启动时处理,预处理 3.调用时处理,懒处理 第三步:编码解释 第四步:请求方式 第五步:分布式支持 第一步: @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface QModel { short value(); } @Targ

[编织消息框架][JAVA核心技术]动态代理应用3

我们先使用懒处理实现提取接口类上的元信息: public abstract class QRpcFactory { public static <T> T loadProxy(Class<T> target, QNode... nodes) public static <T> T loadProxy(Class<T> target, long... ids) } 通过工厂类绑定session id 或 node 生成代理实例 RpcContext 是处理临时

[编织消息框架][JAVA核心技术]异常基础

Java异常体系结构 Thorwable类所有异常和错误的超类,有两个子类Error和Exception,分别表示错误和异常. 其中异常类Exception又分为运行时异常(RuntimeException)和编译时异常(checked Exception), 下面将详细讲述这些异常之间的区别与联系: 1.Error与Exception Error是程序无法处理的错误,比如OutOfMemoryError.ThreadDeath等.这些异常发生时, Java虚拟机(JVM)一般会选择线程终止.

代理模式 &amp; Java原生动态代理技术 &amp; CGLib动态代理技术

第一部分.代理模式  代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后处理消息等.代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务.(其实就是在代理类中关联一个委托类的实例,然后在代理类中进行包装). UML图如下: 第二部分.在Java中实现代理模式  按照代理的创建时期,代理类可以分

java的动态代理

最近在研究这个java的ssh三大框架,当看到这个spring的aop(aspect-orinted-programming)的时候,其中提到了这个java的动态代理机制,这个动态代理,我以前似乎看过,但是那是设计模式的事情.所以有一次搜索到这个动态代理,对这个动态代理进行一个研究,记录自己的进步. spring的aop编程是一个面向切面的编程思想,和这个面向对象的编程是一个补充的关系,不是一个对立的关系.面向对象强调和使用的从上到下的层次关系,但是aop编程使用的是从左到右的关系.一个是纵的关

java中动态代理实现机制

JAVA各种动态代理实现的比较 接口 interface AddInterface{ int add(int a, int b); } interface SubInterface{ int sub(int a, int b); } 实现类 class Arithmetic implements AddInterface, SubInterface{ @Override public int sub(int a, int b) { return a-b; } @Override public i