OSGi Community Event 2016 Presentation by Simon Chemouil (Lambdacube)
Aspect-oriented programming is a paradigm meant to provide “horizontal” modularity: by encapsulating cross-cutting concerns such as access control or performance metrics away from business logic, it was supposed to be a new tool for developers that would not only prevent copy-paste and guard methods, but allow to stack semantic models on top of single-concern implementations.
The early excitement somewhat faded when the freedom provided by rich aspect languages proved to make understanding of code and its debugging harder because of scattered logic and altered bytecode. Today in the Java world, it is used mostly in a lighter form in the Spring framework, but it has traditionally been difficult to integrate properly with OSGi.
When OSGi R5 introduced the ServiceHook API, one of its promises was to enable OSGi-powered implementations of aspect frameworks. Aspecio[1] is such a framework, taking an opinionated approach to aspects to make them predictable while giving a lot of control to developers and keeping the overhead minimal:
Fully OSGi-compliant: Interceptors are services, dynamism is fully supported ;
Define your aspects in plain Java ;
Works with any OSGi component framework, such as Declarative Services, Blueprint, or plain OSGi core APIs ;
Minimal overhead: on-demand bytecode generation, no primitive boxing or Method#invoke, and a “pay only for what you use” approach through a Java 8 mixin-like advice definition API ;
Reasonably easy to debug: no change to existing bytecode, generated proxies are very thin and expose a well-documented behavior.
The OSGi service model is so versatile that aspects could feel useless at first glance; it turns out they are a handy and complementary tool in OSGi application design.
In this talk, I will present Aspecio and what we can accomplish by mixing the OSGi service model with aspects, and demonstrate how anyone can add aspects to any OSGi application in a few minutes without refactoring existing code.
2. Motivation
Aspecio
Summary
Aspecio
Aspecio
A Java/OSGi R6+ ’micro-framework’ that brings a mix of
component-oriented and aspect-oriented programming to your
application.
http: // lambdacube. github. io/ aspecio/
2 / 35 Simon Chemouil Aspecio
3. Motivation
Aspecio
Summary
Outline
1 Motivation
DRY and modularity
Dealing with cross-cutting concerns
2 Aspecio
Overview
Using Aspecio
Interceptors, Advices and Proxies
Getting started
3 Summary
3 / 35 Simon Chemouil Aspecio
4. Motivation
Aspecio
Summary
DRY and modularity
Dealing with cross-cutting concerns
Outline
1 Motivation
DRY and modularity
Dealing with cross-cutting concerns
2 Aspecio
Overview
Using Aspecio
Interceptors, Advices and Proxies
Getting started
3 Summary
4 / 35 Simon Chemouil Aspecio
5. Motivation
Aspecio
Summary
DRY and modularity
Dealing with cross-cutting concerns
The DRY Principle
Do Not Repeat Yourself
Mostly a rule-of-thumb to organize code
Benefits:
Share code / Fix problems once (modularity)
Limit verbosity (readability)
5 / 35 Simon Chemouil Aspecio
6. Motivation
Aspecio
Summary
DRY and modularity
Dealing with cross-cutting concerns
The DRY Principle
Do Not Repeat Yourself
Mostly a rule-of-thumb to organize code
Benefits:
Share code / Fix problems once (modularity)
Limit verbosity (readability)
5 / 35 Simon Chemouil Aspecio
7. Motivation
Aspecio
Summary
DRY and modularity
Dealing with cross-cutting concerns
The DRY Principle
Do Not Repeat Yourself
Mostly a rule-of-thumb to organize code
Benefits:
Share code / Fix problems once (modularity)
Limit verbosity (readability)
5 / 35 Simon Chemouil Aspecio
8. Motivation
Aspecio
Summary
DRY and modularity
Dealing with cross-cutting concerns
The DRY Principle
Do Not Repeat Yourself
Mostly a rule-of-thumb to organize code
Benefits:
Share code / Fix problems once (modularity)
Limit verbosity (readability)
5 / 35 Simon Chemouil Aspecio
9. Motivation
Aspecio
Summary
DRY and modularity
Dealing with cross-cutting concerns
The DRY Principle
Do Not Repeat Yourself
Mostly a rule-of-thumb to organize code
Benefits:
Share code / Fix problems once (modularity)
Limit verbosity (readability)
5 / 35 Simon Chemouil Aspecio
10. Motivation
Aspecio
Summary
DRY and modularity
Dealing with cross-cutting concerns
Motivation: modularizing implementations
OSGi solves API & service modularity
What about implementations?
6 / 35 Simon Chemouil Aspecio
11. Motivation
Aspecio
Summary
DRY and modularity
Dealing with cross-cutting concerns
Motivation: modularizing implementations
OSGi solves API & service modularity
What about implementations?
6 / 35 Simon Chemouil Aspecio
12. Motivation
Aspecio
Summary
DRY and modularity
Dealing with cross-cutting concerns
Outline
1 Motivation
DRY and modularity
Dealing with cross-cutting concerns
2 Aspecio
Overview
Using Aspecio
Interceptors, Advices and Proxies
Getting started
3 Summary
7 / 35 Simon Chemouil Aspecio
13. Motivation
Aspecio
Summary
DRY and modularity
Dealing with cross-cutting concerns
Modularizing implementations
Example
package com.mylibrary.book;
@Component
public final class BookManagerImpl implements BookManager {
@Reference AccessControl accessControl ;
public Promise <Book > getBook(String isbn) {
try {
accessControl . ensureAuthorized (...);
/* business code here */
return actuallyGetBookNow (isbn );
} catch (Exception e) {
return Promises.failed(e);
}
}
}
8 / 35 Simon Chemouil Aspecio
14. Motivation
Aspecio
Summary
DRY and modularity
Dealing with cross-cutting concerns
Modularizing implementations
Example
package com.mylibrary.book;
@Component
public final class BookManagerImpl implements BookManager {
@ EnsureAuthorized
public Promise <Book > getBook(String isbn) {
/* business code here */
return actuallyGetBookNow (isbn );
}
}
9 / 35 Simon Chemouil Aspecio
15. Motivation
Aspecio
Summary
DRY and modularity
Dealing with cross-cutting concerns
Modularizing implementations
Example
package com.mylibrary.book;
@Component
public final class BookManagerImpl implements BookManager {
@ EnsureAuthorized
@Measured
public Promise <Book > getBook(String isbn) {
/* business code here */
return actuallyGetBookNow (isbn );
}
}
10 / 35 Simon Chemouil Aspecio
16. Motivation
Aspecio
Summary
Overview
Using Aspecio
Interceptors, Advices and Proxies
Getting started
Outline
1 Motivation
DRY and modularity
Dealing with cross-cutting concerns
2 Aspecio
Overview
Using Aspecio
Interceptors, Advices and Proxies
Getting started
3 Summary
11 / 35 Simon Chemouil Aspecio
17. Motivation
Aspecio
Summary
Overview
Using Aspecio
Interceptors, Advices and Proxies
Getting started
Aspecio
Aspects at injection-time!
No modification of existing bytecode: dynamic proxy injection
instead
Built with OSGi in mind
Component-framework agnostic ; also works with plain APIs
Minimal proxy overhead
No primitive boxing, pay for what you use
12 / 35 Simon Chemouil Aspecio
18. Motivation
Aspecio
Summary
Overview
Using Aspecio
Interceptors, Advices and Proxies
Getting started
Aspecio
Aspects at injection-time!
No modification of existing bytecode: dynamic proxy injection
instead
Built with OSGi in mind
Component-framework agnostic ; also works with plain APIs
Minimal proxy overhead
No primitive boxing, pay for what you use
12 / 35 Simon Chemouil Aspecio
19. Motivation
Aspecio
Summary
Overview
Using Aspecio
Interceptors, Advices and Proxies
Getting started
Aspecio
Aspects at injection-time!
No modification of existing bytecode: dynamic proxy injection
instead
Built with OSGi in mind
Component-framework agnostic ; also works with plain APIs
Minimal proxy overhead
No primitive boxing, pay for what you use
12 / 35 Simon Chemouil Aspecio
21. Motivation
Aspecio
Summary
Overview
Using Aspecio
Interceptors, Advices and Proxies
Getting started
Framework Hooks
Since OSGi r5 (updated in r6)
Weaving Hooks
Ability to alter the bytecode of a class when it is first loaded.
Useful for “traditional” aspect frameworks, or bytecode
manipulation frameworks in general.
Service Hooks
Intercept queries to BundleContext#getService, service events,
service listeners registration
14 / 35 Simon Chemouil Aspecio
22. Motivation
Aspecio
Summary
Overview
Using Aspecio
Interceptors, Advices and Proxies
Getting started
Framework Hooks
Since OSGi r5 (updated in r6)
Weaving Hooks
Ability to alter the bytecode of a class when it is first loaded.
Useful for “traditional” aspect frameworks, or bytecode
manipulation frameworks in general.
Service Hooks
Intercept queries to BundleContext#getService, service events,
service listeners registration
14 / 35 Simon Chemouil Aspecio
23. Motivation
Aspecio
Summary
Overview
Using Aspecio
Interceptors, Advices and Proxies
Getting started
Framework Hooks
Since OSGi r5 (updated in r6)
Weaving Hooks
Ability to alter the bytecode of a class when it is first loaded.
Useful for “traditional” aspect frameworks, or bytecode
manipulation frameworks in general.
Service Hooks
Intercept queries to BundleContext#getService, service events,
service listeners registration
14 / 35 Simon Chemouil Aspecio
24. Motivation
Aspecio
Summary
Overview
Using Aspecio
Interceptors, Advices and Proxies
Getting started
Outline
1 Motivation
DRY and modularity
Dealing with cross-cutting concerns
2 Aspecio
Overview
Using Aspecio
Interceptors, Advices and Proxies
Getting started
3 Summary
15 / 35 Simon Chemouil Aspecio
25. Motivation
Aspecio
Summary
Overview
Using Aspecio
Interceptors, Advices and Proxies
Getting started
Applying Aspects
In Aspecio, service implementations decide if they want
aspects
Two service properties:
service.aspect.weave: “I can only be consumed as a
service if that aspect is woven”
service.aspect.weave.optional: “I can be consumed
anyhow, but if that aspect is available, use it”
Aspects are similar to service interfaces, they represent a
concept, not necessarily a specific implementation
They are implemented with interceptors that are OSGi services
and may come and go
16 / 35 Simon Chemouil Aspecio
26. Motivation
Aspecio
Summary
Overview
Using Aspecio
Interceptors, Advices and Proxies
Getting started
Applying Aspects
In Aspecio, service implementations decide if they want
aspects
Two service properties:
service.aspect.weave: “I can only be consumed as a
service if that aspect is woven”
service.aspect.weave.optional: “I can be consumed
anyhow, but if that aspect is available, use it”
Aspects are similar to service interfaces, they represent a
concept, not necessarily a specific implementation
They are implemented with interceptors that are OSGi services
and may come and go
16 / 35 Simon Chemouil Aspecio
27. Motivation
Aspecio
Summary
Overview
Using Aspecio
Interceptors, Advices and Proxies
Getting started
Applying Aspects
Example
package com.mylibrary.book;
@Component(properties = { "service.aspect.weave=com.mylibrary.auth.AuthAspect",
"service.aspect.weave=com.metrics. MetricsAspect " })
public final class BookManagerImpl implements BookManager {
@ EnsureAuthorized
@Measured
public Promise <Book > getBook(String isbn) {
/* business code here */
return actuallyGetBookNow (isbn );
}
}
17 / 35 Simon Chemouil Aspecio
28. Motivation
Aspecio
Summary
Overview
Using Aspecio
Interceptors, Advices and Proxies
Getting started
Applying Aspects
Example
package com.mylibrary.book;
@Component
@Weave(required = { AuthAspect.class , MetricAspect .class })
public final class BookManagerImpl implements BookManager {
@ EnsureAuthorized
@Measured
public Promise <Book > getBook(String isbn) {
/* business code here */
return actuallyGetBookNow (isbn );
}
}
18 / 35 Simon Chemouil Aspecio
29. Motivation
Aspecio
Summary
Overview
Using Aspecio
Interceptors, Advices and Proxies
Getting started
Applying Aspects
Example
package com.mylibrary.book;
@Component
@Weave(required = AuthAspect.class , optional = MetricAspect .class)
public final class BookManagerImpl implements BookManager {
@ EnsureAuthorized
@Measured
public Promise <Book > getBook(String isbn) {
/* business code here */
return actuallyGetBookNow (isbn );
}
}
19 / 35 Simon Chemouil Aspecio
30. Motivation
Aspecio
Summary
Overview
Using Aspecio
Interceptors, Advices and Proxies
Getting started
Defining Aspects
Aspects can have any name, but we use classes by convention
to avoid conflicts.
To publish an Aspect, we register an OSGi service
implementing Interceptor (or one of its derivatives)
With the String property service.aspect containing the
name of the Aspect
Optionally, it is possible to define the property
service.aspect.extraProperties
20 / 35 Simon Chemouil Aspecio
31. Motivation
Aspecio
Summary
Overview
Using Aspecio
Interceptors, Advices and Proxies
Getting started
Defining Aspects
Aspects can have any name, but we use classes by convention
to avoid conflicts.
To publish an Aspect, we register an OSGi service
implementing Interceptor (or one of its derivatives)
With the String property service.aspect containing the
name of the Aspect
Optionally, it is possible to define the property
service.aspect.extraProperties
20 / 35 Simon Chemouil Aspecio
33. Motivation
Aspecio
Summary
Overview
Using Aspecio
Interceptors, Advices and Proxies
Getting started
Defining Aspects
Example
package com.metrics;
@Component
@Aspect(provides = MetricAspect .class , extraProperties = "measured ")
public final class AnnotatedMetricInterceptorImpl
implements AnnotationInterceptor <Measured > {
@Reference Metrics metrics;
public Class <Measured > intercept () { return Measured.class; }
public Advice onCall(Measured annotation , CallContext callContext) {
String methodName = callContext .target.getName () +
"::" + callContext .method.getName ();
Context syncTimer = metrics.timer(methodName ). time ();
return new AdviceAdapter () {
public int afterPhases () { return Finally.PHASE; }
public void runFinally () { syncTimer.close (); }
};
}
}
22 / 35 Simon Chemouil Aspecio
34. Motivation
Aspecio
Summary
Overview
Using Aspecio
Interceptors, Advices and Proxies
Getting started
Outline
1 Motivation
DRY and modularity
Dealing with cross-cutting concerns
2 Aspecio
Overview
Using Aspecio
Interceptors, Advices and Proxies
Getting started
3 Summary
23 / 35 Simon Chemouil Aspecio
35. Motivation
Aspecio
Summary
Overview
Using Aspecio
Interceptors, Advices and Proxies
Getting started
A Closer Look At Interceptors
In Aspecio, services providing aspects are called Interceptors
Interceptors always intercept all service methods
We can narrow it down by matching some annotations
If multiple interceptors provide the same aspect, Aspecio
chooses the one with the highest service ranking
If the rankings are equal, the one with the lowest service id is
selected
24 / 35 Simon Chemouil Aspecio
36. Motivation
Aspecio
Summary
Overview
Using Aspecio
Interceptors, Advices and Proxies
Getting started
A Closer Look At Interceptors
In Aspecio, services providing aspects are called Interceptors
Interceptors always intercept all service methods
We can narrow it down by matching some annotations
If multiple interceptors provide the same aspect, Aspecio
chooses the one with the highest service ranking
If the rankings are equal, the one with the lowest service id is
selected
24 / 35 Simon Chemouil Aspecio
37. Motivation
Aspecio
Summary
Overview
Using Aspecio
Interceptors, Advices and Proxies
Getting started
Advices
Each time a method of the aspect proxy is called, the methods
onCall of the active interceptors are called
The method onCall returns an Advice
Advices tell Aspecio what to do when a proxy method is called
25 / 35 Simon Chemouil Aspecio
38. Motivation
Aspecio
Summary
Overview
Using Aspecio
Interceptors, Advices and Proxies
Getting started
Advices
Each time a method of the aspect proxy is called, the methods
onCall of the active interceptors are called
The method onCall returns an Advice
Advices tell Aspecio what to do when a proxy method is called
25 / 35 Simon Chemouil Aspecio
39. Motivation
Aspecio
Summary
Overview
Using Aspecio
Interceptors, Advices and Proxies
Getting started
Advices
Optionally request the actual arguments passed to the method,
and alter them;
Skip the call to the original method and return a value... or
proceed with the call;
Obtain throwables potentially thrown by the proxied method
and optionally alter them, but not swallow them;
Obtain and alter the return value
All of these for reference types and all primitive types to
prevent boxing!
26 / 35 Simon Chemouil Aspecio
40. Motivation
Aspecio
Summary
Overview
Using Aspecio
Interceptors, Advices and Proxies
Getting started
Advices
Optionally request the actual arguments passed to the method,
and alter them;
Skip the call to the original method and return a value... or
proceed with the call;
Obtain throwables potentially thrown by the proxied method
and optionally alter them, but not swallow them;
Obtain and alter the return value
All of these for reference types and all primitive types to
prevent boxing!
26 / 35 Simon Chemouil Aspecio
41. Motivation
Aspecio
Summary
Overview
Using Aspecio
Interceptors, Advices and Proxies
Getting started
Advices
Optionally request the actual arguments passed to the method,
and alter them;
Skip the call to the original method and return a value... or
proceed with the call;
Obtain throwables potentially thrown by the proxied method
and optionally alter them, but not swallow them;
Obtain and alter the return value
All of these for reference types and all primitive types to
prevent boxing!
26 / 35 Simon Chemouil Aspecio
42. Motivation
Aspecio
Summary
Overview
Using Aspecio
Interceptors, Advices and Proxies
Getting started
Advices
Optionally request the actual arguments passed to the method,
and alter them;
Skip the call to the original method and return a value... or
proceed with the call;
Obtain throwables potentially thrown by the proxied method
and optionally alter them, but not swallow them;
Obtain and alter the return value
All of these for reference types and all primitive types to
prevent boxing!
26 / 35 Simon Chemouil Aspecio
43. Motivation
Aspecio
Summary
Overview
Using Aspecio
Interceptors, Advices and Proxies
Getting started
Advices
Optionally request the actual arguments passed to the method,
and alter them;
Skip the call to the original method and return a value... or
proceed with the call;
Obtain throwables potentially thrown by the proxied method
and optionally alter them, but not swallow them;
Obtain and alter the return value
All of these for reference types and all primitive types to
prevent boxing!
26 / 35 Simon Chemouil Aspecio
45. Motivation
Aspecio
Summary
Overview
Using Aspecio
Interceptors, Advices and Proxies
Getting started
Aspecio’s Dynamic Proxies
Aspecio generates proxies with the ASM bytecode generation
library
Proxies might generate several classes lazily
e.g if arguments are requested, an immutable data class in
generated for these unboxed arguments, with proper hashCode
and equals definitions.
Proxies generated by Aspecio expose the same binary signature
as the class they proxy
Including generic signature, annotations, etc, so that framework
relying on introspection work transparently
28 / 35 Simon Chemouil Aspecio
46. Motivation
Aspecio
Summary
Overview
Using Aspecio
Interceptors, Advices and Proxies
Getting started
Aspecio’s Dynamic Proxies
Aspecio generates proxies with the ASM bytecode generation
library
Proxies might generate several classes lazily
e.g if arguments are requested, an immutable data class in
generated for these unboxed arguments, with proper hashCode
and equals definitions.
Proxies generated by Aspecio expose the same binary signature
as the class they proxy
Including generic signature, annotations, etc, so that framework
relying on introspection work transparently
28 / 35 Simon Chemouil Aspecio
47. Motivation
Aspecio
Summary
Overview
Using Aspecio
Interceptors, Advices and Proxies
Getting started
Proxies and Services
Aspecio can proxy services implementing multiple service
interfaces just fine
However Aspecio will ignore services registered as a class or an
abstract class
Service proxies registered by Aspecio share the same properties
as the woven service
Aspecio handles different service scopes intelligently (including
prototype)
It will not generate different proxies for a singleton service
scoped as bundle for lazy-loading reasons (e.g, by Declarative
Services)
29 / 35 Simon Chemouil Aspecio
48. Motivation
Aspecio
Summary
Overview
Using Aspecio
Interceptors, Advices and Proxies
Getting started
Proxies and Services
Aspecio can proxy services implementing multiple service
interfaces just fine
However Aspecio will ignore services registered as a class or an
abstract class
Service proxies registered by Aspecio share the same properties
as the woven service
Aspecio handles different service scopes intelligently (including
prototype)
It will not generate different proxies for a singleton service
scoped as bundle for lazy-loading reasons (e.g, by Declarative
Services)
29 / 35 Simon Chemouil Aspecio
49. Motivation
Aspecio
Summary
Overview
Using Aspecio
Interceptors, Advices and Proxies
Getting started
Proxies and Services
Aspecio can proxy services implementing multiple service
interfaces just fine
However Aspecio will ignore services registered as a class or an
abstract class
Service proxies registered by Aspecio share the same properties
as the woven service
Aspecio handles different service scopes intelligently (including
prototype)
It will not generate different proxies for a singleton service
scoped as bundle for lazy-loading reasons (e.g, by Declarative
Services)
29 / 35 Simon Chemouil Aspecio
50. Motivation
Aspecio
Summary
Overview
Using Aspecio
Interceptors, Advices and Proxies
Getting started
Outline
1 Motivation
DRY and modularity
Dealing with cross-cutting concerns
2 Aspecio
Overview
Using Aspecio
Interceptors, Advices and Proxies
Getting started
3 Summary
30 / 35 Simon Chemouil Aspecio
51. Motivation
Aspecio
Summary
Overview
Using Aspecio
Interceptors, Advices and Proxies
Getting started
Getting started
Aspecio is just one bundle
depends only ony an OSGi R6+ framework
slf4j is an optional dependency; otherwise JUL logging is used
It has to be started early in the framework, before any bundle
that uses it
No way to “fake” service events to “unwire” components;
Same situation for all frameworks making use of framework
hooks, e.g subsystems
31 / 35 Simon Chemouil Aspecio
52. Motivation
Aspecio
Summary
Overview
Using Aspecio
Interceptors, Advices and Proxies
Getting started
Getting started
Aspecio is just one bundle
depends only ony an OSGi R6+ framework
slf4j is an optional dependency; otherwise JUL logging is used
It has to be started early in the framework, before any bundle
that uses it
No way to “fake” service events to “unwire” components;
Same situation for all frameworks making use of framework
hooks, e.g subsystems
31 / 35 Simon Chemouil Aspecio
53. Motivation
Aspecio
Summary
Overview
Using Aspecio
Interceptors, Advices and Proxies
Getting started
Checking if Aspecio sees your aspects
Aspecio provides two Gogo commands
aspect:aspects
aspects and interceptors available
aspect:woven
services currently woven, with which aspect
32 / 35 Simon Chemouil Aspecio
54. Motivation
Aspecio
Summary
Aspecio Tech Sheet
A bit of a component framework
Plays with service dynamics and registers some on behalf of
other bundles
A lot of bytecode trickery
Mimicking the signature of classes and methods it proxies
Supporting all primitive types for call performance
And a Java DSL to define advices
Advices are close to automata that determine how the
generated code will interact with user code
33 / 35 Simon Chemouil Aspecio
55. Motivation
Aspecio
Summary
Aspecio Tech Sheet
A bit of a component framework
Plays with service dynamics and registers some on behalf of
other bundles
A lot of bytecode trickery
Mimicking the signature of classes and methods it proxies
Supporting all primitive types for call performance
And a Java DSL to define advices
Advices are close to automata that determine how the
generated code will interact with user code
33 / 35 Simon Chemouil Aspecio
56. Motivation
Aspecio
Summary
Aspecio Tech Sheet
A bit of a component framework
Plays with service dynamics and registers some on behalf of
other bundles
A lot of bytecode trickery
Mimicking the signature of classes and methods it proxies
Supporting all primitive types for call performance
And a Java DSL to define advices
Advices are close to automata that determine how the
generated code will interact with user code
33 / 35 Simon Chemouil Aspecio
57. Motivation
Aspecio
Summary
In-house Feedback
Used on a large project (hundreds of bundles, thousands of
services)
Easy to get started
Some aspects are extremely useful
Metrics, Access Control, Exception Logging, ...
Practical with integration testing (with and without Aspecio)
Potential improvements:
Better stacking of advices, asynchronous support, “this”
handling
34 / 35 Simon Chemouil Aspecio
58. Motivation
Aspecio
Summary
In-house Feedback
Used on a large project (hundreds of bundles, thousands of
services)
Easy to get started
Some aspects are extremely useful
Metrics, Access Control, Exception Logging, ...
Practical with integration testing (with and without Aspecio)
Potential improvements:
Better stacking of advices, asynchronous support, “this”
handling
34 / 35 Simon Chemouil Aspecio
59. Motivation
Aspecio
Summary
In-house Feedback
Used on a large project (hundreds of bundles, thousands of
services)
Easy to get started
Some aspects are extremely useful
Metrics, Access Control, Exception Logging, ...
Practical with integration testing (with and without Aspecio)
Potential improvements:
Better stacking of advices, asynchronous support, “this”
handling
34 / 35 Simon Chemouil Aspecio