Skip to content

Commit

Permalink
Merge pull request #205 from jd-opensource/7-improve-startup-performance
Browse files Browse the repository at this point in the history
7-improve-startup-performance
  • Loading branch information
chenzhiguo authored Jan 10, 2025
2 parents af53bb0 + 9ae34c9 commit 4e10ce8
Show file tree
Hide file tree
Showing 29 changed files with 1,132 additions and 496 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,11 @@ public LiveClassLoader(URL[] urls, ClassLoader parent, ResourcerType type, Resou
this.name = (name == null || name.isEmpty()) && type != null ? type.getName() : name;
}

@Override
public String getId() {
return name;
}

/**
* Attempts to find a class in the cache, loading and caching it if not already present.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,7 @@ public interface URLResourcer extends Resourcer {
* @param urls An array of URLs to add.
*/
void add(URL... urls);

String getId();
}

Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,15 @@
package com.jd.live.agent.core.bytekit.matcher;

import com.jd.live.agent.core.bytekit.type.NamedElement;
import lombok.Getter;

/**
* NameMatcher
*
* @param <T> Match target type
* @since 1.0.0
*/
@Getter
public class NameMatcher<T extends NamedElement> extends AbstractJunction<T> {

private final ElementMatcher<String> matcher;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,16 @@
*/
package com.jd.live.agent.core.bytekit.matcher;

import lombok.Getter;

/**
* StringMatcher
*
* <p>Implement according to `net.bytebuddy.matcher.StringMatcher`</p>
*
* @since 1.0.0
*/
@Getter
public class StringMatcher extends AbstractJunction<String> {

private final String value;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,10 @@
*/
package com.jd.live.agent.core.bytekit.matcher;

import com.jd.live.agent.core.bytekit.type.TypeDef;
import com.jd.live.agent.bootstrap.logger.Logger;
import com.jd.live.agent.bootstrap.logger.LoggerFactory;
import com.jd.live.agent.core.bytekit.type.TypeDesc;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import com.jd.live.agent.core.util.cache.UnsafeLazyObject;


/**
Expand All @@ -30,6 +29,8 @@
*/
public class SubTypeMatcher<T extends TypeDesc> extends AbstractJunction<T> {

private static final Logger logger = LoggerFactory.getLogger(SubTypeMatcher.class);

private final Class<?> type;

private final boolean implement;
Expand All @@ -50,12 +51,12 @@ public boolean match(T target) {

public static class SubNameMatcher<T extends TypeDesc> extends AbstractJunction<T> {

private static final Map<String, Set<String>> TYPES = new ConcurrentHashMap<>();

private final String type;

private final boolean implement;

private final UnsafeLazyObject<Class<?>> optional = new UnsafeLazyObject<>(this::getType);

public SubNameMatcher(String type) {
this(type, false);
}
Expand All @@ -70,39 +71,18 @@ public boolean match(T target) {
if (target == null || type == null || type.isEmpty() || implement && target.isInterface()) {
return false;
}
return TYPES.computeIfAbsent(target.getActualName(), k -> loadTypes(target)).contains(type);
Class<?> type = optional.get();
return type != null && target.isAssignableTo(type);
}

/**
* Loads all the types that are part of the inheritance hierarchy of the given type definition.
*
* @param typeDef The type definition to start from.
* @return A set of strings representing the names of all the types in the inheritance hierarchy.
*/
private Set<String> loadTypes(TypeDesc typeDef) {
Set<String> result = new HashSet<>();
Queue<TypeDesc> queue = new ArrayDeque<>();
result.add(typeDef.getActualName());
queue.add(typeDef);
TypeDef current;
TypeDesc desc;
while (!queue.isEmpty()) {
current = queue.poll();
for (TypeDesc.Generic generic : current.getInterfaces()) {
desc = generic.asErasure();
if (result.add(desc.getActualName())) {
queue.add(desc);
}
}
TypeDesc.Generic parent = current.getSuperClass();
if (parent != null) {
desc = parent.asErasure();
if (result.add(desc.getActualName())) {
queue.add(desc);
}
}
private Class<?> getType() {
try {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
return classLoader != null ? classLoader.loadClass(type) : Class.forName(type);
} catch (Throwable e) {
logger.error("class is not found in context class loader. " + type);
return null;
}
return result;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,14 @@ public class EnhanceConfig {

public static final String COMPONENT_ENHANCE_CONFIG = "enhanceConfig";

private static final int DEFAULT_POOL_CLEAN_INTERVAL = 60 * 1000;

private String javaVersion = SUPPORT_JAVA_VERSION;

private long poolExpireTime = 10 * 60 * 1000;

private long poolCleanInterval = DEFAULT_POOL_CLEAN_INTERVAL;

/**
* exclude class name prefix
*/
Expand Down Expand Up @@ -87,4 +93,8 @@ public boolean isExclude(Class<?> type) {
}
return false;
}

public long getPoolCleanInterval() {
return poolCleanInterval <= 0 ? DEFAULT_POOL_CLEAN_INTERVAL : poolCleanInterval;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,20 @@ public class PluginConfig {

private String profile;

public boolean isActive(String name, boolean dynamicMode) {
if (isDisable(name)) {
return false;
} else if (isSystem(name)) {
return true;
} else if (!dynamicMode && !isStatic(name)) {
return false;
} else if (profile == null || profile.isEmpty() || profiles == null) {
public boolean isSystemActive(String name) {
return isEnabled(name) && isSystem(name);
}

public boolean isStaticActive(String name) {
return isEnabled(name) && isStatic(name) && isProfileActive(name);
}

public boolean isDynamicActive(String name) {
return isEnabled(name) && isDynamic(name) && isProfileActive(name);
}

public boolean isProfileActive(String name) {
if (profile == null || profile.isEmpty() || profiles == null) {
return true;
} else {
Set<String> profileSet = profiles.get(profile);
Expand All @@ -67,8 +73,8 @@ public boolean isStatic(String name) {
return statics != null && statics.contains(name);
}

public boolean isDisable(String name) {
return disables != null && disables.contains(name);
public boolean isEnabled(String name) {
return disables == null || !disables.contains(name);
}

public boolean isDynamic(String name) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
package com.jd.live.agent.core.plugin.definition;

import com.jd.live.agent.bootstrap.plugin.PluginPublisher;
import com.jd.live.agent.core.bytekit.type.TypeDesc;

import java.util.List;

Expand All @@ -41,6 +42,15 @@ public interface PluginDeclare extends PluginPublisher {
*/
List<PluginDefinition> getDefinitions();

/**
* Matches the plugin definitions with the given {@link TypeDesc}.
*
* @param typeDesc the type descriptor to match against the plugin definitions
* @return A list of {@link PluginDefinition} instances that match the given type descriptor,
* or an empty list if no matches are found.
*/
List<PluginDefinition> match(TypeDesc typeDesc, ClassLoader classLoader);

/**
* Determines whether the plugin does not contain any definitions.
*
Expand All @@ -50,12 +60,4 @@ default boolean isEmpty() {
List<PluginDefinition> definitions = getDefinitions();
return definitions == null || definitions.isEmpty();
}

/**
* Retrieves the class loader associated with the plugin. This class loader is used to load the plugin's
* classes and resources.
*
* @return The {@link ClassLoader} associated with the plugin.
*/
ClassLoader getClassLoader();
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,27 @@ public class CollectionUtils {

private static final FieldDesc MAP_FIELD = ClassUtils.describe(UNMODIFIED_MAP_CLASS).getFieldList().getField("m");

/**
* Adds all elements from the source collection to the target collection that satisfy the given predicate.
* If the predicate is null, all elements from the source collection are added to the target collection.
* If either the source or target collection is null, this method does nothing.
*
* @param <T> the type of elements in the collections
* @param source the source collection from which elements are to be added
* @param target the target collection to which elements are to be added
* @param predicate the predicate to test elements before adding them to the target collection (can be null)
*/
public static <T> void add(Collection<T> source, Collection<T> target, Predicate<T> predicate) {
if (source == null || target == null) {
return;
}
for (T t : source) {
if (predicate == null || predicate.test(t)) {
target.add(t);
}
}
}

/**
* Filters the provided list of objects based on the given predicate.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
* Copyright © ${year} ${owner} (${email})
*
* Licensed 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 com.jd.live.agent.core.util;

import java.util.concurrent.Callable;

/**
* Utility class for executing tasks with a specific context class loader.
*/
public class Executors {

/**
* Executes the specified Runnable using the provided ClassLoader as the context class loader.
* If the ClassLoader is null, the Runnable is executed with the current context class loader.
* After execution, the original context class loader is restored.
*
* @param classLoader the ClassLoader to be set as the context class loader for the execution of the Runnable (can be null)
* @param runnable the Runnable to be executed (can be null)
*/
public static void execute(ClassLoader classLoader, Runnable runnable) {
ClassLoader old = Thread.currentThread().getContextClassLoader();
try {
Thread.currentThread().setContextClassLoader(classLoader);
runnable.run();
} finally {
Thread.currentThread().setContextClassLoader(old);
}
}

/**
* Executes the specified Callable using the provided ClassLoader as the context class loader.
* After execution, the original context class loader is restored.
*
* @param classLoader the ClassLoader to be set as the context class loader for the execution of the Callable
* @param callable the Callable to be executed
* @param <T> the type of the result returned by the Callable
* @return the result of the Callable's computation
* @throws Exception if the Callable throws an exception
*/
public static <T> T execute(ClassLoader classLoader, Callable<T> callable) throws Exception {
ClassLoader old = Thread.currentThread().getContextClassLoader();
try {
Thread.currentThread().setContextClassLoader(classLoader);
return callable.call();
} finally {
Thread.currentThread().setContextClassLoader(old);
}
}
}


Original file line number Diff line number Diff line change
Expand Up @@ -580,7 +580,7 @@ private void addConfigWatcher() {

private PluginSupervisor createPluginManager() {
return new PluginManager(instrumentation, agentConfig.getPluginConfig(), agentPath, extensionManager,
classLoaderManager.getPluginLoaders(), byteSupplier);
classLoaderManager.getPluginLoaders(), byteSupplier, conditionMatcher);
}

private ClassLoaderManager createClassLoaderManager() {
Expand Down
Loading

0 comments on commit 4e10ce8

Please sign in to comment.