You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by no...@apache.org on 2020/07/11 07:51:53 UTC

[lucene-solr] 01/01: SOLR-14155: Load all other SolrCore plugins from packages

This is an automated email from the ASF dual-hosted git repository.

noble pushed a commit to branch jira/solr14155-1
in repository https://gitbox.apache.org/repos/asf/lucene-solr.git

commit 59053416fcf2115305c768e12f7db45fce042565
Author: noblepaul <no...@gmail.com>
AuthorDate: Sat Jul 11 17:51:03 2020 +1000

    SOLR-14155: Load all other SolrCore plugins from packages
---
 .../apache/solr/api/CustomContainerPlugins.java    | 12 +--
 .../java/org/apache/solr/core/CoreContainer.java   | 24 +++---
 .../src/java/org/apache/solr/core/PluginBag.java   |  4 +
 .../src/java/org/apache/solr/core/PluginInfo.java  | 44 +++++++----
 .../src/java/org/apache/solr/core/SolrConfig.java  | 18 +++++
 .../src/java/org/apache/solr/core/SolrCore.java    | 58 +++++++-------
 .../org/apache/solr/core/SolrResourceLoader.java   | 11 +++
 .../org/apache/solr/handler/StreamHandler.java     |  4 +-
 .../solr/handler/component/SearchHandler.java      |  2 +-
 .../apache/solr/packagemanager/PackageManager.java | 10 +--
 .../solr/packagemanager/RepositoryManager.java     |  6 +-
 .../apache/solr/pkg/CoreRefreshingClassLoader.java | 88 ++++++++++++++++++++++
 .../java/org/apache/solr/pkg/PackageListeners.java | 34 +++++++--
 .../org/apache/solr/pkg/PackagePluginHolder.java   | 21 +++---
 .../java/org/apache/solr/search/CacheConfig.java   | 17 ++++-
 .../java/org/apache/solr/update/UpdateHandler.java | 57 +++++++-------
 .../apache/solr/core/TestQuerySenderListener.java  |  3 +-
 .../apache/solr/core/TestQuerySenderNoQuery.java   |  2 +-
 18 files changed, 283 insertions(+), 132 deletions(-)

diff --git a/solr/core/src/java/org/apache/solr/api/CustomContainerPlugins.java b/solr/core/src/java/org/apache/solr/api/CustomContainerPlugins.java
index 6536276..80b570d 100644
--- a/solr/core/src/java/org/apache/solr/api/CustomContainerPlugins.java
+++ b/solr/core/src/java/org/apache/solr/api/CustomContainerPlugins.java
@@ -36,12 +36,12 @@ import org.apache.solr.common.MapWriter;
 import org.apache.solr.common.SolrException;
 import org.apache.solr.common.annotation.JsonProperty;
 import org.apache.solr.common.cloud.ClusterPropertiesListener;
-import org.apache.solr.common.util.Pair;
 import org.apache.solr.common.util.PathTrie;
 import org.apache.solr.common.util.ReflectMapWriter;
 import org.apache.solr.common.util.StrUtils;
 import org.apache.solr.common.util.Utils;
 import org.apache.solr.core.CoreContainer;
+import org.apache.solr.core.PluginInfo;
 import org.apache.solr.handler.admin.ContainerPluginsApi;
 import org.apache.solr.pkg.PackageLoader;
 import org.apache.solr.request.SolrQueryRequest;
@@ -225,12 +225,12 @@ public class CustomContainerPlugins implements ClusterPropertiesListener, MapWri
     @SuppressWarnings({"unchecked","rawtypes"})
     public ApiInfo(PluginMeta info, List<String> errs) {
       this.info = info;
-      Pair<String, String> klassInfo = org.apache.solr.core.PluginInfo.parseClassName(info.klass);
-      pkg = klassInfo.first();
+      PluginInfo.CName klassInfo = new PluginInfo.CName(info.klass);
+      pkg = klassInfo.pkg;
       if (pkg != null) {
         PackageLoader.Package p = coreContainer.getPackageLoader().getPackage(pkg);
         if (p == null) {
-          errs.add("Invalid package " + klassInfo.first());
+          errs.add("Invalid package " + klassInfo.pkg);
           return;
         }
         this.pkgVersion = p.getVersion(info.version);
@@ -239,7 +239,7 @@ public class CustomContainerPlugins implements ClusterPropertiesListener, MapWri
           return;
         }
         try {
-          klas = pkgVersion.getLoader().findClass(klassInfo.second(), Object.class);
+          klas = pkgVersion.getLoader().findClass(klassInfo.className, Object.class);
         } catch (Exception e) {
           log.error("Error loading class", e);
           errs.add("Error loading class " + e.toString());
@@ -247,7 +247,7 @@ public class CustomContainerPlugins implements ClusterPropertiesListener, MapWri
         }
       } else {
         try {
-          klas = Class.forName(klassInfo.second());
+          klas = Class.forName(klassInfo.className);
         } catch (ClassNotFoundException e) {
           errs.add("Error loading class " + e.toString());
           return;
diff --git a/solr/core/src/java/org/apache/solr/core/CoreContainer.java b/solr/core/src/java/org/apache/solr/core/CoreContainer.java
index 53373b6..ca74829 100644
--- a/solr/core/src/java/org/apache/solr/core/CoreContainer.java
+++ b/solr/core/src/java/org/apache/solr/core/CoreContainer.java
@@ -24,19 +24,7 @@ import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.security.spec.InvalidKeySpecException;
 import java.text.SimpleDateFormat;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Optional;
-import java.util.Properties;
-import java.util.Set;
+import java.util.*;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.ExecutorService;
@@ -1588,20 +1576,28 @@ public class CoreContainer {
     return ret;
   }
 
+  public void reload(String name) {
+    reload(name, null);
+  }
   /**
    * Recreates a SolrCore.
    * While the new core is loading, requests will continue to be dispatched to
    * and processed by the old core
    *
    * @param name the name of the SolrCore to reload
+   * @param coreId The unique identifier of the core
    */
-  public void reload(String name) {
+  public void reload(String name, UUID coreId) {
     if (isShutDown) {
       throw new AlreadyClosedException();
     }
     SolrCore newCore = null;
     SolrCore core = solrCores.getCoreFromAnyList(name, false);
     if (core != null) {
+      if(coreId != null && core.uniqueId != coreId) {
+        //trying to reload an already unloaded core
+        return;
+      }
 
       // The underlying core properties files may have changed, we don't really know. So we have a (perhaps) stale
       // CoreDescriptor and we need to reload it from the disk files
diff --git a/solr/core/src/java/org/apache/solr/core/PluginBag.java b/solr/core/src/java/org/apache/solr/core/PluginBag.java
index 2f82ccc..37a3450 100644
--- a/solr/core/src/java/org/apache/solr/core/PluginBag.java
+++ b/solr/core/src/java/org/apache/solr/core/PluginBag.java
@@ -368,6 +368,10 @@ public class PluginBag<T> implements AutoCloseable {
     protected final PluginInfo pluginInfo;
     boolean registerAPI = false;
 
+    public PluginHolder(T inst, SolrConfig.SolrPluginInfo info) {
+      this.inst = inst;
+      pluginInfo = new PluginInfo(info.tag, Collections.singletonMap("class", inst.getClass().getName()));
+    }
     public PluginHolder(PluginInfo info) {
       this.pluginInfo = info;
     }
diff --git a/solr/core/src/java/org/apache/solr/core/PluginInfo.java b/solr/core/src/java/org/apache/solr/core/PluginInfo.java
index cc6615f..58fa73d 100644
--- a/solr/core/src/java/org/apache/solr/core/PluginInfo.java
+++ b/solr/core/src/java/org/apache/solr/core/PluginInfo.java
@@ -25,7 +25,6 @@ import java.util.Map;
 
 import org.apache.solr.common.MapSerializable;
 import org.apache.solr.common.util.NamedList;
-import org.apache.solr.common.util.Pair;
 import org.apache.solr.util.DOMUtil;
 import org.w3c.dom.Node;
 import org.w3c.dom.NodeList;
@@ -42,6 +41,7 @@ import static org.apache.solr.schema.FieldType.CLASS_NAME;
  */
 public class PluginInfo implements MapSerializable {
   public final String name, className, type, pkgName;
+  public final CName cName;
   @SuppressWarnings({"rawtypes"})
   public final NamedList initArgs;
   public final Map<String, String> attributes;
@@ -53,9 +53,9 @@ public class PluginInfo implements MapSerializable {
   public PluginInfo(String type, Map<String, String> attrs, @SuppressWarnings({"rawtypes"})NamedList initArgs, List<PluginInfo> children) {
     this.type = type;
     this.name = attrs.get(NAME);
-    Pair<String, String> parsed = parseClassName(attrs.get(CLASS_NAME));
-    this.className = parsed.second();
-    this.pkgName = parsed.first();
+    cName = parseClassName(attrs.get(CLASS_NAME));
+    this.className = cName.className;
+    this.pkgName = cName.pkg;
     this.initArgs = initArgs;
     attributes = unmodifiableMap(attrs);
     this.children = children == null ? Collections.<PluginInfo>emptyList(): unmodifiableList(children);
@@ -66,17 +66,29 @@ public class PluginInfo implements MapSerializable {
    * This checks if it is a package name prefixed classname.
    * the return value has first = package name and second = class name
    */
-  public static Pair<String,String > parseClassName(String name) {
-    String pkgName = null;
-    String className = name;
-    if (name != null) {
+  public static CName parseClassName(String name) {
+    return new CName(name);
+  }
+
+  public static class CName {
+    public final String pkg;
+    public final String className;
+
+    public CName(String name) {
+      if (name == null) {
+        pkg = null;
+        className = null;
+        return;
+      }
       int colonIdx = name.indexOf(':');
       if (colonIdx > -1) {
-        pkgName = name.substring(0, colonIdx);
+        pkg = name.substring(0, colonIdx);
         className = name.substring(colonIdx + 1);
+      } else {
+        pkg = null;
+        className = name;
       }
     }
-    return new Pair<>(pkgName, className);
 
   }
 
@@ -84,9 +96,9 @@ public class PluginInfo implements MapSerializable {
   public PluginInfo(Node node, String err, boolean requireName, boolean requireClass) {
     type = node.getNodeName();
     name = DOMUtil.getAttr(node, NAME, requireName ? err : null);
-    Pair<String, String> parsed = parseClassName(DOMUtil.getAttr(node, CLASS_NAME, requireClass ? err : null));
-    className = parsed.second();
-    pkgName = parsed.first();
+    cName = parseClassName(DOMUtil.getAttr(node, CLASS_NAME, requireClass ? err : null));
+    className = cName.className;
+    pkgName = cName.pkg;
     initArgs = DOMUtil.childNodesToNamedList(node);
     attributes = unmodifiableMap(DOMUtil.toMap(node.getAttributes()));
     children = loadSubPlugins(node);
@@ -117,9 +129,9 @@ public class PluginInfo implements MapSerializable {
     }
     this.type = type;
     this.name = (String) m.get(NAME);
-    Pair<String, String> parsed = parseClassName((String) m.get(CLASS_NAME));
-    this.className = parsed.second();
-    this.pkgName = parsed.first();
+    cName = parseClassName((String) m.get(CLASS_NAME));
+    this.className = cName.className;
+    this.pkgName = cName.pkg;
     attributes = unmodifiableMap(m);
     this.children =  Collections.<PluginInfo>emptyList();
     isFromSolrConfig = true;
diff --git a/solr/core/src/java/org/apache/solr/core/SolrConfig.java b/solr/core/src/java/org/apache/solr/core/SolrConfig.java
index 2daaa95..c189eb4 100644
--- a/solr/core/src/java/org/apache/solr/core/SolrConfig.java
+++ b/solr/core/src/java/org/apache/solr/core/SolrConfig.java
@@ -57,6 +57,7 @@ import org.apache.solr.common.SolrException;
 import org.apache.solr.common.SolrException.ErrorCode;
 import org.apache.solr.common.util.IOUtils;
 import org.apache.solr.handler.component.SearchComponent;
+import org.apache.solr.pkg.PackageListeners;
 import org.apache.solr.request.SolrRequestHandler;
 import org.apache.solr.response.QueryResponseWriter;
 import org.apache.solr.response.transform.TransformerFactory;
@@ -105,6 +106,8 @@ public class SolrConfig extends XmlConfigFile implements MapSerializable {
   private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
 
   public static final String DEFAULT_CONF_FILE = "solrconfig.xml";
+  public static final String LATEST = "$LATEST";
+
 
   private RequestParams requestParams;
 
@@ -971,6 +974,21 @@ public class SolrConfig extends XmlConfigFile implements MapSerializable {
     return requestParams;
   }
 
+  /**
+   * The version of package that should be loaded for a given package name
+   * This information is stored in the params.json in the same configset
+   * If params.json is absent or there is no corresponding version specified for a given package,
+   * the latest is used
+   */
+  public String maxPackageVersion(String pkg) {
+    RequestParams.ParamSet p = getRequestParams().getParams(PackageListeners.PACKAGE_VERSIONS);
+    if (p == null) {
+      return null;
+    }
+    Object o = p.get().get(pkg);
+    if (o == null || LATEST.equals(o)) return null;
+    return o.toString();
+  }
 
   public RequestParams refreshRequestParams() {
     requestParams = RequestParams.getFreshRequestParams(getResourceLoader(), requestParams);
diff --git a/solr/core/src/java/org/apache/solr/core/SolrCore.java b/solr/core/src/java/org/apache/solr/core/SolrCore.java
index 0b1c551..83526da 100644
--- a/solr/core/src/java/org/apache/solr/core/SolrCore.java
+++ b/solr/core/src/java/org/apache/solr/core/SolrCore.java
@@ -31,22 +31,7 @@ import java.nio.charset.StandardCharsets;
 import java.nio.file.NoSuchFileException;
 import java.nio.file.Path;
 import java.nio.file.Paths;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.LinkedHashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.Properties;
-import java.util.Set;
+import java.util.*;
 import java.util.concurrent.Callable;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.CopyOnWriteArrayList;
@@ -97,6 +82,7 @@ import org.apache.solr.common.util.SimpleOrderedMap;
 import org.apache.solr.common.util.SolrNamedThreadFactory;
 import org.apache.solr.common.util.Utils;
 import org.apache.solr.core.DirectoryFactory.DirContext;
+import org.apache.solr.core.PluginBag.PluginHolder;
 import org.apache.solr.core.snapshots.SolrSnapshotManager;
 import org.apache.solr.core.snapshots.SolrSnapshotMetaDataManager;
 import org.apache.solr.core.snapshots.SolrSnapshotMetaDataManager.SnapshotMetaData;
@@ -112,6 +98,7 @@ import org.apache.solr.metrics.SolrMetricProducer;
 import org.apache.solr.metrics.SolrMetricsContext;
 import org.apache.solr.pkg.PackageListeners;
 import org.apache.solr.pkg.PackageLoader;
+import org.apache.solr.pkg.PackagePluginHolder;
 import org.apache.solr.request.SolrQueryRequest;
 import org.apache.solr.request.SolrRequestHandler;
 import org.apache.solr.response.BinaryResponseWriter;
@@ -137,10 +124,7 @@ import org.apache.solr.schema.FieldType;
 import org.apache.solr.schema.IndexSchema;
 import org.apache.solr.schema.ManagedIndexSchema;
 import org.apache.solr.schema.SimilarityFactory;
-import org.apache.solr.search.QParserPlugin;
-import org.apache.solr.search.SolrFieldCacheBean;
-import org.apache.solr.search.SolrIndexSearcher;
-import org.apache.solr.search.ValueSourceParser;
+import org.apache.solr.search.*;
 import org.apache.solr.search.stats.LocalStatsCache;
 import org.apache.solr.search.stats.StatsCache;
 import org.apache.solr.update.DefaultSolrCoreState;
@@ -191,6 +175,11 @@ public final class SolrCore implements SolrInfoBean, Closeable {
 
   private String name;
   private String logid; // used to show what name is set
+  /**
+   * A unique id to differentiate multiple instances of the same core
+   * If we reload a core, the name remains same , but the id will be new
+   */
+  public final UUID uniqueId = UUID.randomUUID();
 
   private boolean isReloaded = false;
 
@@ -626,25 +615,26 @@ public final class SolrCore implements SolrInfoBean, Closeable {
   }
 
 
+  @SuppressWarnings("unchecked")
   private void initListeners() {
     final Class<SolrEventListener> clazz = SolrEventListener.class;
     final String label = "Event Listener";
     for (PluginInfo info : solrConfig.getPluginInfos(SolrEventListener.class.getName())) {
       final String event = info.attributes.get("event");
       if ("firstSearcher".equals(event)) {
-        SolrEventListener obj = createInitInstance(info, clazz, label, null);
+        PluginHolder<SolrEventListener> obj = (PluginHolder<SolrEventListener>)PackagePluginHolder.createHolder(info, this, SolrEventListener.class, label);
         firstSearcherListeners.add(obj);
-        log.debug("[{}] Added SolrEventListener for firstSearcher: [{}]", logid, obj);
+        log.debug("[{}] Added SolrEventListener for firstSearcher: [{}]", logid, obj.get());
       } else if ("newSearcher".equals(event)) {
-        SolrEventListener obj = createInitInstance(info, clazz, label, null);
+        PluginHolder<SolrEventListener> obj = (PluginHolder<SolrEventListener>)PackagePluginHolder.createHolder(info, this, SolrEventListener.class, label);
         newSearcherListeners.add(obj);
-        log.debug("[{}] Added SolrEventListener for newSearcher: [{}]", logid, obj);
+        log.debug("[{}] Added SolrEventListener for newSearcher: [{}]", logid, obj.get());
       }
     }
   }
 
-  final List<SolrEventListener> firstSearcherListeners = new ArrayList<>();
-  final List<SolrEventListener> newSearcherListeners = new ArrayList<>();
+  final List<PluginHolder<SolrEventListener>> firstSearcherListeners = new ArrayList<>();
+  final List<PluginHolder<SolrEventListener>> newSearcherListeners = new ArrayList<>();
 
   /**
    * NOTE: this function is not thread safe.  However, it is safe to call within the
@@ -654,7 +644,8 @@ public final class SolrCore implements SolrInfoBean, Closeable {
    * @see SolrCoreAware
    */
   public void registerFirstSearcherListener(SolrEventListener listener) {
-    firstSearcherListeners.add(listener);
+    firstSearcherListeners.add(new PluginHolder<>(listener,
+            SolrConfig.classVsSolrPluginInfo.get(SolrEventListener.class.getName())));
   }
 
   /**
@@ -665,7 +656,8 @@ public final class SolrCore implements SolrInfoBean, Closeable {
    * @see SolrCoreAware
    */
   public void registerNewSearcherListener(SolrEventListener listener) {
-    newSearcherListeners.add(listener);
+    newSearcherListeners.add(
+            new PluginHolder<>(listener, SolrConfig.classVsSolrPluginInfo.get(SolrEventListener.class.getName())));
   }
 
   /**
@@ -938,6 +930,7 @@ public final class SolrCore implements SolrInfoBean, Closeable {
 
       this.solrConfig = configSet.getSolrConfig();
       this.resourceLoader = configSet.getSolrConfig().getResourceLoader();
+      this.resourceLoader.core = this;
       this.configSetProperties = configSet.getProperties();
       // Initialize the metrics manager
       this.coreMetricManager = initCoreMetricManager(solrConfig);
@@ -2364,8 +2357,8 @@ public final class SolrCore implements SolrInfoBean, Closeable {
         if (currSearcher == null) {
           future = searcherExecutor.submit(() -> {
             try {
-              for (SolrEventListener listener : firstSearcherListeners) {
-                listener.newSearcher(newSearcher, null);
+              for (PluginHolder<SolrEventListener>  listener : firstSearcherListeners) {
+                listener.get().newSearcher(newSearcher, null);
               }
             } catch (Throwable e) {
               SolrException.log(log, null, e);
@@ -2380,8 +2373,8 @@ public final class SolrCore implements SolrInfoBean, Closeable {
         if (currSearcher != null) {
           future = searcherExecutor.submit(() -> {
             try {
-              for (SolrEventListener listener : newSearcherListeners) {
-                listener.newSearcher(newSearcher, currSearcher);
+              for (PluginHolder<SolrEventListener>  listener : newSearcherListeners) {
+                listener.get().newSearcher(newSearcher, currSearcher);
               }
             } catch (Throwable e) {
               SolrException.log(log, null, e);
@@ -3252,4 +3245,5 @@ public final class SolrCore implements SolrInfoBean, Closeable {
   public void runAsync(Runnable r) {
     coreAsyncTaskExecutor.submit(r);
   }
+
 }
diff --git a/solr/core/src/java/org/apache/solr/core/SolrResourceLoader.java b/solr/core/src/java/org/apache/solr/core/SolrResourceLoader.java
index 77c80bf..3ab1ba1 100644
--- a/solr/core/src/java/org/apache/solr/core/SolrResourceLoader.java
+++ b/solr/core/src/java/org/apache/solr/core/SolrResourceLoader.java
@@ -76,6 +76,12 @@ public class SolrResourceLoader implements ResourceLoader, Closeable {
   protected URLClassLoader classLoader;
   private final Path instanceDir;
 
+  /**
+   * this is set  by the {@link SolrCore}
+   * This could be null if the core is not yet initialized
+   */
+  SolrCore core;
+
   private final List<SolrCoreAware> waitingForCore = Collections.synchronizedList(new ArrayList<SolrCoreAware>());
   private final List<SolrInfoBean> infoMBeans = Collections.synchronizedList(new ArrayList<SolrInfoBean>());
   private final List<ResourceLoaderAware> waitingForResources = Collections.synchronizedList(new ArrayList<ResourceLoaderAware>());
@@ -198,6 +204,11 @@ public class SolrResourceLoader implements ResourceLoader, Closeable {
     TokenizerFactory.reloadTokenizers(this.classLoader);
   }
 
+  public SolrCore getCore(){
+    return core;
+  }
+
+
   private static URLClassLoader addURLsToClassLoader(final URLClassLoader oldLoader, List<URL> urls) {
     if (urls.size() == 0) {
       return oldLoader;
diff --git a/solr/core/src/java/org/apache/solr/handler/StreamHandler.java b/solr/core/src/java/org/apache/solr/handler/StreamHandler.java
index f1b1544..d604616 100644
--- a/solr/core/src/java/org/apache/solr/handler/StreamHandler.java
+++ b/solr/core/src/java/org/apache/solr/handler/StreamHandler.java
@@ -158,8 +158,8 @@ public class StreamHandler extends RequestHandlerBase implements SolrCoreAware,
     }
 
     @Override
-    protected void initNewInstance(PackageLoader.Package.Version newest) {
-      clazz = newest.getLoader().findClass(pluginInfo.className, Expressible.class);
+    protected Object initNewInstance(PackageLoader.Package.Version newest) {
+      return clazz = newest.getLoader().findClass(pluginInfo.className, Expressible.class);
     }
 
   }
diff --git a/solr/core/src/java/org/apache/solr/handler/component/SearchHandler.java b/solr/core/src/java/org/apache/solr/handler/component/SearchHandler.java
index b93d855..6ee180e 100644
--- a/solr/core/src/java/org/apache/solr/handler/component/SearchHandler.java
+++ b/solr/core/src/java/org/apache/solr/handler/component/SearchHandler.java
@@ -166,7 +166,7 @@ public class SearchHandler extends RequestHandlerBase implements SolrCoreAware,
         }
 
         @Override
-        public void changed(PackageLoader.Package pkg) {
+        public void changed(PackageLoader.Package pkg, Ctx ctx) {
           //we could optimize this by listening to only relevant packages,
           // but it is not worth optimizing as these are lightweight objects
           components = null;
diff --git a/solr/core/src/java/org/apache/solr/packagemanager/PackageManager.java b/solr/core/src/java/org/apache/solr/packagemanager/PackageManager.java
index ef042da..f9b746a 100644
--- a/solr/core/src/java/org/apache/solr/packagemanager/PackageManager.java
+++ b/solr/core/src/java/org/apache/solr/packagemanager/PackageManager.java
@@ -43,10 +43,10 @@ import org.apache.solr.common.cloud.SolrZkClient;
 import org.apache.solr.common.cloud.ZkStateReader;
 import org.apache.solr.common.util.Pair;
 import org.apache.solr.common.util.Utils;
+import org.apache.solr.core.SolrConfig;
 import org.apache.solr.packagemanager.SolrPackage.Command;
 import org.apache.solr.packagemanager.SolrPackage.Manifest;
 import org.apache.solr.packagemanager.SolrPackage.Plugin;
-import org.apache.solr.pkg.PackagePluginHolder;
 import org.apache.solr.util.SolrCLI;
 import org.apache.zookeeper.KeeperException;
 import org.slf4j.Logger;
@@ -250,7 +250,7 @@ public class PackageManager implements Closeable {
       // Set the package version in the collection's parameters
       try {
         SolrCLI.postJsonToSolr(solrClient, PackageUtils.getCollectionParamsPath(collection),
-            "{set:{PKG_VERSIONS:{" + packageInstance.name+": '" + (pegToLatest? PackagePluginHolder.LATEST: packageInstance.version)+"'}}}");
+            "{set:{PKG_VERSIONS:{" + packageInstance.name+": '" + (pegToLatest? SolrConfig.LATEST: packageInstance.version)+"'}}}");
       } catch (Exception ex) {
         throw new SolrException(ErrorCode.SERVER_ERROR, ex);
       }
@@ -296,7 +296,7 @@ public class PackageManager implements Closeable {
       // Set the package version in the collection's parameters
       try {
         SolrCLI.postJsonToSolr(solrClient, PackageUtils.getCollectionParamsPath(collection),
-            "{update:{PKG_VERSIONS:{'" + packageInstance.name + "' : '" + (pegToLatest? PackagePluginHolder.LATEST: packageInstance.version) + "'}}}");
+            "{update:{PKG_VERSIONS:{'" + packageInstance.name + "' : '" + (pegToLatest? SolrConfig.LATEST: packageInstance.version) + "'}}}");
       } catch (Exception ex) {
         throw new SolrException(ErrorCode.SERVER_ERROR, ex);
       }
@@ -550,7 +550,7 @@ public class PackageManager implements Closeable {
         }
       }
     }
-    if (version == null || version.equalsIgnoreCase(PackageUtils.LATEST) || version.equalsIgnoreCase(PackagePluginHolder.LATEST)) {
+    if (version == null || version.equalsIgnoreCase(PackageUtils.LATEST) || version.equalsIgnoreCase(SolrConfig.LATEST)) {
       return latest;
     } else return null;
   }
@@ -671,7 +671,7 @@ public class PackageManager implements Closeable {
 
   /**
    * Given a package, return a map of collections where this package is
-   * installed to the installed version (which can be {@link PackagePluginHolder#LATEST})
+   * installed to the installed version (which can be {@link org.apache.solr.core.SolrConfig#LATEST})
    */
   public Map<String, String> getDeployedCollections(String packageName) {
     List<String> allCollections;
diff --git a/solr/core/src/java/org/apache/solr/packagemanager/RepositoryManager.java b/solr/core/src/java/org/apache/solr/packagemanager/RepositoryManager.java
index 0d1fc17..e961a37 100644
--- a/solr/core/src/java/org/apache/solr/packagemanager/RepositoryManager.java
+++ b/solr/core/src/java/org/apache/solr/packagemanager/RepositoryManager.java
@@ -48,11 +48,11 @@ import org.apache.solr.common.SolrException;
 import org.apache.solr.common.SolrException.ErrorCode;
 import org.apache.solr.common.cloud.SolrZkClient;
 import org.apache.solr.core.BlobRepository;
+import org.apache.solr.core.SolrConfig;
 import org.apache.solr.filestore.PackageStoreAPI;
 import org.apache.solr.packagemanager.SolrPackage.Artifact;
 import org.apache.solr.packagemanager.SolrPackage.SolrPackageRelease;
 import org.apache.solr.pkg.PackageAPI;
-import org.apache.solr.pkg.PackagePluginHolder;
 import org.apache.solr.util.SolrCLI;
 import org.apache.zookeeper.CreateMode;
 import org.apache.zookeeper.KeeperException;
@@ -300,7 +300,7 @@ public class RepositoryManager {
 
   /**
    * Install a version of the package. Also, run verify commands in case some
-   * collection was using {@link PackagePluginHolder#LATEST} version of this package and got auto-updated.
+   * collection was using {@link org.apache.solr.core.SolrConfig#LATEST} version of this package and got auto-updated.
    */
   public boolean install(String packageName, String version) throws SolrException {
     SolrPackageRelease pkg = getLastPackageRelease(packageName);
@@ -312,7 +312,7 @@ public class RepositoryManager {
 
     Map<String, String> collectionsDeployedIn = packageManager.getDeployedCollections(packageName);
     List<String> collectionsPeggedToLatest = collectionsDeployedIn.keySet().stream().
-        filter(collection -> collectionsDeployedIn.get(collection).equals(PackagePluginHolder.LATEST)).collect(Collectors.toList());
+        filter(collection -> collectionsDeployedIn.get(collection).equals(SolrConfig.LATEST)).collect(Collectors.toList());
     if (!collectionsPeggedToLatest.isEmpty()) {
       PackageUtils.printGreen("Collections that will be affected (since they are configured to use $LATEST): "+collectionsPeggedToLatest);
     }
diff --git a/solr/core/src/java/org/apache/solr/pkg/CoreRefreshingClassLoader.java b/solr/core/src/java/org/apache/solr/pkg/CoreRefreshingClassLoader.java
new file mode 100644
index 0000000..efad846
--- /dev/null
+++ b/solr/core/src/java/org/apache/solr/pkg/CoreRefreshingClassLoader.java
@@ -0,0 +1,88 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.solr.pkg;
+
+import org.apache.solr.core.PluginInfo;
+import org.apache.solr.core.SolrCore;
+import org.apache.solr.core.SolrResourceLoader;
+
+import java.util.function.Function;
+
+/**A utility class that loads classes from packages and reloads core if any of those packages are updated
+ *
+ */
+public class CoreRefreshingClassLoader implements PackageListeners.Listener {
+  private final SolrCore solrCore;
+  private final PluginInfo info;
+  private final PackageLoader.Package.Version version;
+
+  public CoreRefreshingClassLoader(SolrCore solrCore, PluginInfo info, PackageLoader.Package.Version version) {
+    this.solrCore = solrCore;
+    this.info = info;
+    this.version = version;
+  }
+
+  @Override
+  public String packageName() {
+    return info.cName.pkg;
+  }
+
+  public SolrResourceLoader getLoader() {
+    return version.getLoader();
+  }
+  @Override
+  public PluginInfo pluginInfo() {
+    return info;
+  }
+
+  @Override
+  public void changed(PackageLoader.Package pkg, Ctx ctx) {
+    PackageLoader.Package.Version version = pkg.getLatest(solrCore.getSolrConfig().maxPackageVersion(info.cName.pkg));
+    if(version != this.version) {
+      ctx.runLater(SolrCore.class.getName(), () -> solrCore.getCoreContainer().reload(CoreRefreshingClassLoader.class.getName() , solrCore.uniqueId));
+    }
+  }
+
+  @Override
+  public PackageLoader.Package.Version getPackageVersion() {
+    return version;
+  }
+
+  @SuppressWarnings({"rawtypes","unchecked"})
+  public static Class loadClass(SolrCore core, PluginInfo info, Class type) {
+    return _get(core, info, version -> version.getLoader().findClass(info.cName.className, type));
+
+  }
+
+  private static  <T> T _get(SolrCore core, PluginInfo info, Function<PackageLoader.Package.Version, T> fun){
+    PluginInfo.CName cName = info.cName;
+    PackageLoader.Package.Version latest = core.getCoreContainer().getPackageLoader().getPackage(cName.pkg)
+            .getLatest(core.getSolrConfig().maxPackageVersion(cName.pkg));
+    T result = fun.apply(latest);
+    core.getPackageListeners().addListener(new CoreRefreshingClassLoader(core, info, latest));
+    return result;
+  }
+
+  public static <T> T createInst(SolrCore core, PluginInfo info, Class<T> type) {
+    if(info.cName.pkg == null) {
+      return core.getResourceLoader().newInstance(info.cName.className== null? type.getName(): info.cName.className , type);
+    }
+    return _get(core, info, version -> version.getLoader().newInstance(info.cName.className, type));
+  }
+
+}
diff --git a/solr/core/src/java/org/apache/solr/pkg/PackageListeners.java b/solr/core/src/java/org/apache/solr/pkg/PackageListeners.java
index b5b295f..a2b859e 100644
--- a/solr/core/src/java/org/apache/solr/pkg/PackageListeners.java
+++ b/solr/core/src/java/org/apache/solr/pkg/PackageListeners.java
@@ -20,10 +20,9 @@ package org.apache.solr.pkg;
 import java.lang.invoke.MethodHandles;
 import java.lang.ref.Reference;
 import java.lang.ref.SoftReference;
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
+import java.util.*;
 import java.util.concurrent.CopyOnWriteArrayList;
+
 import org.apache.solr.core.PluginInfo;
 import org.apache.solr.core.SolrCore;
 import org.apache.solr.logging.MDCLoggingContext;
@@ -64,21 +63,23 @@ public class PackageListeners {
 
   synchronized void packagesUpdated(List<PackageLoader.Package> pkgs) {
     MDCLoggingContext.setCore(core);
+    Listener.Ctx ctx = new Listener.Ctx();
     try {
       for (PackageLoader.Package pkgInfo : pkgs) {
-        invokeListeners(pkgInfo);
+        invokeListeners(pkgInfo, ctx);
       }
     } finally {
+      ctx.runLaterTasks();
       MDCLoggingContext.clear();
     }
   }
 
-  private synchronized void invokeListeners(PackageLoader.Package pkg) {
+  private synchronized void invokeListeners(PackageLoader.Package pkg, Listener.Ctx ctx) {
     for (Reference<Listener> ref : listeners) {
       Listener listener = ref.get();
       if(listener == null) continue;
       if (listener.packageName() == null || listener.packageName().equals(pkg.name())) {
-        listener.changed(pkg);
+        listener.changed(pkg, ctx);
       }
     }
   }
@@ -96,15 +97,32 @@ public class PackageListeners {
 
 
   public interface Listener {
-    /**Name of the package or null to loisten to all package changes
+    /**Name of the package or null to listen to all package changes
      */
     String packageName();
 
     PluginInfo pluginInfo();
 
-    void changed(PackageLoader.Package pkg);
+    void changed(PackageLoader.Package pkg, Ctx ctx);
 
     PackageLoader.Package.Version getPackageVersion();
+    class Ctx {
+      private Map<String, Runnable > runLater;
+      public void runLater(String name,  Runnable runnable  ){
+        if(runLater == null) runLater = new LinkedHashMap<>();
+        runLater.put(name, runnable);
+      }
+      private void runLaterTasks(){
+        if(runLater == null) return;
+        new Thread(() -> runLater.forEach((s, runnable) -> {
+          try {
+            runnable.run();
+          } catch (Exception e) {
+            log.error("Unknown error", e);
+          }
+        }));
+      }
+    }
 
   }
 }
diff --git a/solr/core/src/java/org/apache/solr/pkg/PackagePluginHolder.java b/solr/core/src/java/org/apache/solr/pkg/PackagePluginHolder.java
index 322a1d3..9df1ec3 100644
--- a/solr/core/src/java/org/apache/solr/pkg/PackagePluginHolder.java
+++ b/solr/core/src/java/org/apache/solr/pkg/PackagePluginHolder.java
@@ -55,7 +55,7 @@ public class PackagePluginHolder<T> extends PluginBag.PluginHolder<T> {
       }
 
       @Override
-      public void changed(PackageLoader.Package pkg) {
+      public void changed(PackageLoader.Package pkg, Ctx ctx) {
         reload(pkg);
 
       }
@@ -68,19 +68,17 @@ public class PackagePluginHolder<T> extends PluginBag.PluginHolder<T> {
     });
   }
 
-  private String maxVersion() {
-    RequestParams.ParamSet p = core.getSolrConfig().getRequestParams().getParams(PackageListeners.PACKAGE_VERSIONS);
-    if (p == null) {
-      return null;
+  @SuppressWarnings({"rawtypes", "unchecked"})
+  public static PluginBag.PluginHolder createHolder(PluginInfo info, SolrCore core, Class type, String msg) {
+    if(info.cName.pkg == null) {
+      return new PluginBag.PluginHolder(info, core.createInitInstance(info, type,msg, null));
+    } else {
+      return new PackagePluginHolder(info, core, SolrConfig.classVsSolrPluginInfo.get(type.getName()));
     }
-    Object o = p.get().get(info.pkgName);
-    if (o == null || LATEST.equals(o)) return null;
-    return o.toString();
   }
 
-
   private synchronized void reload(PackageLoader.Package pkg) {
-    String lessThan = maxVersion();
+    String lessThan = core.getSolrConfig().maxPackageVersion(info.pkgName);
     PackageLoader.Package.Version newest = pkg.getLatest(lessThan);
     if (newest == null) {
       log.error("No latest version available for package : {}", pkg.name());
@@ -113,7 +111,7 @@ public class PackagePluginHolder<T> extends PluginBag.PluginHolder<T> {
   }
 
   @SuppressWarnings({"unchecked"})
-  protected void initNewInstance(PackageLoader.Package.Version newest) {
+  protected Object initNewInstance(PackageLoader.Package.Version newest) {
     Object instance = SolrCore.createInstance(pluginInfo.className,
         pluginMeta.clazz, pluginMeta.getCleanTag(), core, newest.getLoader());
     PluginBag.initInstance(instance, pluginInfo);
@@ -128,6 +126,7 @@ public class PackagePluginHolder<T> extends PluginBag.PluginHolder<T> {
         log.error("error closing plugin", e);
       }
     }
+    return inst;
   }
 
   private void handleAwareCallbacks(SolrResourceLoader loader, Object instance) {
diff --git a/solr/core/src/java/org/apache/solr/search/CacheConfig.java b/solr/core/src/java/org/apache/solr/search/CacheConfig.java
index 6470915..8b9a458 100644
--- a/solr/core/src/java/org/apache/solr/search/CacheConfig.java
+++ b/solr/core/src/java/org/apache/solr/search/CacheConfig.java
@@ -23,12 +23,15 @@ import java.util.HashMap;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.function.Supplier;
 
 import org.apache.solr.common.SolrException;
 import org.apache.solr.common.util.StrUtils;
 import org.apache.solr.common.MapSerializable;
+import org.apache.solr.core.PluginInfo;
 import org.apache.solr.core.SolrConfig;
 import org.apache.solr.core.SolrResourceLoader;
+import org.apache.solr.pkg.CoreRefreshingClassLoader;
 import org.apache.solr.util.DOMUtil;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -50,7 +53,7 @@ public class CacheConfig implements MapSerializable{
   private String nodeName;
 
   @SuppressWarnings({"rawtypes"})
-  private Class<? extends SolrCache> clazz;
+  private Supplier<Class<? extends SolrCache>> clazz;
   private Map<String,String> args;
   private CacheRegenerator regenerator;
 
@@ -64,7 +67,7 @@ public class CacheConfig implements MapSerializable{
 
   @SuppressWarnings({"rawtypes"})
   public CacheConfig(Class<? extends SolrCache> clazz, Map<String,String> args, CacheRegenerator regenerator) {
-    this.clazz = clazz;
+    this.clazz = () -> clazz;
     this.args = args;
     this.regenerator = regenerator;
   }
@@ -134,8 +137,14 @@ public class CacheConfig implements MapSerializable{
     SolrResourceLoader loader = solrConfig.getResourceLoader();
     config.cacheImpl = config.args.get("class");
     if(config.cacheImpl == null) config.cacheImpl = "solr.CaffeineCache";
+    config.clazz = () -> {
+      PluginInfo.CName cName = new PluginInfo.CName(config.cacheImpl);
+      if(cName.pkg == null) return loader.findClass(cName.className, SolrCache.class);
+      return CoreRefreshingClassLoader.loadClass(loader.getCore(),
+              new PluginInfo("cache", Collections.singletonMap("class", config.cacheImpl)),
+              SolrCache.class);
+    };
     config.regenImpl = config.args.get("regenerator");
-    config.clazz = loader.findClass(config.cacheImpl, SolrCache.class);
     if (config.regenImpl != null) {
       config.regenerator = loader.newInstance(config.regenImpl, CacheRegenerator.class);
     }
@@ -146,7 +155,7 @@ public class CacheConfig implements MapSerializable{
   @SuppressWarnings({"rawtypes"})
   public SolrCache newInstance() {
     try {
-      SolrCache cache = clazz.getConstructor().newInstance();
+      SolrCache cache = clazz.get().getConstructor().newInstance();
       persistence[0] = cache.init(args, persistence[0], regenerator);
       return cache;
     } catch (Exception e) {
diff --git a/solr/core/src/java/org/apache/solr/update/UpdateHandler.java b/solr/core/src/java/org/apache/solr/update/UpdateHandler.java
index 37397f7..6a5eb18 100644
--- a/solr/core/src/java/org/apache/solr/update/UpdateHandler.java
+++ b/solr/core/src/java/org/apache/solr/update/UpdateHandler.java
@@ -20,13 +20,11 @@ import java.io.IOException;
 import java.lang.invoke.MethodHandles;
 import java.util.Vector;
 
-import org.apache.solr.core.DirectoryFactory;
-import org.apache.solr.core.HdfsDirectoryFactory;
-import org.apache.solr.core.PluginInfo;
-import org.apache.solr.core.SolrCore;
-import org.apache.solr.core.SolrEventListener;
-import org.apache.solr.core.SolrInfoBean;
+import org.apache.solr.core.*;
+import org.apache.solr.core.PluginBag.PluginHolder;
 import org.apache.solr.metrics.SolrMetricsContext;
+import org.apache.solr.pkg.CoreRefreshingClassLoader;
+import org.apache.solr.pkg.PackagePluginHolder;
 import org.apache.solr.schema.FieldType;
 import org.apache.solr.schema.SchemaField;
 import org.apache.solr.util.plugin.SolrCoreAware;
@@ -48,25 +46,26 @@ public abstract class UpdateHandler implements SolrInfoBean {
   protected final SchemaField idField;
   protected final FieldType idFieldType;
 
-  protected Vector<SolrEventListener> commitCallbacks = new Vector<>();
-  protected Vector<SolrEventListener> softCommitCallbacks = new Vector<>();
-  protected Vector<SolrEventListener> optimizeCallbacks = new Vector<>();
+  protected Vector<PluginHolder<SolrEventListener>> commitCallbacks = new Vector<>();
+  protected Vector<PluginHolder<SolrEventListener>> softCommitCallbacks = new Vector<>();
+  protected Vector<PluginHolder<SolrEventListener>> optimizeCallbacks = new Vector<>();
 
   protected final UpdateLog ulog;
 
   protected SolrMetricsContext solrMetricsContext;
 
+  @SuppressWarnings("unchecked")
   private void parseEventListeners() {
     final Class<SolrEventListener> clazz = SolrEventListener.class;
     final String label = "Event Listener";
     for (PluginInfo info : core.getSolrConfig().getPluginInfos(SolrEventListener.class.getName())) {
       String event = info.attributes.get("event");
       if ("postCommit".equals(event)) {
-        SolrEventListener obj = core.createInitInstance(info,clazz,label,null);
+        PluginHolder<SolrEventListener> obj = PackagePluginHolder.createHolder(info, core, SolrEventListener.class, label);
         commitCallbacks.add(obj);
         log.info("added SolrEventListener for postCommit: {}", obj);
       } else if ("postOptimize".equals(event)) {
-        SolrEventListener obj = core.createInitInstance(info,clazz,label,null);
+        PluginHolder<SolrEventListener> obj = PackagePluginHolder.createHolder(info, core, SolrEventListener.class, label);
         optimizeCallbacks.add(obj);
         log.info("added SolrEventListener for postOptimize: {}", obj);
       }
@@ -77,33 +76,35 @@ public abstract class UpdateHandler implements SolrInfoBean {
    * Call the {@link SolrCoreAware#inform(SolrCore)} on all the applicable registered listeners.
    */
   public void informEventListeners(SolrCore core) {
-    for (SolrEventListener listener: commitCallbacks) {
-      if (listener instanceof SolrCoreAware) {
-        ((SolrCoreAware) listener).inform(core);
+    for (PluginHolder<SolrEventListener>  listener: commitCallbacks) {
+      if(listener instanceof PackagePluginHolder)continue;
+      if (listener.get() instanceof SolrCoreAware) {
+        ((SolrCoreAware) listener.get()).inform(core);
       }
     }
-    for (SolrEventListener listener: optimizeCallbacks) {
-      if (listener instanceof SolrCoreAware) {
-        ((SolrCoreAware) listener).inform(core);
+    for (PluginHolder<SolrEventListener> listener: optimizeCallbacks) {
+      if(listener instanceof PackagePluginHolder)continue;
+      if (listener.get() instanceof SolrCoreAware) {
+        ((SolrCoreAware) listener.get()).inform(core);
       }
     }
   }
 
   protected void callPostCommitCallbacks() {
-    for (SolrEventListener listener : commitCallbacks) {
-      listener.postCommit();
+    for (PluginHolder<SolrEventListener> listener : commitCallbacks) {
+      listener.get(). postCommit();
     }
   }
 
   protected void callPostSoftCommitCallbacks() {
-    for (SolrEventListener listener : softCommitCallbacks) {
-      listener.postSoftCommit();
+    for (PluginHolder<SolrEventListener>  listener : softCommitCallbacks) {
+      listener.get().postSoftCommit();
     }
   }
 
   protected void callPostOptimizeCallbacks() {
-    for (SolrEventListener listener : optimizeCallbacks) {
-      listener.postCommit();
+    for (PluginHolder<SolrEventListener> listener : optimizeCallbacks) {
+      listener.get().postCommit();
     }
   }
 
@@ -125,8 +126,8 @@ public abstract class UpdateHandler implements SolrInfoBean {
       if (dirFactory instanceof HdfsDirectoryFactory) {
         ulog = new HdfsUpdateLog(((HdfsDirectoryFactory)dirFactory).getConfDir());
       } else {
-        String className = ulogPluginInfo.className == null ? UpdateLog.class.getName() : ulogPluginInfo.className;
-        ulog = core.getResourceLoader().newInstance(className, UpdateLog.class);
+        ulog = ulogPluginInfo.className == null ? new UpdateLog():
+                CoreRefreshingClassLoader.createInst(core, ulogPluginInfo, UpdateLog.class);
       }
 
       if (!core.isReloaded() && !dirFactory.isPersistent()) {
@@ -172,7 +173,7 @@ public abstract class UpdateHandler implements SolrInfoBean {
    */
   public void registerCommitCallback( SolrEventListener listener )
   {
-    commitCallbacks.add( listener );
+    commitCallbacks.add( new PluginHolder<>(listener, SolrConfig.classVsSolrPluginInfo.get(SolrEventListener.class.getName())) );
   }
 
   /**
@@ -184,7 +185,7 @@ public abstract class UpdateHandler implements SolrInfoBean {
    */
   public void registerSoftCommitCallback( SolrEventListener listener )
   {
-    softCommitCallbacks.add( listener );
+    softCommitCallbacks.add( new PluginHolder<>(listener, SolrConfig.classVsSolrPluginInfo.get(SolrEventListener.class.getName())) );
   }
 
   /**
@@ -196,7 +197,7 @@ public abstract class UpdateHandler implements SolrInfoBean {
    */
   public void registerOptimizeCallback( SolrEventListener listener )
   {
-    optimizeCallbacks.add( listener );
+    optimizeCallbacks.add( new PluginHolder<>(listener, SolrConfig.classVsSolrPluginInfo.get(SolrEventListener.class.getName())) );
   }
 
   public abstract void split(SplitIndexCommand cmd) throws IOException;
diff --git a/solr/core/src/test/org/apache/solr/core/TestQuerySenderListener.java b/solr/core/src/test/org/apache/solr/core/TestQuerySenderListener.java
index ad564c2..0d66abe 100644
--- a/solr/core/src/test/org/apache/solr/core/TestQuerySenderListener.java
+++ b/solr/core/src/test/org/apache/solr/core/TestQuerySenderListener.java
@@ -60,7 +60,8 @@ public class TestQuerySenderListener extends SolrTestCaseJ4 {
   @Test
   public void testSearcherEvents() throws Exception {
     SolrCore core = h.getCore();
-    SolrEventListener newSearcherListener = core.newSearcherListeners.get(0);
+    SolrEventListener newSearcherListener = core.newSearcherListeners.get(0).get();
+
     assertTrue("Not an instance of QuerySenderListener", newSearcherListener instanceof QuerySenderListener);
     QuerySenderListener qsl = (QuerySenderListener) newSearcherListener;
 
diff --git a/solr/core/src/test/org/apache/solr/core/TestQuerySenderNoQuery.java b/solr/core/src/test/org/apache/solr/core/TestQuerySenderNoQuery.java
index a44fe3c..e113137 100644
--- a/solr/core/src/test/org/apache/solr/core/TestQuerySenderNoQuery.java
+++ b/solr/core/src/test/org/apache/solr/core/TestQuerySenderNoQuery.java
@@ -61,7 +61,7 @@ public class TestQuerySenderNoQuery extends SolrTestCaseJ4 {
   @Test
   public void testSearcherEvents() throws Exception {
     SolrCore core = h.getCore();
-    SolrEventListener newSearcherListener = core.newSearcherListeners.get(0);
+    SolrEventListener newSearcherListener = core.newSearcherListeners.get(0).get();
     assertTrue("Not an instance of QuerySenderListener", newSearcherListener instanceof QuerySenderListener);
     QuerySenderListener qsl = (QuerySenderListener) newSearcherListener;