日前项目中遇到一个问题:
有一个接口,这个接口定义了一种规范和标志,接口中只有一个初始化方法,接口的实现类可能会有非常多,需要在容器启动过程中我们去手动初始化这个接口的所有实现类,虽然在spring中我们可以直接配置,但是维护与使用时却不够优雅。
1. 以一个Config接口为例:
public interface Config { /** * 初始化 */ void initialize(); }
接口很简单,只有一个初始化方法。
2.然后Config接口可能会有很多种实现,比如:
public class RedisConfig implements Config { @Override public void initialize() { // 初始化实现 } }
然而像这种实现可能会非常多且不受控制,但是我们又想对这些实现统一进行初始化,第一步我们就会想到利用ClassLoader来实现,但是如果这些实现类在不同的包中就非常麻烦,随后我们又想到了ServiceLoader,但是需要配置且不同包下也失败了。
在这里我选择了Reflections类库,Reflections使用起来非常简单比Java自身的反射要简便的多,而且好用的多。
3.导入Maven配置
<dependency> <groupId>org.reflections</groupId> <artifactId>reflections-spring</artifactId> <version>0.9.9-RC1</version> <exclusions> <exclusion> <groupId>javassist</groupId> <artifactId>javassist</artifactId> </exclusion> </exclusions> </dependency>
注意不要选错了。
4.编写相关工具
public class ConfigUtil { // 初始化方法名称 private static final String INIT_METHOD_NAME = "initialize"; // 要扫描的包名 private static final String PACKAGE_NAME = "com.xxxx"; public static void main(String[] args) { List<String> list = getConfigNameList(); for (String name : list) { System.out.println(name); //初始化 manualInitialize(name); } } /** * 获取所有模块名称 * * @return */ public static List<String> getConfigNameList() { List<String> nameList = new ArrayList<String>(); Reflections reflections = new Reflections(PACKAGE_NAME); Set<Class<? extends Config>> classes = reflections.getSubTypesOf(Config.class); if (monitorClasses != null) { for (Class<? extends Config> config: classes) { boolean isAbstract = Modifier.isAbstract(config.getModifiers()); //过滤抽象类 if (!isAbstract) { nameList.add(config.getName()); } } } return nameList; } /** * 获取所有实现 * * @return */ public static List<Class> getConfigList() { List<Class> configList= new ArrayList<Class>(); Reflections reflections = new Reflections(PACKAGE_NAME); Set<Class<? extends Config>> classes = reflections.getSubTypesOf(Config.class); if (monitorClasses != null) { for (Class<? extends Config> config : classes) { boolean isAbstract = Modifier.isAbstract(config.getModifiers()); if (!isAbstract) { configList.add(config); } } } return moduleList; } /** * 调用初始化方法 * * @param fullClassName 全限定名 */ @SuppressWarnings("unchecked") public static void manualInitialize(String fullClassName) { try { Class clazz = Class.forName(fullClassName); Constructor[] constructors = clazz.getDeclaredConstructors(); AccessibleObject.setAccessible(constructors, true); for (Constructor con : constructors) { if (con.isAccessible()) { Object classObject = con.newInstance(); Method method = clazz.getMethod(INIT_METHOD_NAME); method.invoke(classObject); } } } catch (Exception e) { e.printStackTrace(); } } }
最终我们调用manualInitialize(name);方法进行了初始化。
相关推荐
// 工具类初始化 AnnotationInjector.init(this); } } ``` 4. **创建工具类** 创建一个工具类,如`AnnotationInjector`,它会遍历目标类的所有字段,查找带有`BindView`注解的成员,并执行初始化操作。这个...
在Java开发中,"扫描接口实现类"是一个常见的需求,特别是在框架或库的初始化阶段,需要自动发现并加载实现了特定接口的类。这个过程通常涉及到类路径扫描和反射技术。以下将详细介绍这一知识点。 首先,我们需要...
构造方法用于初始化类的新实例,普通方法执行特定任务,静态方法与类关联而非实例,抽象方法则在接口或抽象类中定义,需由子类实现。方法的参数传递、返回值和重载也是重要的知识点,理解这些能帮助我们编写更灵活...
Thread 类的构造函数会初始化线程的状态、线程 ID、线程属性等信息。 Thread 线程类是 Java 中 Thread 和 Runnable 接口的实现,它提供了线程的基本操作和管理。开发者可以使用 Thread 类来创建和管理线程,以实现...
总的来说,"max 插件初始化"是3ds Max插件开发的核心部分,理解并正确实现这一阶段对于创建高效、稳定的插件至关重要。无论是为了提升个人技能,还是为了满足特定项目需求,深入学习和实践插件初始化都会带来巨大的...
初始化语法糖的一个关键特性是“属性包装器”(Property Wrappers),它允许开发者定义一个包装器类型,这个类型可以控制属性的设置和获取。通过@wrappingProperty这样的语法,我们可以将复杂的逻辑封装在属性包装器...
在讨论Android蓝牙初始化...以上内容总结了从初始化、开启、关闭Android蓝牙的详细流程,并对关键函数、服务和类进行了深入的解析。这些知识点对于理解Android蓝牙功能的实现机制和进行蓝牙相关的开发工作至关重要。
- 在类初始化时,所有属性都被设置为初始状态(空字符串)。 #### 类终结 ```vb Private Sub Class_Terminate On Error Resume Next 's_jmail.Close() If Err Then Err.Clear End Sub ``` - 类终结时执行清理...
`Project1.dpr`是项目的主程序文件,它定义了程序的启动点,并可能包含了程序初始化和终止的逻辑。`Project1.dof`和`Project1.exe`分别是项目的配置文件和最终的可执行文件,它们包含了运行程序所需的所有信息。 总...
`BeanPostProcessor`接口则允许我们在bean初始化前后执行自定义逻辑,例如调整bean的加载顺序或进行额外的处理。 `ApplicationContextHolder`类中的`getApplicationContext`和`getBean`方法提供了一种全局获取...
GDI+初始化方法 GDI+(Graphics Device Interface Plus)是微软推出的图形编程接口,用于在Windows平台上进行图形编程。为了使用GDI+,需要进行初始化操作。本文将详细介绍GDI+的初始化方法。 一、添加头文件 在...
例如,我们可能有一个接口,不同的实现类在不同的条件下被创建和使用,这样可以提高代码的灵活性和可扩展性。 2. **参数泛型化**: 泛型是Java 5引入的一个重要特性,它允许我们在类、接口和方法中使用类型参数,...
本示例代码展示了如何在Qt应用中实现动态装入并初始化插件。以下是详细的知识点解释: 1. **插件接口定义**:首先,你需要定义一个插件接口,这是所有插件必须遵循的公共协议。在`ExamplePluginInterface.h`中,你...
首先,`IShellExtInit` 是一个关键的COM接口,它是Shell扩展初始化的入口点。当用户在资源管理器中选中一些文件或文件夹时,Windows会调用此接口的`Initialize`方法。在这个方法中,你可以获取到用户所选的文件和...
### Spring的IoC容器初始化源码解析 #### 一、Spring框架的核心——IoC容器 Spring框架是一个开源的轻量级Java开发框架,其核心功能是IoC(Inversion of Control,控制反转)容器和AOP(Aspect Oriented ...
在Spring中,典型的获取ApplicationContext对象的方式是使用ApplicationContext接口的一个实现类,如ClassPathXmlApplicationContext。这是一个根据给定XML文件的类路径的上下文实现。通常我们会在初始化Spring IoC...
接下来,我们创建具体的实现类,例如`ChessGame`或`TicTacToeGame`,它们继承自`Game`抽象类,并提供这些接口的实现。在`ChessGame`中,`start()`可能包含设置棋盘和初始化玩家的逻辑,`playTurn()`处理玩家的每一步...
总而言之,通过`StartupServlet.java`初始化消息资源并在`LabelMgr.java`中进行管理和使用,开发者能够为用户提供一个具备多语言支持的Web应用。理解如何有效地处理这些资源对于构建可扩展且易于维护的应用至关重要...
在微信小程序开发中,通过API接口获取数据是常见的操作,特别是在构建新闻列表这样的功能时。本项目"微信小程序-通过api接口获取新闻列表的demo"就是这样一个实例,它展示了如何利用微信小程序的网络请求能力来从...