starting spec v3 impl (still some failling tests)
diff --git a/geronimo-metrics-common/src/main/java/org/apache/geronimo/microprofile/metrics/common/RegistryImpl.java b/geronimo-metrics-common/src/main/java/org/apache/geronimo/microprofile/metrics/common/RegistryImpl.java
index 0897ce6..d2ae98e 100644
--- a/geronimo-metrics-common/src/main/java/org/apache/geronimo/microprofile/metrics/common/RegistryImpl.java
+++ b/geronimo-metrics-common/src/main/java/org/apache/geronimo/microprofile/metrics/common/RegistryImpl.java
@@ -16,19 +16,6 @@
  */
 package org.apache.geronimo.microprofile.metrics.common;
 
-import static java.util.stream.Collectors.toCollection;
-import static java.util.stream.Collectors.toMap;
-
-import java.util.Map;
-import java.util.Objects;
-import java.util.SortedMap;
-import java.util.SortedSet;
-import java.util.TreeMap;
-import java.util.TreeSet;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.atomic.AtomicBoolean;
-
 import org.eclipse.microprofile.metrics.ConcurrentGauge;
 import org.eclipse.microprofile.metrics.Counter;
 import org.eclipse.microprofile.metrics.Gauge;
@@ -41,14 +28,33 @@
 import org.eclipse.microprofile.metrics.MetricRegistry;
 import org.eclipse.microprofile.metrics.MetricType;
 import org.eclipse.microprofile.metrics.MetricUnits;
+import org.eclipse.microprofile.metrics.SimpleTimer;
 import org.eclipse.microprofile.metrics.Tag;
 import org.eclipse.microprofile.metrics.Timer;
 
-public class RegistryImpl extends MetricRegistry {
+import java.util.Map;
+import java.util.Objects;
+import java.util.SortedMap;
+import java.util.SortedSet;
+import java.util.TreeMap;
+import java.util.TreeSet;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import static java.util.stream.Collectors.toCollection;
+import static java.util.stream.Collectors.toMap;
+
+public class RegistryImpl implements MetricRegistry {
     private static final Tag[] NO_TAG = new Tag[0];
 
+    private final Type type;
     private final ConcurrentMap<MetricID, Holder<? extends Metric>> metrics = new ConcurrentHashMap<>();
 
+    public RegistryImpl(final Type type) {
+        this.type = type;
+    }
+
     @Override
     public <T extends Metric> T register(final Metadata metadata, final T metric) throws IllegalArgumentException {
         return register(metadata, metric, NO_TAG);
@@ -124,6 +130,11 @@
     }
 
     @Override
+    public ConcurrentGauge concurrentGauge(final MetricID metricID) {
+        return concurrentGauge(metricID.getName(), metricID.getTagsAsArray());
+    }
+
+    @Override
     public ConcurrentGauge concurrentGauge(final Metadata metadata) {
         return concurrentGauge(metadata, NO_TAG);
     }
@@ -151,6 +162,11 @@
     }
 
     @Override
+    public Gauge<?> gauge(final MetricID metricID, final Gauge<?> gauge) {
+        return gauge(metricID.getName(), gauge, metricID.getTagsAsArray());
+    }
+
+    @Override
     public Histogram histogram(final Metadata metadata) {
         return histogram(metadata, NO_TAG);
     }
@@ -229,6 +245,49 @@
     }
 
     @Override
+    public SimpleTimer simpleTimer(final MetricID metricID) {
+        return simpleTimer(metricID.getName(), metricID.getTagsAsArray());
+    }
+
+    @Override
+    public SimpleTimer simpleTimer(final Metadata metadata) {
+        return simpleTimer(metadata, NO_TAG);
+    }
+
+    @Override
+    public SimpleTimer simpleTimer(final Metadata metadata, final Tag... tags) {
+        final MetricID metricID = new MetricID(metadata.getName(), tags);
+        Holder<? extends Metric> holder = metrics.get(metricID);
+        if (holder == null) {
+            holder = new Holder<>(new SimpleTimerImpl(metadata.getUnit().orElse(MetricUnits.NONE)), metadata, metricID);
+            final Holder<? extends Metric> existing = metrics.putIfAbsent(metricID, holder);
+            if (existing != null) {
+                holder = existing;
+            }
+        } else if (!metadata.isReusable()) {
+            throw new IllegalArgumentException("Metric " + metadata.getName() + " already exists and is not set as reusable");
+        } else if (!holder.metadata.isReusable()) {
+            throw new IllegalArgumentException("Metric " + metadata.getName() + " already exists and was not set as reusable");
+        }
+        if (!SimpleTimer.class.isInstance(holder.metric)) {
+            throw new IllegalArgumentException(holder.metric + " is not a timer");
+        }
+        return SimpleTimer.class.cast(holder.metric);
+    }
+
+    @Override
+    public Metric getMetric(final MetricID metricID) {
+        final Holder<? extends Metric> holder = metrics.get(metricID);
+        return holder == null ? null : holder.metric;
+    }
+
+    @Override
+    public Metadata getMetadata(final String name) {
+        final Holder<? extends Metric> holder = metrics.get(new MetricID(name));
+        return holder == null ? null : holder.metadata;
+    }
+
+    @Override
     public Counter counter(final String name) {
         return counter(Metadata.builder().withName(name).withType(MetricType.COUNTER).build(), NO_TAG);
     }
@@ -239,6 +298,11 @@
     }
 
     @Override
+    public Counter counter(final MetricID metricID) {
+        return counter(metricID.getName(), metricID.getTagsAsArray());
+    }
+
+    @Override
     public Histogram histogram(final String name) {
         return histogram(Metadata.builder().withName(name).withType(MetricType.HISTOGRAM).build());
     }
@@ -249,6 +313,11 @@
     }
 
     @Override
+    public Histogram histogram(final MetricID metricID) {
+        return histogram(metricID.getName(), metricID.getTagsAsArray());
+    }
+
+    @Override
     public Meter meter(final String name) {
         return meter(Metadata.builder().withName(name).withType(MetricType.METERED).build());
     }
@@ -259,6 +328,11 @@
     }
 
     @Override
+    public Meter meter(final MetricID metricID) {
+        return meter(metricID.getName(), metricID.getTagsAsArray());
+    }
+
+    @Override
     public Timer timer(final String name) {
         return timer(Metadata.builder().withName(name).withType(MetricType.TIMER).build());
     }
@@ -269,6 +343,11 @@
     }
 
     @Override
+    public Timer timer(final MetricID metricID) {
+        return timer(metricID.getName(), metricID.getTagsAsArray());
+    }
+
+    @Override
     public boolean remove(final String name) {
         final AtomicBoolean done = new AtomicBoolean(false);
         removeMatching((metricID, metric) -> {
@@ -362,6 +441,21 @@
     }
 
     @Override
+    public SortedMap<MetricID, SimpleTimer> getSimpleTimers() {
+        return filterByType(MetricFilter.ALL, SimpleTimer.class);
+    }
+
+    @Override
+    public SortedMap<MetricID, SimpleTimer> getSimpleTimers(final MetricFilter filter) {
+        return filterByType(filter, SimpleTimer.class);
+    }
+
+    @Override
+    public SortedMap<MetricID, Metric> getMetrics(final MetricFilter metricFilter) {
+        return filterByType(metricFilter, Metric.class);
+    }
+
+    @Override
     public Map<MetricID, Metric> getMetrics() {
         return metrics.entrySet().stream().collect(toMap(Map.Entry::getKey, e -> e.getValue().metric));
     }
@@ -372,6 +466,11 @@
                 .collect(toMap(e -> e.getKey().getName(), e -> e.getValue().metadata, (a, b) -> a));
     }
 
+    @Override
+    public Type getType() {
+        return type;
+    }
+
     private <T extends Metric> SortedMap<MetricID, T> filterByType(final MetricFilter filter, final Class<T> type) {
         return metrics.entrySet().stream()
                 .filter(it -> type.isInstance(it.getValue().metric))
diff --git a/geronimo-metrics-common/src/main/java/org/apache/geronimo/microprofile/metrics/common/SimpleTimerImpl.java b/geronimo-metrics-common/src/main/java/org/apache/geronimo/microprofile/metrics/common/SimpleTimerImpl.java
new file mode 100644
index 0000000..5945762
--- /dev/null
+++ b/geronimo-metrics-common/src/main/java/org/apache/geronimo/microprofile/metrics/common/SimpleTimerImpl.java
@@ -0,0 +1,153 @@
+/*
+ * 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.geronimo.microprofile.metrics.common;
+
+import org.eclipse.microprofile.metrics.SimpleTimer;
+
+import java.time.Clock;
+import java.time.Duration;
+import java.time.Instant;
+import java.time.ZoneId;
+import java.util.concurrent.Callable;
+
+public class SimpleTimerImpl implements SimpleTimer {
+    private static final Clock MINUTE_CLOCK = Clock.tickMinutes(ZoneId.of("UTC"));
+    private static final Clock CLOCK = Clock.systemUTC();
+
+    // same logic than ConcurrentGaugeImpl
+    private volatile Instant currentMinute = CLOCK.instant();
+
+    private volatile Duration current;
+    private volatile Duration min;
+    private volatile Duration max;
+    private volatile Duration previousMin;
+    private volatile Duration previousMax;
+    private volatile long count;
+
+    private final String unit;
+
+    public SimpleTimerImpl(final String unit) {
+        this.unit = unit;
+    }
+
+    public String getUnit() {
+        return unit;
+    }
+
+    @Override
+    public void update(final Duration duration) {
+        if (duration.isNegative() || duration.isZero()) {
+            return;
+        }
+        maybeRotate();
+        synchronized (this) {
+            count++;
+            current = duration;
+            if (max == null || duration.toMillis() > max.toMillis()) {
+                max = duration;
+            }
+            if (min == null || duration.toMillis() < min.toMillis()) {
+                min = duration;
+            }
+        }
+    }
+
+    @Override
+    public <T> T time(final Callable<T> callable) throws Exception {
+        final Instant startTime = CLOCK.instant();
+        try {
+            return callable.call();
+        } finally {
+            update(Duration.between(startTime, CLOCK.instant()));
+        }
+    }
+
+    @Override
+    public void time(final Runnable runnable) {
+        try {
+            time(() -> {
+                runnable.run();
+                return null;
+            });
+        } catch (final RuntimeException re) {
+            throw re;
+        } catch (Exception e) {
+            throw new IllegalStateException(e);
+        }
+    }
+
+    @Override
+    public Context time() {
+        return new ContextImpl();
+    }
+
+    @Override
+    public Duration getElapsedTime() {
+        return current;
+    }
+
+    @Override
+    public long getCount() {
+        return count;
+    }
+
+    @Override
+    public Duration getMaxTimeDuration() {
+        maybeRotate();
+        return max;
+    }
+
+    @Override
+    public Duration getMinTimeDuration() {
+        maybeRotate();
+        return min;
+    }
+
+    private void maybeRotate() {
+        final Instant now = MINUTE_CLOCK.instant();
+        if (now.isAfter(currentMinute)) {
+            synchronized (this) {
+                if (now.isAfter(currentMinute)) {
+                    rotate(now);
+                }
+            }
+        }
+    }
+
+    private void rotate(final Instant now) {
+        previousMax = max;
+        previousMin = min;
+        max = min = null;
+        currentMinute = now;
+    }
+
+    private class ContextImpl implements Context {
+        private final Instant start = CLOCK.instant();
+
+        @Override
+        public long stop() {
+            final Duration duration = Duration.between(start, CLOCK.instant());
+            update(duration);
+            return duration.toNanos();
+        }
+
+        @Override
+        public void close() {
+            stop();
+        }
+    }
+}
diff --git a/geronimo-metrics-common/src/main/java/org/apache/geronimo/microprofile/metrics/common/TimerImpl.java b/geronimo-metrics-common/src/main/java/org/apache/geronimo/microprofile/metrics/common/TimerImpl.java
index 51cdbcd..38cf11e 100644
--- a/geronimo-metrics-common/src/main/java/org/apache/geronimo/microprofile/metrics/common/TimerImpl.java
+++ b/geronimo-metrics-common/src/main/java/org/apache/geronimo/microprofile/metrics/common/TimerImpl.java
@@ -16,17 +16,17 @@
  */
 package org.apache.geronimo.microprofile.metrics.common;
 
-import java.util.concurrent.Callable;
-import java.util.concurrent.TimeUnit;
-
-import javax.json.bind.annotation.JsonbProperty;
-import javax.json.bind.annotation.JsonbTransient;
-
 import org.eclipse.microprofile.metrics.Histogram;
 import org.eclipse.microprofile.metrics.Meter;
 import org.eclipse.microprofile.metrics.Snapshot;
 import org.eclipse.microprofile.metrics.Timer;
 
+import javax.json.bind.annotation.JsonbProperty;
+import javax.json.bind.annotation.JsonbTransient;
+import java.time.Duration;
+import java.util.concurrent.Callable;
+import java.util.concurrent.TimeUnit;
+
 public class TimerImpl implements Timer {
     private final Histogram histogram;
     private final Meter meter;
@@ -37,11 +37,12 @@
     }
 
     @Override
-    public void update(final long duration, final TimeUnit unit) {
-        if (duration >= 0) {
-            histogram.update(unit.toNanos(duration));
-            meter.mark();
+    public void update(final Duration duration) {
+        if (duration.isNegative() || duration.isZero()) {
+            return;
         }
+        histogram.update(duration.toNanos());
+        meter.mark();
     }
 
     @Override
@@ -71,6 +72,11 @@
     }
 
     @Override
+    public Duration getElapsedTime() {
+        return null;
+    }
+
+    @Override
     public long getCount() {
         return histogram.getCount();
     }
@@ -150,7 +156,7 @@
         @Override
         public long stop() {
             final long duration = System.nanoTime() - start;
-            update(duration, TimeUnit.NANOSECONDS);
+            update(Duration.ofNanos(duration));
             return duration;
         }
 
diff --git a/geronimo-metrics-common/src/main/java/org/apache/geronimo/microprofile/metrics/common/prometheus/PrometheusFormatter.java b/geronimo-metrics-common/src/main/java/org/apache/geronimo/microprofile/metrics/common/prometheus/PrometheusFormatter.java
index dda1a0c..09b16d6 100644
--- a/geronimo-metrics-common/src/main/java/org/apache/geronimo/microprofile/metrics/common/prometheus/PrometheusFormatter.java
+++ b/geronimo-metrics-common/src/main/java/org/apache/geronimo/microprofile/metrics/common/prometheus/PrometheusFormatter.java
@@ -16,12 +16,22 @@
  */
 package org.apache.geronimo.microprofile.metrics.common.prometheus;
 
-import static java.lang.Math.pow;
-import static java.util.Optional.of;
-import static java.util.stream.Collectors.joining;
-import static java.util.stream.Collectors.toList;
-import static java.util.stream.Collectors.toMap;
-import static java.util.stream.Collectors.toSet;
+import org.eclipse.microprofile.metrics.ConcurrentGauge;
+import org.eclipse.microprofile.metrics.Counter;
+import org.eclipse.microprofile.metrics.Gauge;
+import org.eclipse.microprofile.metrics.Histogram;
+import org.eclipse.microprofile.metrics.Metadata;
+import org.eclipse.microprofile.metrics.Meter;
+import org.eclipse.microprofile.metrics.Metered;
+import org.eclipse.microprofile.metrics.Metric;
+import org.eclipse.microprofile.metrics.MetricID;
+import org.eclipse.microprofile.metrics.MetricRegistry;
+import org.eclipse.microprofile.metrics.MetricType;
+import org.eclipse.microprofile.metrics.MetricUnits;
+import org.eclipse.microprofile.metrics.SimpleTimer;
+import org.eclipse.microprofile.metrics.Snapshot;
+import org.eclipse.microprofile.metrics.Tag;
+import org.eclipse.microprofile.metrics.Timer;
 
 import java.io.IOException;
 import java.io.InputStream;
@@ -36,21 +46,12 @@
 import java.util.function.Predicate;
 import java.util.stream.Stream;
 
-import org.eclipse.microprofile.metrics.ConcurrentGauge;
-import org.eclipse.microprofile.metrics.Counter;
-import org.eclipse.microprofile.metrics.Gauge;
-import org.eclipse.microprofile.metrics.Histogram;
-import org.eclipse.microprofile.metrics.Metadata;
-import org.eclipse.microprofile.metrics.Meter;
-import org.eclipse.microprofile.metrics.Metered;
-import org.eclipse.microprofile.metrics.Metric;
-import org.eclipse.microprofile.metrics.MetricID;
-import org.eclipse.microprofile.metrics.MetricRegistry;
-import org.eclipse.microprofile.metrics.MetricType;
-import org.eclipse.microprofile.metrics.MetricUnits;
-import org.eclipse.microprofile.metrics.Snapshot;
-import org.eclipse.microprofile.metrics.Tag;
-import org.eclipse.microprofile.metrics.Timer;
+import static java.lang.Math.pow;
+import static java.util.Optional.of;
+import static java.util.stream.Collectors.joining;
+import static java.util.stream.Collectors.toList;
+import static java.util.stream.Collectors.toMap;
+import static java.util.stream.Collectors.toSet;
 
 // note: we keep this name for backward compat but this is now an "openmetrics" formatter
 // todo: cache all the keys, can easily be done decorating the registry and enriching metadata (ExtendedMetadata/MetricsID)
@@ -161,6 +162,12 @@
                             final Timer timer = Timer.class.cast(entry.metric);
                             return timer(registryKey, entry, tagsAsList, keyBase, keyUnit, timer);
                         }
+                        case SIMPLE_TIMER: {
+                            final String keyBase = toPrometheus(entry.metadata);
+                            final String keyUnit = toUnitSuffix(entry.metadata, false);
+                            final SimpleTimer timer = SimpleTimer.class.cast(entry.metric);
+                            return simpleTimer(registryKey, entry, tagsAsList, keyBase, keyUnit, timer);
+                        }
                         case HISTOGRAM:
                             final String keyBase = toPrometheus(entry.metadata);
                             final String keyUnit = toUnitSuffix(entry.metadata, false);
@@ -188,6 +195,12 @@
                 .append(toPrometheus(registryKey, keyBase, keyUnit, timer.getSnapshot(), entry.metadata, tagsAsList));
     }
 
+    private StringBuilder simpleTimer(final String registryKey, final Entry entry, final List<Tag> tagsAsList, final String keyBase, final String keyUnit, final SimpleTimer timer) {
+        return new StringBuilder()
+                .append(type(registryKey, keyBase + keyUnit + " summary", entry.metadata))
+                .append(value(registryKey, keyBase + keyUnit + "_count", timer.getCount(), entry.metadata, tagsAsList));
+    }
+
     private StringBuilder meter(final String registryKey, final Entry entry, final List<Tag> tagsAsList, final Metered meter, final String keyBase) {
         return new StringBuilder()
                 .append(value(registryKey, keyBase + "_rate_per_second", meter.getMeanRate(), entry.metadata, tagsAsList))
diff --git a/geronimo-metrics-common/src/test/java/org/apache/geronimo/microprofile/metrics/common/json/JsonMetricTest.java b/geronimo-metrics-common/src/test/java/org/apache/geronimo/microprofile/metrics/common/json/JsonMetricTest.java
index 554f6ac..f5f1879 100644
--- a/geronimo-metrics-common/src/test/java/org/apache/geronimo/microprofile/metrics/common/json/JsonMetricTest.java
+++ b/geronimo-metrics-common/src/test/java/org/apache/geronimo/microprofile/metrics/common/json/JsonMetricTest.java
@@ -22,6 +22,7 @@
 import org.apache.geronimo.microprofile.metrics.common.jaxrs.SecurityValidator;
 import org.apache.geronimo.microprofile.metrics.common.prometheus.PrometheusFormatter;
 import org.eclipse.microprofile.metrics.Gauge;
+import org.eclipse.microprofile.metrics.MetricRegistry;
 import org.junit.Test;
 
 import javax.ws.rs.core.SecurityContext;
@@ -34,7 +35,7 @@
 
     @Test
     public void testJsonGaugeValue() {
-        final RegistryImpl registry = new RegistryImpl();
+        final RegistryImpl registry = new RegistryImpl(MetricRegistry.Type.APPLICATION);
         registry.register("foo", (Gauge<Long>) () -> 1L);
 
         final MetricsEndpoints endpoints = new MetricsEndpoints();
diff --git a/geronimo-metrics-common/src/test/java/org/apache/geronimo/microprofile/metrics/common/prometheus/PrometheusFormatterTest.java b/geronimo-metrics-common/src/test/java/org/apache/geronimo/microprofile/metrics/common/prometheus/PrometheusFormatterTest.java
index f73a48f..92ada93 100644
--- a/geronimo-metrics-common/src/test/java/org/apache/geronimo/microprofile/metrics/common/prometheus/PrometheusFormatterTest.java
+++ b/geronimo-metrics-common/src/test/java/org/apache/geronimo/microprofile/metrics/common/prometheus/PrometheusFormatterTest.java
@@ -19,7 +19,6 @@
 import static java.util.Collections.singletonMap;
 import static org.junit.Assert.assertEquals;
 
-import java.util.HashMap;
 import java.util.LinkedHashMap;
 import java.util.Map;
 import java.util.Properties;
@@ -27,13 +26,14 @@
 import org.apache.geronimo.microprofile.metrics.common.RegistryImpl;
 import org.eclipse.microprofile.metrics.Gauge;
 import org.eclipse.microprofile.metrics.Metric;
+import org.eclipse.microprofile.metrics.MetricRegistry;
 import org.junit.Test;
 
 public class PrometheusFormatterTest {
     @Test
     public void rename() {
         final PrometheusFormatter prometheusFormatter = new PrometheusFormatter().enableOverriding();
-        final RegistryImpl registry = new RegistryImpl();
+        final RegistryImpl registry = new RegistryImpl(MetricRegistry.Type.APPLICATION);
         final Map<String, Metric> metrics = singletonMap("myMetric", (Gauge<Long>) () -> 1234L);
         metrics.forEach(registry::register);
         assertEquals(
@@ -59,7 +59,7 @@
     @Test
     public void filter() {
         final PrometheusFormatter prometheusFormatter = new PrometheusFormatter().enableOverriding();
-        final RegistryImpl registry = new RegistryImpl();
+        final RegistryImpl registry = new RegistryImpl(MetricRegistry.Type.APPLICATION);
         final Map<String, Metric> metrics = new LinkedHashMap<>();
         metrics.put("myMetric1", (Gauge<Long>) () -> 1234L);
         metrics.put("myMetric2", (Gauge<Long>) () -> 1235L);
diff --git a/geronimo-metrics/src/main/java/org/apache/geronimo/microprofile/metrics/cdi/ConcurrentGaugeInterceptor.java b/geronimo-metrics/src/main/java/org/apache/geronimo/microprofile/metrics/cdi/ConcurrentGaugeInterceptor.java
index 586d16c..fe7147c 100644
--- a/geronimo-metrics/src/main/java/org/apache/geronimo/microprofile/metrics/cdi/ConcurrentGaugeInterceptor.java
+++ b/geronimo-metrics/src/main/java/org/apache/geronimo/microprofile/metrics/cdi/ConcurrentGaugeInterceptor.java
@@ -16,14 +16,10 @@
  */
 package org.apache.geronimo.microprofile.metrics.cdi;
 
-import static java.util.Optional.ofNullable;
-
-import java.io.Serializable;
-import java.lang.reflect.Executable;
-import java.lang.reflect.Modifier;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-import java.util.stream.Stream;
+import org.eclipse.microprofile.metrics.ConcurrentGauge;
+import org.eclipse.microprofile.metrics.MetricID;
+import org.eclipse.microprofile.metrics.MetricRegistry;
+import org.eclipse.microprofile.metrics.Tag;
 
 import javax.annotation.Priority;
 import javax.enterprise.inject.Intercepted;
@@ -35,11 +31,14 @@
 import javax.interceptor.AroundInvoke;
 import javax.interceptor.Interceptor;
 import javax.interceptor.InvocationContext;
+import java.io.Serializable;
+import java.lang.reflect.Executable;
+import java.lang.reflect.Modifier;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.stream.Stream;
 
-import org.eclipse.microprofile.metrics.ConcurrentGauge;
-import org.eclipse.microprofile.metrics.MetricID;
-import org.eclipse.microprofile.metrics.MetricRegistry;
-import org.eclipse.microprofile.metrics.Tag;
+import static java.util.Optional.ofNullable;
 
 @Interceptor
 @Priority(Interceptor.Priority.LIBRARY_BEFORE)
@@ -100,12 +99,12 @@
                     Modifier.isAbstract(executable.getDeclaringClass().getModifiers()) ? type.getJavaClass() : executable.getDeclaringClass(),
                     executable, concurrentGauge == null ? null : concurrentGauge.name(),
                     concurrentGauge != null && concurrentGauge.absolute(),
-                    ofNullable(type.getAnnotation(org.eclipse.microprofile.metrics.annotation.ConcurrentGauge.class))
+                    ofNullable(extension.getAnnotation(type, org.eclipse.microprofile.metrics.annotation.ConcurrentGauge.class))
                             .map(org.eclipse.microprofile.metrics.annotation.ConcurrentGauge::name)
                             .orElse(""));
 
-            final ConcurrentGauge gauge = ConcurrentGauge.class.cast(registry.getMetrics().get(
-                    new MetricID(name, concurrentGauge == null ? new Tag[0] : extension.createTags(concurrentGauge.tags()))));
+            final ConcurrentGauge gauge = registry.getConcurrentGauge(
+                    new MetricID(name, concurrentGauge == null ? new Tag[0] : extension.createTags(concurrentGauge.tags())));
             if (gauge == null) {
                 throw new IllegalStateException("No counter with name [" + name + "] found in registry [" + registry + "]");
             }
diff --git a/geronimo-metrics/src/main/java/org/apache/geronimo/microprofile/metrics/cdi/CountedInterceptor.java b/geronimo-metrics/src/main/java/org/apache/geronimo/microprofile/metrics/cdi/CountedInterceptor.java
index 386f745..7357071 100644
--- a/geronimo-metrics/src/main/java/org/apache/geronimo/microprofile/metrics/cdi/CountedInterceptor.java
+++ b/geronimo-metrics/src/main/java/org/apache/geronimo/microprofile/metrics/cdi/CountedInterceptor.java
@@ -16,14 +16,11 @@
  */
 package org.apache.geronimo.microprofile.metrics.cdi;
 
-import static java.util.Optional.ofNullable;
-
-import java.io.Serializable;
-import java.lang.reflect.Executable;
-import java.lang.reflect.Modifier;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-import java.util.stream.Stream;
+import org.eclipse.microprofile.metrics.Counter;
+import org.eclipse.microprofile.metrics.MetricID;
+import org.eclipse.microprofile.metrics.MetricRegistry;
+import org.eclipse.microprofile.metrics.Tag;
+import org.eclipse.microprofile.metrics.annotation.Counted;
 
 import javax.annotation.Priority;
 import javax.enterprise.inject.Intercepted;
@@ -35,12 +32,14 @@
 import javax.interceptor.AroundInvoke;
 import javax.interceptor.Interceptor;
 import javax.interceptor.InvocationContext;
+import java.io.Serializable;
+import java.lang.reflect.Executable;
+import java.lang.reflect.Modifier;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.stream.Stream;
 
-import org.eclipse.microprofile.metrics.Counter;
-import org.eclipse.microprofile.metrics.MetricID;
-import org.eclipse.microprofile.metrics.MetricRegistry;
-import org.eclipse.microprofile.metrics.Tag;
-import org.eclipse.microprofile.metrics.annotation.Counted;
+import static java.util.Optional.ofNullable;
 
 @Counted
 @Interceptor
@@ -97,10 +96,10 @@
                     Modifier.isAbstract(executable.getDeclaringClass().getModifiers()) ? type.getJavaClass() : executable.getDeclaringClass(),
                     executable, counted == null ? null : counted.name(),
                     counted != null && counted.absolute(),
-                    ofNullable(type.getAnnotation(Counted.class)).map(Counted::name).orElse(""));
+                    ofNullable(extension.getAnnotation(type, Counted.class)).map(Counted::name).orElse(""));
 
-            final Counter counter = Counter.class.cast(registry.getMetrics().get(
-                    new MetricID(name, counted == null ? new Tag[0] : extension.createTags(counted.tags()))));
+            final Counter counter = registry.getCounter(
+                    new MetricID(name, counted == null ? new Tag[0] : extension.createTags(counted.tags())));
             if (counter == null) {
                 throw new IllegalStateException("No counter with name [" + name + "] found in registry [" + registry + "]");
             }
diff --git a/geronimo-metrics/src/main/java/org/apache/geronimo/microprofile/metrics/cdi/MeteredInterceptor.java b/geronimo-metrics/src/main/java/org/apache/geronimo/microprofile/metrics/cdi/MeteredInterceptor.java
index a944811..bb56b77 100644
--- a/geronimo-metrics/src/main/java/org/apache/geronimo/microprofile/metrics/cdi/MeteredInterceptor.java
+++ b/geronimo-metrics/src/main/java/org/apache/geronimo/microprofile/metrics/cdi/MeteredInterceptor.java
@@ -16,14 +16,11 @@
  */
 package org.apache.geronimo.microprofile.metrics.cdi;
 
-import static java.util.Optional.ofNullable;
-
-import java.io.Serializable;
-import java.lang.reflect.Executable;
-import java.lang.reflect.Modifier;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-import java.util.stream.Stream;
+import org.eclipse.microprofile.metrics.Meter;
+import org.eclipse.microprofile.metrics.MetricID;
+import org.eclipse.microprofile.metrics.MetricRegistry;
+import org.eclipse.microprofile.metrics.Tag;
+import org.eclipse.microprofile.metrics.annotation.Metered;
 
 import javax.annotation.Priority;
 import javax.enterprise.inject.Intercepted;
@@ -35,12 +32,14 @@
 import javax.interceptor.AroundInvoke;
 import javax.interceptor.Interceptor;
 import javax.interceptor.InvocationContext;
+import java.io.Serializable;
+import java.lang.reflect.Executable;
+import java.lang.reflect.Modifier;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.stream.Stream;
 
-import org.eclipse.microprofile.metrics.Meter;
-import org.eclipse.microprofile.metrics.MetricID;
-import org.eclipse.microprofile.metrics.MetricRegistry;
-import org.eclipse.microprofile.metrics.Tag;
-import org.eclipse.microprofile.metrics.annotation.Metered;
+import static java.util.Optional.ofNullable;
 
 @Metered
 @Interceptor
@@ -93,10 +92,10 @@
                     Modifier.isAbstract(executable.getDeclaringClass().getModifiers()) ? type.getJavaClass() : executable.getDeclaringClass(),
                     executable, metered == null ? null : metered.name(),
                     metered != null && metered.absolute(),
-                    ofNullable(type.getAnnotation(Metered.class)).map(Metered::name).orElse(""));
+                    ofNullable(extension.getAnnotation(type, Metered.class)).map(Metered::name).orElse(""));
 
-            meter = Meter.class.cast(registry.getMetrics().get(
-                    new MetricID(name, metered == null ? new Tag[0] : extension.createTags(metered.tags()))));
+            meter = registry.getMeter(
+                    new MetricID(name, metered == null ? new Tag[0] : extension.createTags(metered.tags())));
             if (meter == null) {
                 throw new IllegalStateException("No meter with name [" + name + "] found in registry [" + registry + "]");
             }
diff --git a/geronimo-metrics/src/main/java/org/apache/geronimo/microprofile/metrics/cdi/MetricsExtension.java b/geronimo-metrics/src/main/java/org/apache/geronimo/microprofile/metrics/cdi/MetricsExtension.java
index cb50015..79e6b90 100644
--- a/geronimo-metrics/src/main/java/org/apache/geronimo/microprofile/metrics/cdi/MetricsExtension.java
+++ b/geronimo-metrics/src/main/java/org/apache/geronimo/microprofile/metrics/cdi/MetricsExtension.java
@@ -16,28 +16,36 @@
  */
 package org.apache.geronimo.microprofile.metrics.cdi;
 
-import static java.util.Optional.of;
-import static java.util.Optional.ofNullable;
-
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Member;
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.lang.reflect.ParameterizedType;
-import java.lang.reflect.Type;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.concurrent.atomic.AtomicReference;
-import java.util.function.Function;
-import java.util.stream.Stream;
+import org.apache.geronimo.microprofile.metrics.common.BaseMetrics;
+import org.apache.geronimo.microprofile.metrics.common.GaugeImpl;
+import org.apache.geronimo.microprofile.metrics.common.RegistryImpl;
+import org.apache.geronimo.microprofile.metrics.common.jaxrs.MetricsEndpoints;
+import org.apache.geronimo.microprofile.metrics.jaxrs.CdiMetricsEndpoints;
+import org.eclipse.microprofile.metrics.Counter;
+import org.eclipse.microprofile.metrics.Gauge;
+import org.eclipse.microprofile.metrics.Histogram;
+import org.eclipse.microprofile.metrics.Metadata;
+import org.eclipse.microprofile.metrics.Meter;
+import org.eclipse.microprofile.metrics.Metric;
+import org.eclipse.microprofile.metrics.MetricID;
+import org.eclipse.microprofile.metrics.MetricRegistry;
+import org.eclipse.microprofile.metrics.MetricType;
+import org.eclipse.microprofile.metrics.SimpleTimer;
+import org.eclipse.microprofile.metrics.Tag;
+import org.eclipse.microprofile.metrics.Timer;
+import org.eclipse.microprofile.metrics.annotation.ConcurrentGauge;
+import org.eclipse.microprofile.metrics.annotation.Counted;
+import org.eclipse.microprofile.metrics.annotation.Metered;
+import org.eclipse.microprofile.metrics.annotation.RegistryType;
+import org.eclipse.microprofile.metrics.annotation.SimplyTimed;
+import org.eclipse.microprofile.metrics.annotation.Timed;
 
 import javax.enterprise.context.Dependent;
 import javax.enterprise.context.spi.CreationalContext;
 import javax.enterprise.event.Observes;
 import javax.enterprise.inject.Any;
 import javax.enterprise.inject.Default;
+import javax.enterprise.inject.Stereotype;
 import javax.enterprise.inject.spi.AfterBeanDiscovery;
 import javax.enterprise.inject.spi.AfterDeploymentValidation;
 import javax.enterprise.inject.spi.Annotated;
@@ -56,35 +64,30 @@
 import javax.enterprise.inject.spi.configurator.BeanConfigurator;
 import javax.enterprise.util.AnnotationLiteral;
 import javax.enterprise.util.Nonbinding;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Member;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.Function;
+import java.util.stream.Stream;
 
-import org.apache.geronimo.microprofile.metrics.common.BaseMetrics;
-import org.apache.geronimo.microprofile.metrics.common.GaugeImpl;
-import org.apache.geronimo.microprofile.metrics.common.RegistryImpl;
-import org.apache.geronimo.microprofile.metrics.common.jaxrs.MetricsEndpoints;
-import org.apache.geronimo.microprofile.metrics.jaxrs.CdiMetricsEndpoints;
-import org.eclipse.microprofile.metrics.Counter;
-import org.eclipse.microprofile.metrics.Gauge;
-import org.eclipse.microprofile.metrics.Histogram;
-import org.eclipse.microprofile.metrics.Metadata;
-import org.eclipse.microprofile.metrics.Meter;
-import org.eclipse.microprofile.metrics.Metric;
-import org.eclipse.microprofile.metrics.MetricID;
-import org.eclipse.microprofile.metrics.MetricRegistry;
-import org.eclipse.microprofile.metrics.MetricType;
-import org.eclipse.microprofile.metrics.Tag;
-import org.eclipse.microprofile.metrics.Timer;
-import org.eclipse.microprofile.metrics.annotation.ConcurrentGauge;
-import org.eclipse.microprofile.metrics.annotation.Counted;
-import org.eclipse.microprofile.metrics.annotation.Metered;
-import org.eclipse.microprofile.metrics.annotation.RegistryType;
-import org.eclipse.microprofile.metrics.annotation.Timed;
+import static java.util.Optional.of;
+import static java.util.Optional.ofNullable;
 
 public class MetricsExtension implements Extension {
     private static final Tag[] NO_TAG = new Tag[0];
 
-    private final MetricRegistry applicationRegistry = new RegistryImpl();
-    private final MetricRegistry baseRegistry = new RegistryImpl();
-    private final MetricRegistry vendorRegistry = new RegistryImpl();
+    private final MetricRegistry applicationRegistry = new RegistryImpl(MetricRegistry.Type.APPLICATION);
+    private final MetricRegistry baseRegistry = new RegistryImpl(MetricRegistry.Type.BASE);
+    private final MetricRegistry vendorRegistry = new RegistryImpl(MetricRegistry.Type.VENDOR);
 
     private final Map<MetricID, Metadata> registrations = new HashMap<>();
     private final Map<MetricID, Function<BeanManager, Gauge<?>>> gaugeFactories = new HashMap<>();
@@ -228,6 +231,7 @@
 
     void findInterceptorMetrics(@Observes @WithAnnotations({
             Counted.class,
+            SimplyTimed.class,
             Timed.class,
             ConcurrentGauge.class,
             org.eclipse.microprofile.metrics.annotation.Metered.class,
@@ -248,11 +252,11 @@
                     final Member javaMember = method.getJavaMember();
 
                     final Counted counted = ofNullable(method.getAnnotation(Counted.class)).orElseGet(() ->
-                            annotatedType.getAnnotation(Counted.class));
+                            getAnnotation(annotatedType, Counted.class));
                     if (counted != null) {
                         final boolean isMethod = method.isAnnotationPresent(Counted.class);
                         final String name = Names.findName(javaClass, javaMember, isMethod ? counted.name() : "", counted.absolute(),
-                                ofNullable(annotatedType.getAnnotation(Counted.class)).map(Counted::name).orElse(""));
+                                ofNullable(getAnnotation(annotatedType, Counted.class)).map(Counted::name).orElse(""));
                         final Metadata metadata = Metadata.builder()
                                 .withName(name)
                                 .withDisplayName(counted.displayName())
@@ -265,11 +269,11 @@
                     }
 
                     final ConcurrentGauge concurrentGauge = ofNullable(method.getAnnotation(ConcurrentGauge.class)).orElseGet(() ->
-                            annotatedType.getAnnotation(ConcurrentGauge.class));
+                            getAnnotation(annotatedType, ConcurrentGauge.class));
                     if (concurrentGauge != null) {
                         final boolean isMethod = method.isAnnotationPresent(ConcurrentGauge.class);
                         final String name = Names.findName(javaClass, javaMember, isMethod ? concurrentGauge.name() : "", concurrentGauge.absolute(),
-                                ofNullable(annotatedType.getAnnotation(ConcurrentGauge.class)).map(ConcurrentGauge::name).orElse(""));
+                                ofNullable(getAnnotation(annotatedType, ConcurrentGauge.class)).map(ConcurrentGauge::name).orElse(""));
                         final Metadata metadata = Metadata.builder()
                                 .withName(name)
                                 .withDisplayName(concurrentGauge.displayName())
@@ -281,11 +285,11 @@
                         addRegistration(metadata, metricID, concurrentGauge.reusable() || !isMethod);
                     }
 
-                    final Timed timed = ofNullable(method.getAnnotation(Timed.class)).orElseGet(() -> annotatedType.getAnnotation(Timed.class));
+                    final Timed timed = ofNullable(method.getAnnotation(Timed.class)).orElseGet(() -> getAnnotation(annotatedType, Timed.class));
                     if (timed != null) {
                         final boolean isMethod = method.isAnnotationPresent(Timed.class);
                         final String name = Names.findName(javaClass, javaMember, isMethod ? timed.name() : "", timed.absolute(),
-                                ofNullable(annotatedType.getAnnotation(Timed.class)).map(Timed::name).orElse(""));
+                                ofNullable(getAnnotation(annotatedType, Timed.class)).map(Timed::name).orElse(""));
                         final Metadata metadata = Metadata.builder()
                                 .withName(name)
                                 .withDisplayName(timed.displayName())
@@ -297,12 +301,28 @@
                         addRegistration(metadata, metricID, timed.reusable() || !isMethod);
                     }
 
+                    final SimplyTimed simplyTimed = ofNullable(method.getAnnotation(SimplyTimed.class)).orElseGet(() -> getAnnotation(annotatedType, SimplyTimed.class));
+                    if (simplyTimed != null) {
+                        final boolean isMethod = method.isAnnotationPresent(SimplyTimed.class);
+                        final String name = Names.findName(javaClass, javaMember, isMethod ? simplyTimed.name() : "", simplyTimed.absolute(),
+                                ofNullable(getAnnotation(annotatedType, SimplyTimed.class)).map(SimplyTimed::name).orElse(""));
+                        final Metadata metadata = Metadata.builder()
+                                .withName(name)
+                                .withDisplayName(simplyTimed.displayName())
+                                .withDescription(simplyTimed.description())
+                                .withType(MetricType.SIMPLE_TIMER)
+                                .withUnit(simplyTimed.unit())
+                                .build();
+                        final MetricID metricID = new MetricID(name, createTags(simplyTimed.tags()));
+                        addRegistration(metadata, metricID, simplyTimed.reusable() || !isMethod);
+                    }
+
                     final org.eclipse.microprofile.metrics.annotation.Metered metered = ofNullable(method.getAnnotation(org.eclipse.microprofile.metrics.annotation.Metered.class))
-                            .orElseGet(() -> annotatedType.getAnnotation(org.eclipse.microprofile.metrics.annotation.Metered.class));
+                            .orElseGet(() -> getAnnotation(annotatedType, org.eclipse.microprofile.metrics.annotation.Metered.class));
                     if (metered != null) {
                         final boolean isMethod = method.isAnnotationPresent(Metered.class);
                         final String name = Names.findName(javaClass, javaMember, isMethod ? metered.name() : "", metered.absolute(),
-                                ofNullable(annotatedType.getAnnotation(Metered.class)).map(Metered::name).orElse(""));
+                                ofNullable(getAnnotation(annotatedType, Metered.class)).map(Metered::name).orElse(""));
                         final Metadata metadata = Metadata.builder()
                                 .withName(name)
                                 .withDisplayName(metered.displayName())
@@ -315,12 +335,11 @@
                     }
 
                     final org.eclipse.microprofile.metrics.annotation.Gauge gauge = ofNullable(method.getAnnotation(org.eclipse.microprofile.metrics.annotation.Gauge.class))
-                            .orElseGet(() -> annotatedType.getAnnotation(org.eclipse.microprofile.metrics.annotation
-                                    .Gauge.class));
+                            .orElseGet(() -> getAnnotation(annotatedType, org.eclipse.microprofile.metrics.annotation.Gauge.class));
                     if (gauge != null) {
                         final String name = Names.findName(
                                 javaClass, javaMember, gauge.name(), gauge.absolute(),
-                                ofNullable(annotatedType.getAnnotation(org.eclipse.microprofile.metrics.annotation.Gauge.class)).map(org.eclipse.microprofile.metrics.annotation.Gauge::name).orElse(""));
+                                ofNullable(getAnnotation(annotatedType, org.eclipse.microprofile.metrics.annotation.Gauge.class)).map(org.eclipse.microprofile.metrics.annotation.Gauge::name).orElse(""));
                         final Metadata metadata = Metadata.builder()
                                 .withName(name)
                                 .withDisplayName(gauge.displayName())
@@ -367,6 +386,10 @@
                     addBean(afterBeanDiscovery, idSuffix, Timer.class, new MetricImpl(metadata, id),
                             applicationRegistry.timer(metadata, id.getTagsAsList().toArray(NO_TAG)), true);
                     break;
+                case SIMPLE_TIMER:
+                    addBean(afterBeanDiscovery, idSuffix, SimpleTimer.class, new MetricImpl(metadata, id),
+                            applicationRegistry.simpleTimer(metadata, id.getTagsAsList().toArray(NO_TAG)), true);
+                    break;
                 case COUNTER:
                     addBean(afterBeanDiscovery, idSuffix, Counter.class, new MetricImpl(metadata, id),
                             applicationRegistry.counter(metadata, id.getTagsAsList().toArray(NO_TAG)), true);
@@ -454,6 +477,8 @@
             type = MetricType.METERED;
         } else if (Timer.class.isAssignableFrom(clazz)) {
             type = MetricType.TIMER;
+        } else if (SimpleTimer.class.isAssignableFrom(clazz)) {
+            type = MetricType.SIMPLE_TIMER;
         } else if (Histogram.class.isAssignableFrom(clazz)) {
             type = MetricType.HISTOGRAM;
         } else if (org.eclipse.microprofile.metrics.ConcurrentGauge.class.isAssignableFrom(clazz)) {
@@ -508,6 +533,20 @@
         }
     }
 
+    public <T extends Annotation> T getAnnotation(final AnnotatedType<?> type, final Class<T> expected) {
+        final T annotation = type.getAnnotation(expected);
+        if (annotation != null) {
+            return annotation;
+        }
+        // not sexy but not great to use too
+        return type.getAnnotations().stream()
+                .filter(a -> a.annotationType().isAnnotationPresent(Stereotype.class))
+                .map(a -> a.annotationType().getAnnotation(expected))
+                .filter(Objects::nonNull)
+                .findFirst()
+                .orElse(null);
+    }
+
     private static final class MetricImpl extends AnnotationLiteral<org.eclipse.microprofile.metrics.annotation.Metric> implements org.eclipse.microprofile.metrics.annotation.Metric {
         private final Metadata metadata;
         private final String[] tags;
@@ -573,14 +612,4 @@
             return RegistryType.class;
         }
     }
-
-    private static class Registration {
-        private final MetricID id;
-        private final Metadata metadata;
-
-        private Registration(final MetricID id, final Metadata metadata) {
-            this.id = id;
-            this.metadata = metadata;
-        }
-    }
 }
diff --git a/geronimo-metrics/src/main/java/org/apache/geronimo/microprofile/metrics/cdi/SimplyTimedInterceptor.java b/geronimo-metrics/src/main/java/org/apache/geronimo/microprofile/metrics/cdi/SimplyTimedInterceptor.java
new file mode 100644
index 0000000..b97e8d7
--- /dev/null
+++ b/geronimo-metrics/src/main/java/org/apache/geronimo/microprofile/metrics/cdi/SimplyTimedInterceptor.java
@@ -0,0 +1,101 @@
+/*
+ * 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.geronimo.microprofile.metrics.cdi;
+
+import org.eclipse.microprofile.metrics.MetricID;
+import org.eclipse.microprofile.metrics.MetricRegistry;
+import org.eclipse.microprofile.metrics.SimpleTimer;
+import org.eclipse.microprofile.metrics.Tag;
+import org.eclipse.microprofile.metrics.annotation.SimplyTimed;
+
+import javax.annotation.Priority;
+import javax.enterprise.inject.Intercepted;
+import javax.enterprise.inject.spi.AnnotatedType;
+import javax.enterprise.inject.spi.Bean;
+import javax.enterprise.inject.spi.BeanManager;
+import javax.inject.Inject;
+import javax.interceptor.AroundConstruct;
+import javax.interceptor.AroundInvoke;
+import javax.interceptor.Interceptor;
+import javax.interceptor.InvocationContext;
+import java.io.Serializable;
+import java.lang.reflect.Executable;
+import java.lang.reflect.Modifier;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.stream.Stream;
+
+import static java.util.Optional.ofNullable;
+
+@SimplyTimed
+@Interceptor
+@Priority(Interceptor.Priority.LIBRARY_BEFORE)
+public class SimplyTimedInterceptor implements Serializable {
+    @Inject
+    private MetricRegistry registry;
+
+    @Inject
+    @Intercepted
+    private Bean<?> bean;
+
+    @Inject
+    private BeanManager beanManager;
+
+    @Inject
+    private MetricsExtension extension;
+
+    private transient volatile ConcurrentMap<Executable, SimpleTimer> timers = new ConcurrentHashMap<>();
+
+    @AroundConstruct
+    public Object onConstructor(final InvocationContext context) throws Exception {
+        return findTimer(context.getConstructor()).time(context::proceed);
+    }
+
+    @AroundInvoke
+    public Object onMethod(final InvocationContext context) throws Exception {
+        return findTimer(context.getMethod()).time(context::proceed);
+    }
+
+    private SimpleTimer findTimer(final Executable executable) {
+        if (timers == null) {
+            synchronized (this) {
+                if (timers == null) {
+                    timers = new ConcurrentHashMap<>();
+                }
+            }
+        }
+        SimpleTimer timer = timers.get(executable);
+        if (timer == null) {
+            final AnnotatedType<?> type = beanManager.createAnnotatedType(bean.getBeanClass());
+            final SimplyTimed timed = Stream.concat(type.getMethods().stream(), type.getConstructors().stream())
+                    .filter(it -> it.getJavaMember().equals(executable))
+                    .findFirst()
+                    .map(m -> m.getAnnotation(SimplyTimed.class))
+                    .orElse(null);
+            final String name = Names.findName(
+                    Modifier.isAbstract(executable.getDeclaringClass().getModifiers()) ? type.getJavaClass() : executable.getDeclaringClass(),
+                    executable, timed == null ? null : timed.name(), timed != null && timed.absolute(),
+                    ofNullable(extension.getAnnotation(type, SimplyTimed.class)).map(SimplyTimed::name).orElse(""));
+            timer = registry.getSimpleTimer(new MetricID(name, timed == null ? new Tag[0] : extension.createTags(timed.tags())));
+            if (timer == null) {
+                throw new IllegalStateException("No timer with name [" + name + "] found in registry [" + registry + "]");
+            }
+            timers.putIfAbsent(executable, timer);
+        }
+        return timer;
+    }
+}
diff --git a/geronimo-metrics/src/main/java/org/apache/geronimo/microprofile/metrics/cdi/TimedInterceptor.java b/geronimo-metrics/src/main/java/org/apache/geronimo/microprofile/metrics/cdi/TimedInterceptor.java
index f760c83..d736fc1 100644
--- a/geronimo-metrics/src/main/java/org/apache/geronimo/microprofile/metrics/cdi/TimedInterceptor.java
+++ b/geronimo-metrics/src/main/java/org/apache/geronimo/microprofile/metrics/cdi/TimedInterceptor.java
@@ -90,9 +90,8 @@
             final String name = Names.findName(
                     Modifier.isAbstract(executable.getDeclaringClass().getModifiers()) ? type.getJavaClass() : executable.getDeclaringClass(),
                     executable, timed == null ? null : timed.name(), timed != null && timed.absolute(),
-                    ofNullable(type.getAnnotation(Timed.class)).map(Timed::name).orElse(""));
-            timer = Timer.class.cast(registry.getMetrics().get(
-                    new MetricID(name, timed == null ? new Tag[0] : extension.createTags(timed.tags()))));
+                    ofNullable(extension.getAnnotation(type, Timed.class)).map(Timed::name).orElse(""));
+            timer = registry.getTimer(new MetricID(name, timed == null ? new Tag[0] : extension.createTags(timed.tags())));
             if (timer == null) {
                 throw new IllegalStateException("No timer with name [" + name + "] found in registry [" + registry + "]");
             }
diff --git a/pom.xml b/pom.xml
index e33d4c5..616437a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -42,7 +42,7 @@
   </scm>
 
   <properties>
-    <spec.version>2.2.1</spec.version>
+    <spec.version>3.0-M2</spec.version>
     <arquillian.version>1.1.8.Final</arquillian.version>
     <meecrowave.version>1.2.8</meecrowave.version>
   </properties>
@@ -116,13 +116,13 @@
       <dependency>
         <groupId>org.apache.geronimo.specs</groupId>
         <artifactId>geronimo-jcdi_2.0_spec</artifactId>
-        <version>1.0.1</version>
+        <version>1.1</version>
         <scope>provided</scope>
       </dependency>
       <dependency>
         <groupId>org.apache.geronimo.specs</groupId>
         <artifactId>geronimo-annotation_1.3_spec</artifactId>
-        <version>1.0</version>
+        <version>1.2</version>
         <scope>provided</scope>
       </dependency>
       <dependency>
@@ -147,7 +147,7 @@
       <dependency>
         <groupId>org.apache.openwebbeans</groupId>
         <artifactId>openwebbeans-web</artifactId>
-        <version>2.0.7</version>
+        <version>2.0.16</version>
         <scope>test</scope>
       </dependency>
     </dependencies>
@@ -158,7 +158,7 @@
       <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-compiler-plugin</artifactId>
-        <version>3.8.0</version>
+        <version>3.8.1</version>
         <configuration>
           <source>1.8</source>
           <target>1.8</target>