All Projects → astefanutti → metrics-aspectj

astefanutti / metrics-aspectj

Licence: Apache-2.0 license
AspectJ integration for Dropwizard Metrics

Programming Languages

java
68154 projects - #9 most used programming language
AspectJ
31 projects

Projects that are alternatives of or similar to metrics-aspectj

Paonet
【MVVM+RxJava2+AspectJ】泡网第三方客户端,网站主页:http://www.jcodecraeer.com/index.php
Stars: ✭ 374 (+379.49%)
Mutual labels:  aop, aspectj
android-aop-analytics
Demo application that implements Google Analytics tracking in an aspect-oriented way using AspectJ.
Stars: ✭ 31 (-60.26%)
Mutual labels:  aop, aspectj
Crepecake
An compile-time aop engine like AspectJ but easier to use in android application development.
Stars: ✭ 103 (+32.05%)
Mutual labels:  aop, aspectj
T Mvp
Android AOP Architecture by Apt, AspectJ, Javassisit, based on Realm+Databinding+MVP+Retrofit+Rxjava2
Stars: ✭ 2,740 (+3412.82%)
Mutual labels:  aop, aspectj
Automon
Automon combines the power of AOP (AspectJ) with monitoring or logging tools you already use to declaratively monitor your Java code, the JDK, and 3rd party libraries.
Stars: ✭ 548 (+602.56%)
Mutual labels:  aop, aspectj
Androidlearn
Android Custom Views
Stars: ✭ 66 (-15.38%)
Mutual labels:  aop, aspectj
Fragmentrigger
💥A powerful library powered by AOP to manage Fragments.(一个基于AOP设计的Fragment管理框架)
Stars: ✭ 2,260 (+2797.44%)
Mutual labels:  aop, aspectj
hasor
Hasor是一套基于 Java 语言的开发框架,区别于其它框架的是 Hasor 有着自己一套完整的体系,同时还可以和先有技术体系做到完美融合。它包含:IoC/Aop容器框架、Web框架、Jdbc框架、RSF分布式RPC框架、DataQL引擎,等几块。
Stars: ✭ 938 (+1102.56%)
Mutual labels:  aop
egg-aop
AOP plugin for eggjs, add DI, AOP support.
Stars: ✭ 44 (-43.59%)
Mutual labels:  aop
Lokie
iOS efficient AOP Library using C++ and libffi
Stars: ✭ 139 (+78.21%)
Mutual labels:  aop
langx-java
Java tools, helper, common utilities. A replacement of guava, apache-commons, hutool
Stars: ✭ 50 (-35.9%)
Mutual labels:  aop
MethodBoundaryAspect.Fody
A Fody weaver which allows to decorate methods and hook into method start, method end and method exceptions.
Stars: ✭ 173 (+121.79%)
Mutual labels:  aop
dropwizard-elasticsearch
A set of classes for using Elasticsearch in a Dropwizard service.
Stars: ✭ 61 (-21.79%)
Mutual labels:  dropwizard
CrmWebApi
🎉 CRM后台管理系统(后端 WebApi)
Stars: ✭ 13 (-83.33%)
Mutual labels:  aop
DRouter
简单易用的支持多进程架构的组件化方案
Stars: ✭ 74 (-5.13%)
Mutual labels:  aop
Deflector.NET
A library for intercepting all method calls at runtime in nearly any .NET application.
Stars: ✭ 80 (+2.56%)
Mutual labels:  aop
instrumentation
An extensible java agent framework that instruments (modifies the bytecode at class loading time) programs running on the JVM, with the purpose of capturing method invocation events (start, finish, errors ...) and notifying custom listeners.
Stars: ✭ 39 (-50%)
Mutual labels:  aop
keycloak-dropwizard-integration
This project shows how JBoss Keycloak and Dropwizard can be used together.
Stars: ✭ 49 (-37.18%)
Mutual labels:  dropwizard
metrics-spring-boot
Spring Boot 基于Sentinel服务接口监控及其手自一体化限流
Stars: ✭ 17 (-78.21%)
Mutual labels:  aop
Farseer.Net
Provides consistent standard use of common components of the .Net Core language
Stars: ✭ 42 (-46.15%)
Mutual labels:  aop

AspectJ for Metrics

Build Status Coverage Status Maven Central

AspectJ integration for Dropwizard Metrics with optional Expression Language 3.0 (JSR-341) support.

About

Metrics AspectJ provides support for the Metrics annotations in Java SE environments using AspectJ to perform AOP instrumentation. It implements the contract specified by these annotations with the following level of functionality:

Metrics AspectJ is compatible with Metrics version 3.0.0+ and requires Java 6 or higher.

Getting Started

Using Maven

Add the metrics-aspectj library as a dependency:

<dependency>
    <groupId>io.astefanutti.metrics.aspectj</groupId>
    <artifactId>metrics-aspectj</artifactId>
    <version>1.2.0</version>
</dependency>

And configure the maven-aspectj-plugin to compile-time weave (CTW) the metrics-aspectj aspects into your project:

<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>aspectj-maven-plugin</artifactId>
    <configuration>
        <aspectLibraries>
            <aspectLibrary>
                <groupId>io.astefanutti.metrics.aspectj</groupId>
                <artifactId>metrics-aspectj</artifactId>
            </aspectLibrary>
        </aspectLibraries>
    </configuration>
    <executions>
        <execution>
            <goals>
                <goal>compile</goal>
            </goals>
        </execution>
    </executions>
</plugin>

More information can be found in the Maven AspectJ plugin documentation.

Using Ant

Use the AjcTask (iajc) Ant task:

<target name="{target}" >
    <iajc sourceroots="${basedir}/src"
          classpath="${basedir}/lib/aspectjrt.jar"
          outjar="${basedir}/build/${ant.project.name}.jar">
        ...
        <aspectpath>
            <pathelement location="${basedir}/lib/metrics-aspectj.jar"/>
        </aspectpath>
        ...
    </iajc>
</target>

Other options are detailed in the AspectJ Ant tasks documentation.

Using Gradle

A working gradle example is available, but each integration point is described here.

build.gradle snippets
buildscript {
    // ensure the gradle-aspectj integration is w/i the build classpath
    dependencies {
        classpath 'nl.eveoh:gradle-aspectj:1.6'
    }
}

// specify the aspectjVersion, used by gradle-aspectj
project.ext {
    aspectjVersion = '1.8.10'
}

// specify the Dropwizard Metrics version (metricsVer)
//  and the aspect-oriented metrics version (metricsAspectVer, this solution)
ext {
    metricsVer = '3.2.2'
    metricsAspectVer = '1.2.0'
}

// via the gradle-aspectj integration, run "aspect weaving"
apply plugin: 'aspectj'

// ensure Dropwizard Metrics as well as the aspect-oriented metrics (astefanutti.metrics.aspectj)
//  runtime dependencies of your solution are satisfied.
dependencies {
    compile "io.astefanutti.metrics.aspectj:metrics-aspectj:${metricsAspectVer}"
    // add a path for the gradle-aspectj "aspect weaving" (AspectJ Compiler compile)
    aspectpath "io.astefanutti.metrics.aspectj:metrics-aspectj:${metricsAspectVer}"

    compile "io.dropwizard.metrics:metrics-core:${metricsVer}"
    compile "io.dropwizard.metrics:metrics-annotation:${metricsVer}"
}

Using the AspectJ Compiler

The AspectJ compiler can be used directly by executing the following command:

ajc -aspectpath metrics-aspectj.jar [Options] [file...]

More information can be found in the AspectJ compiler / weaver documentation.

Required Dependencies

Besides depending on Metrics (metrics-core and metrics-annotation modules), Metrics AspectJ requires the AspectJ aspectjrt module:

<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjrt</artifactId>
</dependency>

These three modules are transitive dependencies of the metrics-aspectj Maven module.

Alternatively, the metrics-aspectj-deps artifact that re-packages the metrics-annotation and the aspectjrt modules can be used so that the only required dependency is metrics-core:

<dependency>
    <groupId>io.astefanutti.metrics.aspectj</groupId>
    <artifactId>metrics-aspectj-deps</artifactId>
</dependency>

Optional Dependencies

In addition to that, Metrics AspectJ optional support of EL 3.0 expression for MetricRegistry resolution and Metric name evaluation requires an implementation of Expression Language 3.0 (JSR-341) to be present at runtime. For example, the metrics-aspectj-el module is using the GlassFish reference implementation as test dependency for its unit tests execution:

<dependency>
    <groupId>org.glassfish</groupId>
    <artifactId>javax.el</artifactId>
</dependency>

Usage

Metrics AspectJ Activation

In order to activate Metrics AspectJ for a particular class, it must be annotated with the @Metrics annotation:

import com.codahale.metrics.annotation.Timed;

import io.astefanutti.metrics.aspectj.Metrics;

@Metrics
class TimedMethod {

    @Timed(name = "timerName")
    void timedMethod() {} // Timer name => TimedMethod.timerName
}

At weaving time, Metrics AspectJ will detect the @Metrics annotation, scan all the declared methods of the target class that are annotated with Metrics annotations, then create and register the corresponding Metric instances and weave its aspects around these methods. At runtime, these Metric instances will eventually get called according to the Metrics annotations specification.

Note that Metrics annotations won't be inherited if declared on an interface or a parent class method. More details are available in the Limitations section.

The Metrics Annotations

Metrics comes with the metrics-annotation module that contains a set of annotations and provides a standard way to integrate Metrics with frameworks supporting Aspect Oriented Programming (AOP). These annotations are supported by Metrics AspectJ that implements their contract as documented in their Javadoc.

For example, a method can be annotated with the @Timed annotation so that its execution can be monitored using Metrics:

import com.codahale.metrics.annotation.Timed;

import io.astefanutti.metrics.aspectj.Metrics;

@Metrics
class TimedMethod {

    @Timed(name = "timerName")
    void timedMethod() {} // Timer name => TimedMethod.timerName
}

In that example, Metrics AspectJ will instrument all the constructors of the TimedMethod class by injecting Java bytecode that will automatically create a Timer instance with the provided name (or retrieve an existing Timer with the same name already registered in the MetricRegistry) right after the instantiation of the TimedMethod class and inline the method invocation around with the needed code to time the method execution using that Timer instance.

A static method can also be annotated with the @Timed annotation so that its execution can be monitored using Metrics:

import com.codahale.metrics.annotation.Timed;

import io.astefanutti.metrics.aspectj.Metrics;

@Metrics
class TimedMethod {

    @Timed(name = "timerName")
    static void timedStaticMethod() {} // Timer name => TimedMethod.timerName
}

In that example, Metrics AspectJ will instrument the TimedMethod class so that, when it's loaded, a Timer instance with the provided name will be created (or an existing Timer with the same name already registered in the MetricRegistry will be retrieved) and inline the method invocation around with the needed code to time the method execution using that Timer instance.

Optionally, the Metric name can be resolved with an EL expression that evaluates to a String:

import com.codahale.metrics.annotation.Timed;

import io.astefanutti.metrics.aspectj.Metrics;

@Metrics
class TimedMethod {

    private long id;

    public long getId() {
        return id;
    }

    @Timed(name = "timerName ${this.id}")
    void timedMethod() {} // Timer name => TimedMethod.timerName <id>
}

In that example, Metrics AspectJ will automatically create a Timer instance (respectively retrieve an existing Timer instance with the same name already registered in the MetricRegistry) right after the instantiation of the TimedMethod class and evaluate the EL expression based on the value of the id attribute of that newly created TimedMethod instance to name the Timer instance (respectively resolve the Timer instance registered in the MetricRegistry). If the value of the id attribute changes over time, the name of the Timer instance won't be re-evaluated.

Note that these annotations won't be inherited if they are placed on interface or parent class methods. Indeed, according to the Java language specification, non-type annotations are not inherited. It is discussed in more details in the Limitations section.

Metrics Registry Resolution

The Metrics.registry annotation attribute provides the way to declare the MetricRegistry to register the generated Metric instances into. Its value can either be a string literal that identifies a MetricRegistry accessible by name from the SharedMetricRegistries class or a valid EL expression that evaluates to the registry name or the registry instance. The resultant MetricRegistry is used to register the Metric instantiated into each time a Metrics annotation is present on that class methods. It defaults to the string literal metrics-registry.

The MetricRegistry can thus be resolved by name relying on the SharedMetricRegistries.getOrCreate(String name) method:

import com.codahale.metrics.annotation.Metered;

import io.astefanutti.metrics.aspectj.Metrics;

@Metrics(registry = "registryName")
class MeteredMethodWithRegistryByName {

    @Metered(name = "meterName")
    void meteredMethod() {} // Registry => SharedMetricRegistries.getOrCreate("registryName")
}

Or with an EL expression that evaluates to a bean property of type MetricRegistry:

import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.annotation.Metered;

import io.astefanutti.metrics.aspectj.Metrics;

@Metrics(registry = "${this.registry}")
class MeteredMethodWithRegistryFromProperty {

    final MetricRegistry registry;

    MeteredMethodWithRegistryFromProperty(MetricRegistry registry) {
        this.registry = registry;
    }

    MetricRegistry getRegistry() {
        return registry;
    }

    @Metered(name = "meterName")
    void meteredMethod() {} // Registry => this.getRegistry()
}

Or with an EL expression that evaluates to a String. In that case the registry is resolved by name using the SharedMetricRegistries.getOrCreate(String name) method.

Limitations

The Metrics annotations are not inherited whether these are declared on a parent class or an implemented interface method. The root causes of that limitation, according to the Java language specification, are:

  • Non-type annotations are not inherited,
  • Annotations on types are only inherited if they have the @Inherited meta-annotation,
  • Annotations on interfaces are not inherited irrespective to having the @Inherited meta-annotation.

See the @Inherited Javadoc and Annotation types from the Java language specification for more details.

AspectJ follows the Java language specification and has documented to what extent it's impacted in Annotation inheritance and Annotation inheritance and pointcut matching. There would have been ways of working around that though:

  • That would have been working around the Java language specification in the first place,
  • Plus that would have required to rely on a combination of Expression-based pointcuts, Runtime type matching and Reflective access to define conditional pointcut expressions which:
    • Would have widen the scope of matching joint points thus introducing side-effects in addition to being inefficient,
    • Would have been evaluated at runtime for each candidate join point relying on the Java Reflection API thus impacting the application performance and incidentally voiding the non-intrusive benefit of AOP in a larger sense.

Spring AOP vs. AspectJ

Spring AOP and AspectJ provides Aspect Oriented Programming (AOP) in two very different ways:

  • AspectJ provides a full-fledged aspect definition and support both Compile Time Weaving (CTW) and Load Time Weaving (LTW) (with a Java agent) and implements AOP with class instrumentation (byte code manipulation),
  • Spring AOP does not support the whole AspectJ aspect definition and does not support Compile Time Weaving,
  • Spring AOP implements AOP either using (see Spring proxying mechanisms):
    • JDK dynamic proxies, which add little runtime overhead, clutter stack traces and can be incompatible with other Spring functionality like Spring JMX (for dynamic MBean export for example),
    • Or CGLIB (byte code manipulation), that has to be added as a runtime dependency:
      • It dynamically extends classes thus it is incompatible with final classes or methods,
      • CGLIB development isn't active, Hibernate has been deprecating it in favor of Javassist (see Deprecated CGLIB support),
  • AJDT (AspectJ Development Tools) provides deep integration between AspectJ and the Eclipse platform which is not possible with Spring AOP due to the runtime / dynamic nature of its AOP implementation.

Further details can be found in Choosing which AOP declaration style to use from the Spring framework documentation. The Spring AOP vs AspectJ question on Stack Overflow provides some insights as well.

License

Copyright © 2013-2016, Antonin Stefanutti

Published under Apache Software License 2.0, see LICENSE

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].