Java根据包名获取指定接口的所有实现

1872人阅读 评论(0) 收藏 举报
分类:

原文出自:http://blog.csdn.net/anxpp/article/details/52295168,转载请注明出处,谢谢!

    准备做一个IM,实现服务端的时候,准备将所有消息处理器(MessageHandler)使用责任链设计模式,但是又不希望增加处理器的时候修改责任链的实现。

    这时想到了Spring框架的实现,我们在使用Spring Boot 时,只需要实现一些接口,Spring能自动处理。

    所以就想到通过指定接口和要扫描的包路径来获取所有处理器接口的实现,这样动态添加处理器就不需要修改责任链的实现了。

    具体代码如下:

package com.anxpp.im.config;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.List;

import com.anxpp.im.server.handler.MessageHandler;

/**
 * 通过接口获取所有实现
 *
 * @author http://anxpp.com/ 时间:2016年8月23日 下午10:16:53
 */
@SuppressWarnings("rawtypes")
public class ClassUtil {

	private Class clazz;
	private String packagePath;

	public ClassUtil(Class clazz, String packagePath) {
		this.clazz = clazz;
		this.packagePath = packagePath;
	}

	@SuppressWarnings("unchecked")
	public static void main(String[] args) throws ClassNotFoundException, IOException, InstantiationException, IllegalAccessException {
		List<Class> handlers = new ClassUtil(MessageHandler.class, "com.anxpp.im.server.controller").getAllClassByPackage();
		for (Class<MessageHandler> handler : handlers) {
			handler.newInstance().dealMessage();
		}
	}

	/**
	 * 通过包名获取所有实现(可以将包名配置到统一配置文件中)
	 * 
	 * @param packageName
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public List<Class> getAllClassByPackage() {
		ArrayList<Class> returnClassList = new ArrayList<Class>();
		try {
			List<Class> allClass = getClasses(packagePath);
			// 判断是否是一个接口
			for (int i = 0; i < allClass.size(); i++) {
				if (clazz.isAssignableFrom(allClass.get(i))) {
					if (!clazz.equals(allClass.get(i))) {
						returnClassList.add(allClass.get(i));
					}
				}
			}
		} catch (Exception e) {
		}
		return returnClassList;
	}

	private List<Class> getClasses(String packageName) throws ClassNotFoundException, IOException {
		ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
		String path = packageName.replace(".", "/");
		Enumeration<URL> resources = classLoader.getResources(path);
		List<File> dirs = new ArrayList<File>();
		while (resources.hasMoreElements()) {
			URL resource = resources.nextElement();
			dirs.add(new File(resource.getFile()));
		}
		ArrayList<Class> classes = new ArrayList<Class>();
		for (File directory : dirs) {
			classes.addAll((Collection<? extends Class>) findClass(directory, packageName));
		}
		return classes;
	}

	private List<Class> findClass(File directory, String packageName) throws ClassNotFoundException {
		List<Class> classes = new ArrayList<Class>();
		if (!directory.exists()) {
			return classes;
		}
		File[] files = directory.listFiles();
		for (File file : files) {
			if (file.isDirectory()) {
				assert !file.getName().contains(".");
				classes.addAll(findClass(file, packageName + "." + file.getName()));
			} else if (file.getName().endsWith(".class")) {
				classes.add((Class) Class.forName(packageName + "." + file.getName().substring(0, file.getName().length() - 6)));
			}
		}
		return classes;
	}
}

    处理器接口:

package com.anxpp.im.server.handler;

/**
 * 客户端消息处理器接口
 *
 * @author http://anxpp.com/  时间:2016年8月23日  下午8:18:05
 */
public interface MessageHandler {
	void dealMessage();
}
    其中一个处理器实现如下:
package com.anxpp.im.server.controller;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.anxpp.im.server.handler.Handler;
import com.anxpp.im.server.handler.MessageHandler;

@Handler
public class LoginHandler implements MessageHandler{
	private static final Logger log = LoggerFactory.getLogger(LoginHandler.class);
	@Override
	public void dealMessage() {
		log.info("登陆消息");
	}

}
    这里只是简单的实现,并没有完全贴出责任链的代码。

    其中的@Handler注解还没用上,本意是判断接口同时判断是否注解为处理器。

查看评论

《赤壁》学习笔记(一)

早就听说《赤壁》游戏是在国产游戏中的先驱,后来听说销售情况不是很好,干脆就把源码卖了,也就是业内人士常说的《G档案》。我费尽千辛万苦,在网上下载到了源码和标准版的游戏执行档。  分析了CBMain.C...
  • ysb
  • ysb
  • 2002-07-06 23:29:00
  • 1652

java由类的完整路径利用反射给接口注入对象

  • 2015年12月03日 09:10
  • 7KB
  • 下载

java中通过包名获取该包下的所有class

前面做的在mybatis通过注解自动创建更新表结构的项目,其中在spring加载完毕之后需要去获取所有实体类的class,用来获取实体类属性上的注解,进而分析表结构达到创建修改表结构的目的。 所以就...
  • sun5769675
  • sun5769675
  • 2016-07-15 19:00:48
  • 6251

Java 获取接口所有实现类

利用Spring的Bean工厂,获取接口所有实现类。
  • RickyIT
  • RickyIT
  • 2017-10-10 23:17:22
  • 1198

通过反射机制获取位于同一个包下的接口的所有实现类

通过反射机制获取位于同一个包下的接口的所有实现类   public class ClassUtils {    public static List getAllImplClassesByIn...
  • jiang123986
  • jiang123986
  • 2016-12-14 20:43:57
  • 1421

Java NIO框架Netty简单使用

之前写了一篇文章:Java 网络IO编程总结(BIO、NIO、AIO均含完整实例代码),介绍了如何使用Java原生IO支持进行网络编程,本文介绍一种更为简单的方式,即Java NIO框架。 N...
  • anxpp
  • anxpp
  • 2016-08-03 22:37:04
  • 10346

Java 并发

Java并发      并发编程可以是程序执行速度得到极大提高,或者为设计某些类型的程序提供更易用的模型,或者两者皆有。      (友情提示,双击代码块可以全选) 1 并发的多面性     ...
  • anxpp
  • anxpp
  • 2015-12-02 16:35:04
  • 1996

根据类名,获取接口对象

public static CommonInterface getCommonInterface(Interface itf) throws ClassNotFoundException, Insta...
  • lovebosom
  • lovebosom
  • 2016-12-14 22:50:10
  • 1734

java包名的约定,如Dao,vo,之类

http://wenku.baidu.com/view/c9ec1822af45b307e871978d.html O/R Mapping 是 Object Relational Mapping(对...
  • jajavaja
  • jajavaja
  • 2013-02-21 15:20:43
  • 9981

Javascript代码质量检测工具JSLint

JSLint是一个Javascript代码质量检测工具.代码不是通过编译,可以使用就OK了.编码的风格是很重要的.尤其在编写framework级别的可重用的代码的时候.JSLint支持和推荐使用Jav...
  • iamoyjj
  • iamoyjj
  • 2010-09-04 21:26:00
  • 1711
    个人资料
    专栏达人 持之以恒
    等级:
    访问量: 88万+
    积分: 5843
    排名: 5510
    博客专栏
    music