关闭

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

1646人阅读 评论(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注解还没用上,本意是判断接口同时判断是否注解为处理器。

1
0
查看评论
发表评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场

java中借助Spring获取所有带有指定注解的接口、类、对象-续集

1、支持通过Spring的xml配置文件来制定要获取注解类的包,如何获取配置文件的参数: /** * 通过依赖注入获取配置文件中的属性值 * @param basePackages */ @Resou...
  • Lvbey
  • Lvbey
  • 2016-11-19 15:50
  • 4255

通过接口获取所有实现类以及通过注解获取实现类的思路

近日,工作上被安排修改项目,别人写的一套内外网同步系统,修改成一套上报下发系统,处理很复杂,在原先那人的基础上修改了不少源代码,比较痛苦的是修改他的源代码,必须要看懂全部代码,改的才能顺利进行下去,其...
  • ckao7470
  • ckao7470
  • 2015-08-06 14:30
  • 6778

Java中的Class类以及获取Class对象的三种方式

Java中的Class类以及获取Class对象的三种方式 java.lang.Class 之前Hadoop里面job.setMapperClass(Map.class)之类的方法用到了 x...
  • uniooo
  • uniooo
  • 2014-08-09 01:25
  • 5426

Java语言中,包名、类名、接口名、方法名、变量名,以及常量名的命名有何规范的命名习惯

Java包的名字都是由小写单词组成。但是由于Java面向对象编程的特性,每一名Java程序员都可以编写属于自己的Java包,为了保障每个Java包命名的唯一性,在最新的Java编程规范中,要求程序员在...
  • genious1225
  • genious1225
  • 2011-06-23 16:37
  • 884

Java语言中,包名、类名、接口名、方法名、变量名,以及常量名的命名有何规范的命名习惯

【载自:】http://dingchaoqun12.blog.163.com/blog/static/1160625042010327543481/     Java包的名字都是由小写单词组成。但是由...
  • mycup163
  • mycup163
  • 2011-07-18 11:23
  • 2767

java环境,根据apk路径获取apk的信息(包名,版本号,版本名,权限,图标等信息)

  • 2017-11-29 17:28
  • 15.74MB
  • 下载

纯JAVA环境获取APK信息:包名,版本,版本号,大小,权限...

  • 2014-12-10 23:28
  • 185KB
  • 下载

java 扫描apk获取包名、版本号、版本名称完整代码

  • 2014-09-05 17:08
  • 5KB
  • 下载

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

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

shell中获取某个目录下全部的子文件名,java根据包名分批打包

需求公司每次升级正式环境都是对着项目各个模块进行单独打包。 现在公司希望在使用shell脚本来批量的自动打包,以减少人工出错的情况。思路首先我们要先获得文件夹v1下所有的文件夹名。 因为打jar包...
  • u013066244
  • u013066244
  • 2016-12-07 15:20
  • 1589
    个人资料
    • 访问:747911次
    • 积分:5460
    • 等级:
    • 排名:第5713名
    • 原创:96篇
    • 转载:1篇
    • 译文:0篇
    • 评论:291条
    博客专栏
    其他信息