-
Notifications
You must be signed in to change notification settings - Fork 508
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support plugin management and dynamic plugin installation with extensions #984
base: master
Are you sure you want to change the base?
Changes from 9 commits
a9512c5
7a53f28
0bbd4e3
b8bfd91
f5e356f
94d01ab
ae207e0
4ee8415
58ca02a
345c577
e7d6e2a
84c8548
f81c2be
0e2645b
7b7ea95
c293814
5a35f75
4b08ce4
e4cd09b
792c726
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -38,6 +38,7 @@ | |||||||||||||||||
import com.alipay.sofa.ark.spi.event.biz.BeforeBizStopEvent; | ||||||||||||||||||
import com.alipay.sofa.ark.spi.model.Biz; | ||||||||||||||||||
import com.alipay.sofa.ark.spi.model.BizState; | ||||||||||||||||||
import com.alipay.sofa.ark.spi.model.Plugin; | ||||||||||||||||||
import com.alipay.sofa.ark.spi.service.biz.BizManagerService; | ||||||||||||||||||
import com.alipay.sofa.ark.spi.service.event.EventAdminService; | ||||||||||||||||||
|
||||||||||||||||||
|
@@ -46,6 +47,7 @@ | |||||||||||||||||
import java.net.URL; | ||||||||||||||||||
import java.nio.file.Files; | ||||||||||||||||||
import java.nio.file.Paths; | ||||||||||||||||||
import java.util.ArrayList; | ||||||||||||||||||
import java.util.Date; | ||||||||||||||||||
import java.util.HashSet; | ||||||||||||||||||
import java.util.LinkedHashSet; | ||||||||||||||||||
|
@@ -111,6 +113,8 @@ public class BizModel implements Biz { | |||||||||||||||||
|
||||||||||||||||||
private List<BizStateRecord> bizStateRecords = new CopyOnWriteArrayList<>(); | ||||||||||||||||||
|
||||||||||||||||||
private Set<Plugin> dependentPlugins = new HashSet<>(); | ||||||||||||||||||
|
||||||||||||||||||
public BizModel setBizName(String bizName) { | ||||||||||||||||||
AssertUtils.isFalse(StringUtils.isEmpty(bizName), "Biz Name must not be empty!"); | ||||||||||||||||||
this.bizName = bizName; | ||||||||||||||||||
|
@@ -229,6 +233,15 @@ private void addStateChangeLog(StateChangeReason reason, String message) { | |||||||||||||||||
bizStateRecords.add(new BizStateRecord(new Date(), bizState, reason, message)); | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
public Set<Plugin> getDependentPlugins() { | ||||||||||||||||||
return dependentPlugins; | ||||||||||||||||||
} | ||||||||||||||||||
Comment on lines
+236
to
+238
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Return Unmodifiable Set in Returning the mutable Example: public Set<Plugin> getDependentPlugins() {
- return dependentPlugins;
+ return Collections.unmodifiableSet(dependentPlugins);
} Committable suggestion
Suggested change
|
||||||||||||||||||
|
||||||||||||||||||
public BizModel setDependentPlugins(Set<Plugin> dependentPlugins) { | ||||||||||||||||||
this.dependentPlugins = dependentPlugins; | ||||||||||||||||||
return this; | ||||||||||||||||||
} | ||||||||||||||||||
Comment on lines
+240
to
+243
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Make a Defensive Copy in Assigning the provided set directly to Example: public BizModel setDependentPlugins(Set<Plugin> dependentPlugins) {
- this.dependentPlugins = dependentPlugins;
+ this.dependentPlugins = new HashSet<>(dependentPlugins);
return this;
} Committable suggestion
Suggested change
|
||||||||||||||||||
|
||||||||||||||||||
@Override | ||||||||||||||||||
public String getBizName() { | ||||||||||||||||||
return bizName; | ||||||||||||||||||
|
@@ -615,4 +628,39 @@ private static String markBizTempWorkDirRecycled(File bizTempWorkDir) throws IOE | |||||||||||||||||
|
||||||||||||||||||
return targetPath; | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
/* export class and classloader relationship cache */ | ||||||||||||||||||
private ConcurrentHashMap<String, Plugin> exportClassAndClassLoaderMap = new ConcurrentHashMap<>(); | ||||||||||||||||||
private ConcurrentHashMap<String, Plugin> exportNodeAndClassLoaderMap = new ConcurrentHashMap<>(); | ||||||||||||||||||
private ConcurrentHashMap<String, Plugin> exportStemAndClassLoaderMap = new ConcurrentHashMap<>(); | ||||||||||||||||||
|
||||||||||||||||||
/* export cache and classloader relationship cache */ | ||||||||||||||||||
private ConcurrentHashMap<String, List<Plugin>> exportResourceAndClassLoaderMap = new ConcurrentHashMap<>(); | ||||||||||||||||||
private ConcurrentHashMap<String, List<Plugin>> exportPrefixStemResourceAndClassLoaderMap = new ConcurrentHashMap<>(); | ||||||||||||||||||
private ConcurrentHashMap<String, List<Plugin>> exportSuffixStemResourceAndClassLoaderMap = new ConcurrentHashMap<>(); | ||||||||||||||||||
|
||||||||||||||||||
public ConcurrentHashMap<String, Plugin> getExportClassAndClassLoaderMap() { | ||||||||||||||||||
return exportClassAndClassLoaderMap; | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
public ConcurrentHashMap<String, Plugin> getExportNodeAndClassLoaderMap() { | ||||||||||||||||||
return exportNodeAndClassLoaderMap; | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
public ConcurrentHashMap<String, Plugin> getExportStemAndClassLoaderMap() { | ||||||||||||||||||
return exportStemAndClassLoaderMap; | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
public ConcurrentHashMap<String, List<Plugin>> getExportResourceAndClassLoaderMap() { | ||||||||||||||||||
return exportResourceAndClassLoaderMap; | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
public ConcurrentHashMap<String, List<Plugin>> getExportPrefixStemResourceAndClassLoaderMap() { | ||||||||||||||||||
return exportPrefixStemResourceAndClassLoaderMap; | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
public ConcurrentHashMap<String, List<Plugin>> getExportSuffixStemResourceAndClassLoaderMap() { | ||||||||||||||||||
return exportSuffixStemResourceAndClassLoaderMap; | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -48,9 +48,11 @@ | |
import java.util.ArrayList; | ||
import java.util.Arrays; | ||
import java.util.HashSet; | ||
import java.util.LinkedList; | ||
import java.util.List; | ||
import java.util.Set; | ||
import java.util.jar.Attributes; | ||
import java.util.stream.Stream; | ||
|
||
import static com.alipay.sofa.ark.spi.constant.Constants.ARK_BIZ_NAME; | ||
import static com.alipay.sofa.ark.spi.constant.Constants.ARK_BIZ_VERSION; | ||
|
@@ -80,6 +82,11 @@ public class BizFactoryServiceImpl implements BizFactoryService { | |
|
||
@Override | ||
public Biz createBiz(BizArchive bizArchive) throws IOException { | ||
return createBiz(bizArchive, null); | ||
} | ||
|
||
@Override | ||
public Biz createBiz(BizArchive bizArchive, URL[] extensionUrls) throws IOException { | ||
AssertUtils.isTrue(isArkBiz(bizArchive), "Archive must be a ark biz!"); | ||
BizModel bizModel = new BizModel(); | ||
Attributes manifestMainAttributes = bizArchive.getManifest().getMainAttributes(); | ||
|
@@ -99,7 +106,10 @@ public Biz createBiz(BizArchive bizArchive) throws IOException { | |
getInjectDependencies(manifestMainAttributes.getValue(INJECT_PLUGIN_DEPENDENCIES))) | ||
.setInjectExportPackages(manifestMainAttributes.getValue(INJECT_EXPORT_PACKAGES)) | ||
.setDeclaredLibraries(manifestMainAttributes.getValue(DECLARED_LIBRARIES)) | ||
.setClassPath(bizArchive.getUrls()).setPluginClassPath(getPluginURLs()); | ||
.setClassPath(getMergedBizClassPath(bizArchive.getUrls(), extensionUrls)).setPluginClassPath(getPluginURLs()); | ||
|
||
// prepare dependent plugins and plugin export map | ||
resolveExportMapIfNecessary(bizModel, manifestMainAttributes.getValue("dependent-plugins")); | ||
|
||
if (!(bizArchive instanceof DirectoryBizArchive)) { | ||
bizModel.setBizUrl(bizArchive.getUrl()); | ||
|
@@ -113,8 +123,63 @@ public Biz createBiz(BizArchive bizArchive) throws IOException { | |
return bizModel; | ||
} | ||
|
||
private URL[] getMergedBizClassPath(URL[] bizArchiveUrls, URL[] extensionUrls) { | ||
if (extensionUrls == null || extensionUrls.length == 0) { | ||
return bizArchiveUrls; | ||
} | ||
return Stream.concat(Arrays.stream(bizArchiveUrls), Arrays.stream(extensionUrls)).toArray(URL[]::new); | ||
} | ||
|
||
private void resolveExportMapIfNecessary(BizModel bizModel, String dependentPlugins) { | ||
Set<Plugin> plugins = new HashSet<>(); | ||
if (ArkConfigs.areAllPluginsVisibleForBiz()) { | ||
plugins.addAll(pluginManagerService.getPluginsInOrder()); | ||
} | ||
|
||
if (dependentPlugins != null) { | ||
Set<String> pluginNames = StringUtils.strToSet(dependentPlugins, Constants.MANIFEST_VALUE_SPLIT); | ||
for (String pluginName : pluginNames) { | ||
Plugin plugin = pluginManagerService.getPluginByName(pluginName); | ||
plugins.add(plugin); | ||
} | ||
} | ||
|
||
bizModel.setDependentPlugins(plugins); | ||
for (Plugin plugin : plugins) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 所以每个 plugin,是需要定义自己的 export 内容的,这部分需要在使用文档里说明。 |
||
for (String exportIndex : plugin.getExportPackageNodes()) { | ||
bizModel.getExportNodeAndClassLoaderMap().putIfAbsent(exportIndex, plugin); | ||
} | ||
for (String exportIndex : plugin.getExportPackageStems()) { | ||
bizModel.getExportStemAndClassLoaderMap().putIfAbsent(exportIndex, plugin); | ||
} | ||
for (String exportIndex : plugin.getExportClasses()) { | ||
bizModel.getExportClassAndClassLoaderMap().putIfAbsent(exportIndex, plugin); | ||
} | ||
for (String resource : plugin.getExportResources()) { | ||
bizModel.getExportResourceAndClassLoaderMap().putIfAbsent(resource, | ||
new LinkedList<>()); | ||
bizModel.getExportResourceAndClassLoaderMap().get(resource).add(plugin); | ||
} | ||
for (String resource : plugin.getExportPrefixResourceStems()) { | ||
bizModel.getExportPrefixStemResourceAndClassLoaderMap().putIfAbsent(resource, | ||
new LinkedList<>()); | ||
bizModel.getExportPrefixStemResourceAndClassLoaderMap().get(resource).add(plugin); | ||
} | ||
for (String resource : plugin.getExportSuffixResourceStems()) { | ||
bizModel.getExportSuffixStemResourceAndClassLoaderMap().putIfAbsent(resource, | ||
new LinkedList<>()); | ||
bizModel.getExportSuffixStemResourceAndClassLoaderMap().get(resource).add(plugin); | ||
} | ||
} | ||
} | ||
|
||
@Override | ||
public Biz createBiz(File file) throws IOException { | ||
return createBiz(file, null); | ||
} | ||
|
||
@Override | ||
public Biz createBiz(File file, URL[] extensionUrls) throws IOException { | ||
BizArchive bizArchive; | ||
if (ArkConfigs.isEmbedEnable()) { | ||
File unpackFile = FileUtils.file(file.getAbsolutePath() + "-unpack"); | ||
|
@@ -131,14 +196,14 @@ public Biz createBiz(File file) throws IOException { | |
JarFileArchive jarFileArchive = new JarFileArchive(bizFile); | ||
bizArchive = new JarBizArchive(jarFileArchive); | ||
} | ||
BizModel biz = (BizModel) createBiz(bizArchive); | ||
BizModel biz = (BizModel) createBiz(bizArchive, extensionUrls); | ||
biz.setBizTempWorkDir(file); | ||
yuanyuancin marked this conversation as resolved.
Show resolved
Hide resolved
|
||
return biz; | ||
} | ||
|
||
@Override | ||
public Biz createBiz(BizOperation bizOperation, File file) throws IOException { | ||
BizModel biz = (BizModel) createBiz(file); | ||
BizModel biz = (BizModel) createBiz(file, null); | ||
if (bizOperation != null && !StringUtils.isEmpty(bizOperation.getBizVersion())) { | ||
biz.setBizVersion(bizOperation.getBizVersion()); | ||
if (biz.getBizClassLoader() instanceof BizClassLoader) { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Consider Thread Safety for
dependentPlugins
If
dependentPlugins
may be accessed by multiple threads concurrently, consider using a thread-safe collection likeCopyOnWriteArraySet
or synchronizing access appropriately to prevent concurrent modification issues.