You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openwebbeans.apache.org by rm...@apache.org on 2020/03/11 15:09:36 UTC

[openwebbeans] branch master updated: OWB-1316 make event bus faster when using Event class

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

rmannibucau pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/openwebbeans.git


The following commit(s) were added to refs/heads/master by this push:
     new 50a9746  OWB-1316 make event bus faster when using Event class
50a9746 is described below

commit 50a97460d3e824f298c52f98195a7d7ea5ac52af
Author: Romain Manni-Bucau <rm...@apache.org>
AuthorDate: Wed Mar 11 16:09:26 2020 +0100

    OWB-1316 make event bus faster when using Event class
---
 .../webbeans/annotation/AnnotationManager.java     |   1 +
 .../apache/webbeans/config/WebBeansContext.java    |  12 ++
 .../webbeans/context/AbstractContextsService.java  |  19 ++
 .../webbeans/corespi/se/BaseSeContextsService.java |  33 +++-
 .../java/org/apache/webbeans/event/EventImpl.java  | 174 ++++++++++++++++-
 .../apache/webbeans/event/NotificationManager.java | 215 ++++++++++++---------
 .../apache/webbeans/event/ObserverMethodImpl.java  |  43 +++--
 .../webbeans/web/context/WebContextsService.java   |  17 --
 8 files changed, 379 insertions(+), 135 deletions(-)

diff --git a/webbeans-impl/src/main/java/org/apache/webbeans/annotation/AnnotationManager.java b/webbeans-impl/src/main/java/org/apache/webbeans/annotation/AnnotationManager.java
index 771be4b..24033f4 100644
--- a/webbeans-impl/src/main/java/org/apache/webbeans/annotation/AnnotationManager.java
+++ b/webbeans-impl/src/main/java/org/apache/webbeans/annotation/AnnotationManager.java
@@ -417,6 +417,7 @@ public final class AnnotationManager
         {
             // performance hack to avoid Set creation
             checkQualifierConditions(qualifierAnnots[0]);
+            return;
         }
 
         Set<Annotation> annSet = ArrayUtil.asSet(qualifierAnnots);
diff --git a/webbeans-impl/src/main/java/org/apache/webbeans/config/WebBeansContext.java b/webbeans-impl/src/main/java/org/apache/webbeans/config/WebBeansContext.java
index 848162f..c12eff6 100644
--- a/webbeans-impl/src/main/java/org/apache/webbeans/config/WebBeansContext.java
+++ b/webbeans-impl/src/main/java/org/apache/webbeans/config/WebBeansContext.java
@@ -66,6 +66,7 @@ import org.apache.webbeans.spi.ConversationService;
 import org.apache.webbeans.spi.LoaderService;
 import org.apache.webbeans.spi.ScannerService;
 import org.apache.webbeans.spi.SecurityService;
+import org.apache.webbeans.spi.TransactionService;
 import org.apache.webbeans.spi.plugins.OpenWebBeansPlugin;
 import org.apache.webbeans.util.ClassUtil;
 import org.apache.webbeans.util.WebBeansUtil;
@@ -114,6 +115,7 @@ public class WebBeansContext
     private ConversationService conversationService;
     private final ApplicationBoundaryService applicationBoundaryService;
     private final NotificationManager notificationManager;
+    private TransactionService transactionService;
 
 
     public WebBeansContext()
@@ -342,6 +344,16 @@ public class WebBeansContext
         return subclassProxyFactory;
     }
 
+    public TransactionService getTransactionService() // used in event bus so ensure it is a plain getter at runtime
+    {
+        if (transactionService == null)
+        {
+            // lazy init
+            transactionService = getService(TransactionService.class);
+        }
+        return transactionService;
+    }
+
     public ScannerService getScannerService()
     {
         if (scannerService == null)
diff --git a/webbeans-impl/src/main/java/org/apache/webbeans/context/AbstractContextsService.java b/webbeans-impl/src/main/java/org/apache/webbeans/context/AbstractContextsService.java
index a1f2033..43ec3c0 100644
--- a/webbeans-impl/src/main/java/org/apache/webbeans/context/AbstractContextsService.java
+++ b/webbeans-impl/src/main/java/org/apache/webbeans/context/AbstractContextsService.java
@@ -26,9 +26,13 @@ import javax.enterprise.context.ContextException;
 import javax.enterprise.context.SessionScoped;
 import javax.enterprise.context.spi.Context;
 
+import org.apache.webbeans.annotation.BeforeDestroyedLiteral;
+import org.apache.webbeans.annotation.DestroyedLiteral;
+import org.apache.webbeans.annotation.InitializedLiteral;
 import org.apache.webbeans.config.WebBeansContext;
 import org.apache.webbeans.conversation.ConversationImpl;
 import org.apache.webbeans.conversation.ConversationManager;
+import org.apache.webbeans.event.NotificationManager;
 import org.apache.webbeans.spi.ContextsService;
 
 public abstract class AbstractContextsService implements ContextsService
@@ -37,6 +41,7 @@ public abstract class AbstractContextsService implements ContextsService
 
     protected boolean supportsConversation;
 
+    protected Boolean fireRequestLifecycleEvents;
 
     protected AbstractContextsService(WebBeansContext webBeansContext)
     {
@@ -137,4 +142,18 @@ public abstract class AbstractContextsService implements ContextsService
     {
         return supportsConversation;
     }
+
+    protected boolean shouldFireRequestLifecycleEvents()
+    {
+        if (fireRequestLifecycleEvents == null)
+        {
+            NotificationManager notificationManager = webBeansContext.getNotificationManager();
+            fireRequestLifecycleEvents
+                    = notificationManager.hasContextLifecycleObserver(InitializedLiteral.INSTANCE_REQUEST_SCOPED) ||
+                    notificationManager.hasContextLifecycleObserver(BeforeDestroyedLiteral.INSTANCE_REQUEST_SCOPED) ||
+                    notificationManager.hasContextLifecycleObserver(DestroyedLiteral.INSTANCE_REQUEST_SCOPED) ;
+        }
+
+        return fireRequestLifecycleEvents;
+    }
 }
diff --git a/webbeans-impl/src/main/java/org/apache/webbeans/corespi/se/BaseSeContextsService.java b/webbeans-impl/src/main/java/org/apache/webbeans/corespi/se/BaseSeContextsService.java
index 11ea0db..9bd65cb 100644
--- a/webbeans-impl/src/main/java/org/apache/webbeans/corespi/se/BaseSeContextsService.java
+++ b/webbeans-impl/src/main/java/org/apache/webbeans/corespi/se/BaseSeContextsService.java
@@ -332,8 +332,11 @@ public abstract class BaseSeContextsService extends AbstractContextsService
         ctx.setActive(true);
         
         requestContext.set(ctx);
-        webBeansContext.getBeanManagerImpl().fireContextLifecyleEvent(
-            new Object(), InitializedLiteral.INSTANCE_REQUEST_SCOPED);
+        if (shouldFireRequestLifecycleEvents())
+        {
+            webBeansContext.getBeanManagerImpl().fireContextLifecyleEvent(
+                    ctx, InitializedLiteral.INSTANCE_REQUEST_SCOPED);
+        }
     }
 
     
@@ -395,18 +398,28 @@ public abstract class BaseSeContextsService extends AbstractContextsService
             conversationContext.remove();
         }
 
-        webBeansContext.getBeanManagerImpl().fireContextLifecyleEvent(
-                new Object(), BeforeDestroyedLiteral.INSTANCE_REQUEST_SCOPED);
-        if(requestContext.get() != null)
+
+        if (shouldFireRequestLifecycleEvents())
         {
-            requestContext.get().destroy();   
+            webBeansContext.getBeanManagerImpl().fireContextLifecyleEvent(
+                    new Object(), BeforeDestroyedLiteral.INSTANCE_REQUEST_SCOPED);
         }
 
-        requestContext.set(null);
-        requestContext.remove();
+        final RequestContext ctx = BaseSeContextsService.requestContext.get();
+        if (ctx != null)
+        {
+            ctx.destroy();
+        }
+
+        BaseSeContextsService.requestContext.set(null);
+        BaseSeContextsService.requestContext.remove();
         RequestScopedBeanInterceptorHandler.removeThreadLocals();
-        webBeansContext.getBeanManagerImpl().fireContextLifecyleEvent(
-            new Object(), DestroyedLiteral.INSTANCE_REQUEST_SCOPED);
+
+        if (shouldFireRequestLifecycleEvents())
+        {
+            webBeansContext.getBeanManagerImpl().fireContextLifecyleEvent(
+                    ctx, DestroyedLiteral.INSTANCE_REQUEST_SCOPED);
+        }
     }
 
     
diff --git a/webbeans-impl/src/main/java/org/apache/webbeans/event/EventImpl.java b/webbeans-impl/src/main/java/org/apache/webbeans/event/EventImpl.java
index cbe93e0..5f7b71f 100644
--- a/webbeans-impl/src/main/java/org/apache/webbeans/event/EventImpl.java
+++ b/webbeans-impl/src/main/java/org/apache/webbeans/event/EventImpl.java
@@ -22,12 +22,19 @@ import java.io.IOException;
 import java.io.Serializable;
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Objects;
 import java.util.Set;
 import java.util.concurrent.CompletionStage;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
 
 import javax.enterprise.event.Event;
 import javax.enterprise.event.NotificationOptions;
 import javax.enterprise.inject.spi.EventMetadata;
+import javax.enterprise.inject.spi.ObserverMethod;
 import javax.enterprise.util.TypeLiteral;
 
 import org.apache.webbeans.config.WebBeansContext;
@@ -47,6 +54,13 @@ public class EventImpl<T> implements Event<T>, Serializable
 
     private transient WebBeansContext webBeansContext;
 
+    // cache for metadata != this.metadata
+    private volatile transient ConcurrentMap<ObserverCacheKey, List<ObserverMethod<? super Object>>> observers;
+    private volatile transient ConcurrentMap<ObserverCacheKey, List<ObserverMethod<? super Object>>> asyncObservers;
+    // cache for metadata == this.metadata (fast path)
+    private volatile transient List<ObserverMethod<? super Object>> defaultMetadataObservers;
+    private volatile transient List<ObserverMethod<? super Object>> defaultMetadataAsyncObservers;
+
     /**
      * Creates a new event.
      * 
@@ -57,6 +71,12 @@ public class EventImpl<T> implements Event<T>, Serializable
         Asserts.assertNotNull(metadata, "event metadata");
         this.metadata = wrapMetadata(metadata);
         this.webBeansContext = webBeansContext;
+        // earger validation to bypass it at runtime
+        this.webBeansContext.getWebBeansUtil().validEventType(metadata.getType(), metadata.getType());
+        if (webBeansContext.getWebBeansUtil().isContainerEventType(this.metadata.validatedType()))
+        {
+            throw new IllegalArgumentException("Firing container events is forbidden");
+        }
     }
 
     private EventMetadataImpl wrapMetadata(EventMetadata metadata)
@@ -79,8 +99,16 @@ public class EventImpl<T> implements Event<T>, Serializable
     public void fire(T event)
     {
         Type eventType = event.getClass();
-        webBeansContext.getWebBeansUtil().validEventType(eventType.getClass(), metadata.getType());
-        webBeansContext.getBeanManagerImpl().fireEvent(event, metadata.select(eventType), false);
+        if (metadata.validatedType() == eventType)
+        {
+            // already validated so don't recall validEventType()
+            doFireSyncEvent(event, metadata);
+        }
+        else
+        {
+            webBeansContext.getWebBeansUtil().validEventType(eventType.getClass(), metadata.getType());
+            doFireSyncEvent(event, metadata.select(eventType));
+        }
     }
 
     @Override
@@ -93,9 +121,13 @@ public class EventImpl<T> implements Event<T>, Serializable
     public <U extends T> CompletionStage<U> fireAsync(U event, NotificationOptions notificationOptions)
     {
         Type eventType = event.getClass();
-        webBeansContext.getWebBeansUtil().validEventType(eventType.getClass(), metadata.getType());
-        return webBeansContext.getNotificationManager().fireEvent(event, metadata.select(eventType), false,
-                    notificationOptions);
+        if (eventType != metadata.validatedType())
+        {
+            webBeansContext.getWebBeansUtil().validEventType(eventType.getClass(), metadata.getType());
+            return webBeansContext.getNotificationManager()
+                    .fireEvent(event, metadata.select(eventType), false, notificationOptions);
+        }
+        return doFireAsyncEvent(event, metadata, notificationOptions);
     }
 
     /**
@@ -135,4 +167,136 @@ public class EventImpl<T> implements Event<T>, Serializable
     {
         return metadata;
     }
+
+    private void doFireSyncEvent(T event, EventMetadataImpl metadata)
+    {
+        final NotificationManager notificationManager = webBeansContext.getNotificationManager();
+        List<ObserverMethod<? super Object>> observerMethods;
+        if (metadata == this.metadata) // no validation of isContainerEventType, already done
+        {
+            if (defaultMetadataObservers == null)
+            {
+                final List<ObserverMethod<? super Object>> tmp = new ArrayList<>( // faster than LinkedList
+                        notificationManager.resolveObservers(event, metadata, false));
+                notificationManager.prepareObserverListForFire(false, false, tmp);
+                this.defaultMetadataObservers = tmp;
+            }
+            observerMethods = defaultMetadataObservers;
+        }
+        else
+        {
+            if (webBeansContext.getWebBeansUtil().isContainerEventType(event))
+            {
+                throw new IllegalArgumentException("Firing container events is forbidden");
+            }
+
+            if (observers == null)
+            {
+                synchronized (this)
+                {
+                    if (observers == null)
+                    {
+                        observers = new ConcurrentHashMap<>();
+                    }
+                }
+            }
+            final ObserverCacheKey key = new ObserverCacheKey(
+                    event.getClass(), metadata.validatedType(), metadata.getQualifiers());
+            observerMethods = observers.get(key);
+            if (observerMethods == null)
+            {
+                observerMethods = new ArrayList<>( // faster than LinkedList
+                        notificationManager.resolveObservers(event, metadata, false));
+                notificationManager.prepareObserverListForFire(false, false, observerMethods);
+                this.observers.putIfAbsent(key, observerMethods);
+            }
+        }
+        notificationManager.doFireSync(new EventContextImpl<>(event, metadata), false, observerMethods);
+    }
+
+    private <U extends T> CompletionStage<U> doFireAsyncEvent(T event, EventMetadataImpl metadata, NotificationOptions options)
+    {
+        final NotificationManager notificationManager = webBeansContext.getNotificationManager();
+        List<ObserverMethod<? super Object>> observerMethods;
+        if (metadata == this.metadata) // no validation of isContainerEventType, already done
+        {
+            if (defaultMetadataAsyncObservers == null)
+            {
+                final List<ObserverMethod<? super Object>> tmp = new ArrayList<>( // faster than LinkedList
+                        notificationManager.resolveObservers(event, metadata, false));
+                notificationManager.prepareObserverListForFire(false, true, tmp);
+                this.defaultMetadataAsyncObservers = tmp;
+            }
+            observerMethods = defaultMetadataAsyncObservers;
+        }
+        else
+        {
+            if (webBeansContext.getWebBeansUtil().isContainerEventType(event))
+            {
+                throw new IllegalArgumentException("Firing container events is forbidden");
+            }
+
+            if (asyncObservers == null)
+            {
+                synchronized (this)
+                {
+                    if (asyncObservers == null)
+                    {
+                        asyncObservers = new ConcurrentHashMap<>();
+                    }
+                }
+            }
+            final ObserverCacheKey key = new ObserverCacheKey(
+                    event.getClass(), metadata.validatedType(), metadata.getQualifiers());
+            observerMethods = asyncObservers.get(key);
+            if (observerMethods == null)
+            {
+                observerMethods = new ArrayList<>( // faster than LinkedList
+                        notificationManager.resolveObservers(event, metadata, false));
+                notificationManager.prepareObserverListForFire(false, true, observerMethods);
+                this.asyncObservers.putIfAbsent(key, observerMethods);
+            }
+        }
+        return notificationManager.doFireAsync(
+                new EventContextImpl<>(event, metadata), false, options, observerMethods);
+    }
+
+    private static class ObserverCacheKey
+    {
+        private final Class<?> clazz;
+        private final Type type;
+        private final Collection<Annotation> qualifiers;
+        private final int hash;
+
+        private ObserverCacheKey(Class<?> clazz, Type type, Collection<Annotation> qualifiers)
+        {
+            this.clazz = clazz;
+            this.type = type;
+            this.qualifiers = qualifiers;
+            this.hash = Objects.hash(clazz, type, qualifiers);
+        }
+
+        @Override
+        public boolean equals(final Object o)
+        {
+            if (this == o)
+            {
+                return true;
+            }
+            if (o == null || getClass() != o.getClass())
+            {
+                return false;
+            }
+            ObserverCacheKey that = ObserverCacheKey.class.cast(o);
+            return Objects.equals(clazz, that.clazz) &&
+                    Objects.equals(type, that.type) &&
+                    Objects.equals(qualifiers, that.qualifiers);
+        }
+
+        @Override
+        public int hashCode()
+        {
+            return hash;
+        }
+    }
 }
diff --git a/webbeans-impl/src/main/java/org/apache/webbeans/event/NotificationManager.java b/webbeans-impl/src/main/java/org/apache/webbeans/event/NotificationManager.java
index c7f02b5..c7703c7 100644
--- a/webbeans-impl/src/main/java/org/apache/webbeans/event/NotificationManager.java
+++ b/webbeans-impl/src/main/java/org/apache/webbeans/event/NotificationManager.java
@@ -31,8 +31,6 @@ import java.util.Collection;
 import java.util.Comparator;
 import java.util.HashMap;
 import java.util.HashSet;
-import java.util.Iterator;
-import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -59,6 +57,7 @@ import javax.enterprise.inject.spi.AnnotatedField;
 import javax.enterprise.inject.spi.AnnotatedMethod;
 import javax.enterprise.inject.spi.AnnotatedParameter;
 import javax.enterprise.inject.spi.AnnotatedType;
+import javax.enterprise.inject.spi.EventContext;
 import javax.enterprise.inject.spi.Extension;
 import javax.enterprise.inject.spi.ObserverMethod;
 import javax.enterprise.inject.spi.ProcessAnnotatedType;
@@ -75,6 +74,7 @@ import org.apache.webbeans.portable.events.generics.GProcessObserverMethod;
 import org.apache.webbeans.portable.events.generics.GenericBeanEvent;
 import org.apache.webbeans.portable.events.generics.GenericProducerObserverEvent;
 import org.apache.webbeans.portable.events.generics.TwoParametersGenericBeanEvent;
+import org.apache.webbeans.spi.ContextsService;
 import org.apache.webbeans.spi.TransactionService;
 import org.apache.webbeans.util.AnnotationUtil;
 import org.apache.webbeans.util.Asserts;
@@ -195,9 +195,8 @@ public final class NotificationManager
     public <T> Collection<ObserverMethod<? super T>> resolveObservers(T event, EventMetadataImpl metadata, boolean isLifecycleEvent)
     {
         Type eventType = metadata.validatedType();
-        Collection<ObserverMethod<? super T>> observersMethods = filterByType(event, eventType, isLifecycleEvent);
-
-        observersMethods = filterByQualifiers(observersMethods, metadata.getQualifiers());
+        Collection<ObserverMethod<? super T>> observersMethods = filterByQualifiers(
+                filterByType(event, eventType, isLifecycleEvent), metadata.getQualifiers());
 
         if (isLifecycleEvent && event instanceof ProcessAnnotatedType)
         {
@@ -641,124 +640,167 @@ public final class NotificationManager
      * Fire the given event
      * @param notificationOptions if {@code null} then this is a synchronous event. Otherwise fireAsync
      */
-    public <T> CompletionStage<T> fireEvent(Object event, EventMetadataImpl metadata, boolean isLifecycleEvent, NotificationOptions notificationOptions)
+    public <T> CompletionStage<T> fireEvent(Object event, EventMetadataImpl metadata, boolean isLifecycleEvent,
+                                            NotificationOptions notificationOptions)
     {
         boolean async = notificationOptions != null;
-
         if (!isLifecycleEvent && webBeansContext.getWebBeansUtil().isContainerEventType(event))
         {
             throw new IllegalArgumentException("Firing container events is forbidden");
         }
+        return doFireEvent(
+                event, metadata, isLifecycleEvent, notificationOptions, async,
+                new ArrayList<>(resolveObservers(event, metadata, isLifecycleEvent)));
 
-        LinkedList<ObserverMethod<? super Object>> observerMethods = new LinkedList<>(resolveObservers(event, metadata, isLifecycleEvent));
+    }
 
-        // async doesn't apply to Extension lifecycle events
-        if (!isLifecycleEvent)
+    public <T> CompletionStage<T> doFireEvent(Object event, EventMetadataImpl metadata, boolean isLifecycleEvent,
+                                              NotificationOptions notificationOptions, boolean async,
+                                              List<ObserverMethod<? super Object>> observerMethods)
+    {
+        prepareObserverListForFire(isLifecycleEvent, async, observerMethods);
+        EventContextImpl<Object> context = new EventContextImpl<>(event, metadata);
+        if (async)
         {
-            // filter for all async or all synchronous observermethods
-            // oldschool and not Streams, because of performance and avoiding tons of temporary objects
-            Iterator<ObserverMethod<? super Object>> observerMethodIterator = observerMethods.iterator();
-            while (observerMethodIterator.hasNext())
+            return doFireAsync(context, isLifecycleEvent, notificationOptions, observerMethods);
+        }
+        doFireSync(context, isLifecycleEvent, observerMethods);
+        return null;
+
+    }
+
+    public <T> CompletionStage<T> doFireAsync(EventContext<?> context,
+                                              boolean isLifecycleEvent, NotificationOptions notificationOptions,
+                                              List<ObserverMethod<? super Object>> observerMethods)
+    {
+        List<CompletableFuture<Void>> completableFutures = new ArrayList<>();
+        for (ObserverMethod<? super Object> observer : observerMethods)
+        {
+            try
             {
-                if (async != observerMethodIterator.next().isAsync())
+                TransactionPhase phase = observer.getTransactionPhase();
+
+                if (phase == null || phase == TransactionPhase.IN_PROGRESS)
                 {
-                    observerMethodIterator.remove();
+                    completableFutures.add(invokeObserverMethodAsync(context, observer, notificationOptions));
                 }
+                else
+                {
+                    throw new WebBeansConfigurationException("Async Observer Methods can only use TransactionPhase.IN_PROGRESS!");
+                }
+            }
+            catch (WebBeansException e)
+            {
+                return onWebBeansException(context.getEvent(), isLifecycleEvent, e);
+            }
+            catch (RuntimeException e)
+            {
+                throw e;
+            }
+            catch (Exception e)
+            {
+                throw new WebBeansException(e);
             }
         }
+        return complete(completableFutures, (T) context.getEvent());
+    }
 
-        // new in CDI-2.0: sort observers
-        if (observerMethods.size() > 1)
+    public void doFireSync(EventContext<?> context, boolean isLifecycleEvent,
+                           List<ObserverMethod<? super Object>> observerMethods)
+    {
+        if (observerMethods.isEmpty())
         {
-            observerMethods.sort(observerMethodComparator);
+            return;
         }
-
-        List<CompletableFuture<Void>> completableFutures = async ? new ArrayList<>() : null;
-
+        // synchronous case
         for (ObserverMethod<? super Object> observer : observerMethods)
         {
             try
             {
-                if (isLifecycleEvent && !Extension.class.isAssignableFrom(observer.getBeanClass()))
-                {
-                    // we must not fire Extension Lifecycle events to beans which are no Extensions
-                    continue;
-                }
-
                 TransactionPhase phase = observer.getTransactionPhase();
-                
-                if(phase != null && phase != TransactionPhase.IN_PROGRESS)
-                {
-                    if (async)
-                    {
-                        throw new WebBeansConfigurationException("Async Observer Methods can only use TransactionPhase.IN_PROGRESS!");
-                    }
 
-                    TransactionService transactionService = webBeansContext.getService(TransactionService.class);
-                    if(transactionService != null)
-                    {
-                        transactionService.registerTransactionSynchronization(phase, observer, event);
-                    }
-                    else
-                    {
-                        invokeObserverMethod(event, metadata, observer);
-                    }                    
+                if (phase == null || phase != TransactionPhase.IN_PROGRESS)
+                {
+                    invokeObserverMethod(context, observer);
                 }
                 else
                 {
-                    if (async)
+                    TransactionService transactionService = webBeansContext.getTransactionService();
+                    if(transactionService != null)
                     {
-                        completableFutures.add(invokeObserverMethodAsync(event, metadata, observer, notificationOptions));
+                        transactionService.registerTransactionSynchronization(phase, observer, context.getEvent());
                     }
                     else
                     {
-                        invokeObserverMethod(event, metadata, observer);
+                        invokeObserverMethod(context, observer);
                     }
                 }
             }
             catch (WebBeansException e)
             {
-                Throwable exc = e.getCause();
-                if(exc instanceof InvocationTargetException)
-                {
-                    InvocationTargetException invt = (InvocationTargetException)exc;
-                    exc = invt.getCause();
-                }
-
-                if (isLifecycleEvent)
-                {
-                    if (event instanceof AfterDeploymentValidation)
-                    {
-                        throw new WebBeansDeploymentException("Error while sending SystemEvent to a CDI Extension! " + event.toString(), e);
-                    }
-                    else
-                    {
-                        throw new WebBeansConfigurationException("Error while sending SystemEvent to a CDI Extension! " + event.toString(), e);
-                    }
-                }
-                
-                if (!RuntimeException.class.isAssignableFrom(exc.getClass()))
-                {
-                    throw new ObserverException(WebBeansLoggerFacade.getTokenString(OWBLogConst.EXCEPT_0008) + event.getClass().getName(), e);
-                }
-                else
-                {
-                    RuntimeException rte = (RuntimeException) exc;
-                    throw rte;
-                }
+                onWebBeansException(context.getEvent(), isLifecycleEvent, e);
             }
             catch (RuntimeException e)
             {
                 throw e;
             }
-
             catch (Exception e)
             {
                 throw new WebBeansException(e);
             }
         }
+    }
+
+    public void prepareObserverListForFire(boolean isLifecycleEvent, boolean async,
+                                           List<ObserverMethod<? super Object>> observerMethods)
+    {
+        // async doesn't apply to Extension lifecycle events
+        if (!isLifecycleEvent)
+        {
+            // filter for all async or all synchronous observermethods
+            // oldschool and not Streams, because of performance and avoiding tons of temporary objects
+            observerMethods.removeIf(observerMethod -> async != observerMethod.isAsync());
+        }
+        else
+        {
+            observerMethods.removeIf(observer -> !Extension.class.isAssignableFrom(observer.getBeanClass()));
+        }
+
+        // new in CDI-2.0: sort observers
+        if (observerMethods.size() > 1)
+        {
+            observerMethods.sort(observerMethodComparator);
+        }
+    }
+
+    private <T> CompletionStage<T> onWebBeansException(final Object event, final boolean isLifecycleEvent,
+                                                       final WebBeansException e)
+    {
+        Throwable exc = e.getCause();
+        if(exc instanceof InvocationTargetException)
+        {
+            InvocationTargetException invt = (InvocationTargetException)exc;
+            exc = invt.getCause();
+        }
+
+        if (isLifecycleEvent)
+        {
+            if (event instanceof AfterDeploymentValidation)
+            {
+                throw new WebBeansDeploymentException("Error while sending SystemEvent to a CDI Extension! " + event.toString(), e);
+            }
+            else
+            {
+                throw new WebBeansConfigurationException("Error while sending SystemEvent to a CDI Extension! " + event.toString(), e);
+            }
+        }
 
-        return async ? complete(completableFutures, (T) event) : null;
+        if (!RuntimeException.class.isAssignableFrom(exc.getClass()))
+        {
+            throw new ObserverException(WebBeansLoggerFacade.getTokenString(OWBLogConst.EXCEPT_0008) + event.getClass().getName(), e);
+        }
+        RuntimeException rte = (RuntimeException) exc;
+        throw rte;
     }
 
     private <T> CompletableFuture<T> complete(List<CompletableFuture<Void>> completableFutures, T event)
@@ -780,8 +822,7 @@ public final class NotificationManager
         return future;
     }
 
-    private CompletableFuture invokeObserverMethodAsync(Object event,
-                                           EventMetadataImpl metadata,
+    private CompletableFuture invokeObserverMethodAsync(EventContext<?> context,
                                            ObserverMethod<? super Object> observer,
                                            NotificationOptions notificationOptions)
     {
@@ -789,7 +830,7 @@ public final class NotificationManager
         CompletableFuture.runAsync(() -> {
             try
             {
-                runAsync(event, metadata, observer);
+                runAsync(context, observer);
                 future.complete(null);
             }
             catch (WebBeansException wbe)
@@ -800,23 +841,25 @@ public final class NotificationManager
         return future;
     }
 
-    private void runAsync(Object event, EventMetadataImpl metadata, ObserverMethod<? super Object> observer)
+    private void runAsync(EventContext<?> context, ObserverMethod<? super Object> observer)
     {
         //X TODO set up threads, requestcontext etc
-        webBeansContext.getContextsService().startContext(RequestScoped.class, null);
+        final ContextsService contextsService = webBeansContext.getContextsService();
+        contextsService.getCurrentContext(RequestScoped.class);
+        contextsService.startContext(RequestScoped.class, null);
         try
         {
-            invokeObserverMethod(event, metadata, observer);
+            invokeObserverMethod(context, observer);
         }
         finally
         {
-            webBeansContext.getContextsService().endContext(RequestScoped.class, null);
+            contextsService.endContext(RequestScoped.class, null);
         }
     }
 
-    private <T> void invokeObserverMethod(T event, EventMetadataImpl metadata, ObserverMethod<?> observer)
+    private void invokeObserverMethod(EventContext context, ObserverMethod<?> observer)
     {
-        observer.notify(new EventContextImpl(event, metadata));
+        observer.notify(context);
     }
 
     /**
diff --git a/webbeans-impl/src/main/java/org/apache/webbeans/event/ObserverMethodImpl.java b/webbeans-impl/src/main/java/org/apache/webbeans/event/ObserverMethodImpl.java
index d2fad9f..7061714 100644
--- a/webbeans-impl/src/main/java/org/apache/webbeans/event/ObserverMethodImpl.java
+++ b/webbeans-impl/src/main/java/org/apache/webbeans/event/ObserverMethodImpl.java
@@ -199,6 +199,11 @@ public class ObserverMethodImpl<T> implements OwbObserverMethod<T>
         }
 
         checkObserverCondition(annotatedObservesParameter);
+
+        if (!view.isAccessible())
+        {
+            ownerBean.getWebBeansContext().getSecurityService().doPrivilegedSetAccessible(view, true);
+        }
     }
 
     protected void checkObserverCondition(AnnotatedParameter<T> annotatedObservesParameter)
@@ -278,22 +283,26 @@ public class ObserverMethodImpl<T> implements OwbObserverMethod<T>
         ObserverParams[] obargs = null;
         try
         {
-            obargs = new ObserverParams[methodArgsMap.size()];
-            obargs = methodArgsMap.toArray(obargs);
-            Object[] args = new Object[obargs.length];
-            int i = 0;
-            for(ObserverParams param : obargs)
+            Object[] args;
+            if (methodArgsMap == null)
+            {
+                args = new Object[]{event};
+            }
+            else
             {
-                args[i++] = param.instance;
+                args = new Object[methodArgsMap.size()];
+                obargs = new ObserverParams[args.length];
+                obargs = methodArgsMap.toArray(obargs);
+                int i = 0;
+                for (ObserverParams param : obargs)
+                {
+                    args[i++] = param.instance;
+                }
             }
 
             //Static or not
             if (Modifier.isStatic(view.getModifiers()))
             {
-                if (!view.isAccessible())
-                {
-                    view.setAccessible(true);
-                }
                 //Invoke Method
                 view.invoke(null, args);
             }
@@ -347,14 +356,9 @@ public class ObserverMethodImpl<T> implements OwbObserverMethod<T>
 
                 if (object != null)
                 {
-                    if (!view.isAccessible())
-                    {
-                        ownerBean.getWebBeansContext().getSecurityService().doPrivilegedSetAccessible(view, true);
-                    }
-
                     if (Modifier.isPrivate(view.getModifiers()))
                     {
-                        // since private methods cannot be intercepted, we have to unwrap anny possible proxy
+                        // since private methods cannot be intercepted, we have to unwrap any possible proxy
                         if (object instanceof OwbNormalScopeProxy)
                         {
                             object = getWebBeansContext().getInterceptorDecoratorProxyFactory().unwrapInstance(object);
@@ -385,7 +389,7 @@ public class ObserverMethodImpl<T> implements OwbObserverMethod<T>
             }
             
             //Destroy observer method dependent instances
-            if(methodArgsMap != null)
+            if(methodArgsMap != null && obargs != null)
             {
                 for(ObserverParams param : obargs)
                 {
@@ -411,6 +415,11 @@ public class ObserverMethodImpl<T> implements OwbObserverMethod<T>
      */
     protected List<ObserverParams> getMethodArguments(Object event, EventMetadata metadata)
     {
+        if (injectionPoints.isEmpty() && annotatedObservesParameter.getPosition() == 0)
+        {
+            return null; // special handling
+        }
+
         List<ObserverParams> list = new ArrayList<>();
         if (annotatedObservesParameter.getPosition() == 0)
         {
diff --git a/webbeans-web/src/main/java/org/apache/webbeans/web/context/WebContextsService.java b/webbeans-web/src/main/java/org/apache/webbeans/web/context/WebContextsService.java
index 0055c3a..135c867 100644
--- a/webbeans-web/src/main/java/org/apache/webbeans/web/context/WebContextsService.java
+++ b/webbeans-web/src/main/java/org/apache/webbeans/web/context/WebContextsService.java
@@ -33,7 +33,6 @@ import org.apache.webbeans.context.SessionContext;
 import org.apache.webbeans.context.SingletonContext;
 import org.apache.webbeans.conversation.ConversationManager;
 import org.apache.webbeans.el.ELContextStore;
-import org.apache.webbeans.event.NotificationManager;
 import org.apache.webbeans.intercept.SessionScopedBeanInterceptorHandler;
 import org.apache.webbeans.logger.WebBeansLoggerFacade;
 import org.apache.webbeans.intercept.RequestScopedBeanInterceptorHandler;
@@ -99,8 +98,6 @@ public class WebContextsService extends AbstractContextsService
     protected Pattern eagerSessionPattern;
 
 
-    protected Boolean fireRequestLifecycleEvents;
-
     /**
      * Creates a new instance.
      */
@@ -806,20 +803,6 @@ public class WebContextsService extends AbstractContextsService
         return conversationContext;
     }
 
-    protected boolean shouldFireRequestLifecycleEvents()
-    {
-        if (fireRequestLifecycleEvents == null)
-        {
-            NotificationManager notificationManager = webBeansContext.getNotificationManager();
-            fireRequestLifecycleEvents
-                = notificationManager.hasContextLifecycleObserver(InitializedLiteral.INSTANCE_REQUEST_SCOPED) ||
-                  notificationManager.hasContextLifecycleObserver(BeforeDestroyedLiteral.INSTANCE_REQUEST_SCOPED) ||
-                  notificationManager.hasContextLifecycleObserver(DestroyedLiteral.INSTANCE_REQUEST_SCOPED) ;
-        }
-
-        return fireRequestLifecycleEvents;
-    }
-
 
     /**
      * Try to lazily start the sessionContext.