Skip to content

Commit

Permalink
Merge pull request #33760 from mkouba/arc-speedup-beanmanagergetbeans
Browse files Browse the repository at this point in the history
ArC: speed up bean resolution at runtime
  • Loading branch information
mkouba authored Jun 5, 2023
2 parents 0fa62d8 + d582a45 commit ca0ad11
Showing 1 changed file with 71 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.stream.Collectors;
Expand Down Expand Up @@ -80,6 +81,7 @@ public class ArcContainerImpl implements ArcContainer {
private final AtomicBoolean running;

private final List<InjectableBean<?>> beans;
private final Map<String, List<InjectableBean<?>>> beansByRawType;
private final LazyValue<List<RemovedBean>> removedBeans;
private final List<InjectableInterceptor<?>> interceptors;
private final List<InjectableDecorator<?>> decorators;
Expand All @@ -106,6 +108,7 @@ public ArcContainerImpl(CurrentContextFactory currentContextFactory, boolean str
id = String.valueOf(ID_GENERATOR.incrementAndGet());
running = new AtomicBoolean(true);
List<InjectableBean<?>> beans = new ArrayList<>();
Map<String, List<InjectableBean<?>>> beansByRawType = new HashMap<>();
List<Supplier<Collection<RemovedBean>>> removedBeans = new ArrayList<>();
List<InjectableInterceptor<?>> interceptors = new ArrayList<>();
List<InjectableDecorator<?>> decorators = new ArrayList<>();
Expand All @@ -130,6 +133,7 @@ public ArcContainerImpl(CurrentContextFactory currentContextFactory, boolean str
decorators.add((InjectableDecorator<?>) bean);
} else {
beans.add(bean);
precomputeBeanRawTypes(beansByRawType, bean);
}
}
removedBeans.add(c.getRemovedBeans());
Expand All @@ -141,7 +145,7 @@ public ArcContainerImpl(CurrentContextFactory currentContextFactory, boolean str
}

// register built-in beans
addBuiltInBeans(beans);
addBuiltInBeans(beans, beansByRawType);

interceptors.sort(Comparator.comparingInt(InjectableInterceptor::getPriority));
decorators.sort(Comparator.comparingInt(InjectableDecorator::getPriority));
Expand All @@ -158,6 +162,17 @@ public ArcContainerImpl(CurrentContextFactory currentContextFactory, boolean str
instance = InstanceImpl.forGlobalEntrypoint(Object.class, Collections.emptySet());

this.beans = List.copyOf(beans);
this.beansByRawType = Map.copyOf(beansByRawType);
// Trim the size of the non-singleton lists
this.beansByRawType.forEach(new BiConsumer<String, List<InjectableBean<?>>>() {
@Override
public void accept(String key, List<InjectableBean<?>> val) {
if (val.size() > 1) {
((ArrayList<InjectableBean<?>>) val).trimToSize();
}
}
});

this.interceptors = List.copyOf(interceptors);
this.decorators = List.copyOf(decorators);
this.observers = List.copyOf(observers);
Expand Down Expand Up @@ -202,6 +217,38 @@ public List<RemovedBean> get() {
this.contexts = contextsBuilder.build();
}

static void precomputeBeanRawTypes(Map<String, List<InjectableBean<?>>> map, InjectableBean<?> bean) {
for (Type type : bean.getTypes()) {
if (Object.class.equals(type)) {
continue;
}
Class<?> rawType = Types.getRawType(type);
if (rawType == null) {
continue;
}
rawType = Types.boxedClass(rawType);
String key = rawType.getName();
List<InjectableBean<?>> match = map.get(key);
if (match == null) {
// very often a singleton list will be used
map.put(key, List.of(bean));
} else {
// we don't expect large lists so this should be fine performance wise
if (match.contains(bean)) {
continue;
}
if (match.size() == 1) {
List<InjectableBean<?>> newMatch = new ArrayList<>();
newMatch.add(match.get(0));
newMatch.add(bean);
map.put(key, newMatch);
} else {
match.add(bean);
}
}
}
}

public void init() {
// Fire an event with qualifier @Initialized(ApplicationScoped.class)
Set<Annotation> qualifiers = Set.of(Initialized.Literal.APPLICATION, Any.Literal.INSTANCE);
Expand Down Expand Up @@ -462,12 +509,19 @@ private Notifier<Object> notifierOrNull(Set<Annotation> qualifiers) {
return notifier.isEmpty() ? null : notifier;
}

private static void addBuiltInBeans(List<InjectableBean<?>> beans) {
private static void addBuiltInBeans(List<InjectableBean<?>> beans, Map<String, List<InjectableBean<?>>> beansByRawType) {
// BeanManager, Event<?>, Instance<?>, InjectionPoint
beans.add(new BeanManagerBean());
beans.add(new EventBean());
BeanManagerBean beanManagerBean = new BeanManagerBean();
beans.add(beanManagerBean);
precomputeBeanRawTypes(beansByRawType, beanManagerBean);
EventBean eventBean = new EventBean();
beans.add(eventBean);
precomputeBeanRawTypes(beansByRawType, eventBean);
beans.add(InstanceBean.INSTANCE);
beans.add(new InjectionPointBean());
precomputeBeanRawTypes(beansByRawType, InstanceBean.INSTANCE);
InjectionPointBean injectionPointBean = new InjectionPointBean();
beans.add(injectionPointBean);
precomputeBeanRawTypes(beansByRawType, injectionPointBean);
}

private <T> InstanceHandle<T> instanceHandle(Type type, Annotation... qualifiers) {
Expand Down Expand Up @@ -680,14 +734,25 @@ private static Integer getAlternativePriority(InjectableBean<?> bean) {

List<InjectableBean<?>> getMatchingBeans(Resolvable resolvable) {
List<InjectableBean<?>> matching = new ArrayList<>();
for (InjectableBean<?> bean : beans) {
for (InjectableBean<?> bean : potentialBeans(resolvable.requiredType)) {
if (matches(bean, resolvable.requiredType, resolvable.qualifiers)) {
matching.add(bean);
}
}
return matching;
}

Iterable<InjectableBean<?>> potentialBeans(Type type) {
if (!Object.class.equals(type)) {
Class<?> rawType = Types.getRawType(type);
if (rawType != null) {
List<InjectableBean<?>> match = beansByRawType.get(Types.boxedClass(rawType).getName());
return match == null ? List.of() : match;
}
}
return beans;
}

List<RemovedBean> getMatchingRemovedBeans(Resolvable resolvable) {
List<RemovedBean> matching = new ArrayList<>();
for (RemovedBean removedBean : removedBeans.get()) {
Expand Down

0 comments on commit ca0ad11

Please sign in to comment.