I'm building a multi-module project using Play 2.3 and Java 8. Root application and each module have a Global object. But how we know Play uses only one Global object from root application.
Simplified folder structure:
/root
/app
Global.java
/conf
application.conf
/subprojects
/user
/app
UserGlobal.java
/admin
/app
AdminGlobal.java
Run Code Online (Sandbox Code Playgroud)
All Global classes placed in unnamed package.
I use such way for merging Global objects from subprojects:
1) Declared configuration variable in root application.conf
subprojects.with.globals="subprojectName1, subprojectName2, subprojectName3, ..."
Run Code Online (Sandbox Code Playgroud)
2) Added private field and private method in root Global.java
private List<GlobalSettings> subprojectGlobals = new ArrayList<>();
private void LoadSubprojectGlobals(Application app)
throws ClassNotFoundException, IllegalAccessException, InstantiationException
{
String subprojectNames =
app.configuration().getString("subprojects.with.globals");
if (!subprojectNames.isEmpty())
{
Class subprojectGlobalClass = null;
for (String subprojectName : subprojectNames.split(","))
{
subprojectGlobalClass = Class.forName(
WordUtils.capitalize(subprojectName.trim().toLowerCase()) +
"Global"
);
subprojectGlobals.add(
(GlobalSettings)subprojectGlobalClass.newInstance()
);
}
}
}
Run Code Online (Sandbox Code Playgroud)
3) Placed such code into onStart event handler in root Global.java
@Override
public void onStart(Application app)
{
try
{
LoadSubprojectGlobals(app);
}
catch(Exception e)
{
new RuntimeException(e);
}
for(GlobalSettings subprojectGlobal: subprojectGlobals)
{
subprojectGlobal.onStart(app);
}
}
Run Code Online (Sandbox Code Playgroud)
Now if we add some new subproject we must edit subprojects.with.globals in root application.conf. And if we want to handle more global settings we need to override appropriate method in root Global.java.
It will be cool if we'll be able to determine all subproject names dynamically from java-code in root onStart. Is it possible? May be from root build.sbt or from Application object?
UPDATE
I changed my project applying @Mon Calamari's approach.
1) Removed configuration variable subprojects.with.globals from root application.conf.
2) Put all subproject Global classes into globals package:
/subprojects
/user
/app
/globals
UserGlobal.java
/admin
/app
/globals
AdminGlobal.java
Run Code Online (Sandbox Code Playgroud)
3) 将配置变量添加到所有子项目 conf 文件中,例如
application.global= globals.UserGlobal
Run Code Online (Sandbox Code Playgroud)
4) 更改LoadSubprojectGlobals()实现:
private void LoadSubprojectGlobals(Application app)
throws ClassNotFoundException, IllegalAccessException, InstantiationException
{
Reflections reflections = new Reflections("globals");
Set<Class<? extends GlobalSettings>> subprojectGlobalClasses =
reflections.getSubTypesOf(GlobalSettings.class);
for(Class subprojectGlobalClass : subprojectGlobalClasses)
{
subprojectGlobals.add(
(GlobalSettings)subprojectGlobalClass.newInstance()
);
}
}
Run Code Online (Sandbox Code Playgroud)
现在如果我们添加一些新的子项目,我们必须遵循一些关于添加全局类的约定,但我们不需要跟踪子项目列表。
非常感谢。
我不确定你的模块/包是如何排列的,但是如果你用来org.reflections获取play.GlobalSettings类的所有扩展怎么办:
Reflections reflections = new Reflections("your.package");
Set<Class<? extends GlobalSettings>> classes = reflections.getSubTypesOf(GlobalSettings.class)
Run Code Online (Sandbox Code Playgroud)