0% found this document useful (0 votes)
25 views35 pages

Sa 03 1 Architecturalpatterns Modules

Uploaded by

Manu Vleurick
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
25 views35 pages

Sa 03 1 Architecturalpatterns Modules

Uploaded by

Manu Vleurick
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 35

3.

Architectural patterns
Learning objectives
review the Layer, Onion, and the Aspect-Oriented pattern as examples of the most common
architectural patterns in the Module category
discuss the motivations for their use, the elements and constraints they consist of, and their
weaknesses and strengths
compare the so-called Cake pattern with injection frameworks for realising dependency
inversion

2
What is an architectural pattern?
Proceedings of the 21st International Computer Software and Applications Conference, 1997, pp. 6-13.

School of architectural styles


An architectural pattern establishes a relation between:
A Field Guide to Boxology:
Preliminary Classification of Architectural Styles for
A context
Software Systems
Recurring real-world situation that gives rise to a
Mary Shaw and Paul Clements

Computer Science Department and Software Engineering Institute


Carnegie Mellon University
Pittsburgh, PA 15213
problem.
April 1996

Abstract: Software architects use a number of commonly-recognized “styles”


to guide their design of system structures. Each of these is appropriate for
some classes of problems, but none is suitable for all problems. How, then,
does a software designer choose an architecture suitable for the problem at
hand? Two kinds of information are required: (1) careful discrimination among
but when to use A problem
the candidate architectures and (2) design guidance on how to make
appropriate choices. Here we support careful discrimination with a
preliminary classification of styles. We use a two-dimensional classification
strategy with control and data issues as the dominant organizing axes. We
which style? The problem, appropriately generalized, that arises in
position the major styles within this space and use finer-grained
discriminations to elaborate variations on the styles. This provides a
framework for organizing design guidance, which we partially flesh out with
rules of thumb.

School of architectural patterns the given context.

focus
Keywords: software architecture, architectural styles, style classification/taxonomy

software patterns A solution


A successful architectural resolution to the problem,
Thi d d ihF M k 404

Using Patterns to Capture


Architectural Decisions
appropriately abstracted. The solution for a pattern is
capture the
Neil B. Harrison, Utah Valley State College
Paris Avgeriou, University of Groningen architect’s rationale! determined and described by:
Uwe Zdun, Vienna University of Technology

A set of element types


T
hroughout the software design process, developers must make de-
By providing
information about
a decision’s
rationale and
cisions and reify them in code. The decisions made during software
architecting are particularly significant in that they have system-
wide implications, especially on the quality attributes. However,
architects often fail to adequately document their decisions because they don’t
(e.g., data repositories, processes, and objects)
consequences,
architecture
patterns can help
architects better
appreciate the benefits, don’t know how to document decisions, or don’t rec-
ognize that they’re making decisions. This lack of thorough documentation
can significantly disrupt the system when deci-
sions made later, during subsequent develop-
discuss the relation between patterns and deci-
sion making and describe how architects can
A set of interaction mechanisms or connectors
understand
and more easily
record their
decisions.
ment iterations, conflict with the original archi-
tectural decisions.
Researchers are investigating various meth-
ods and tools to help software architects effec-
tively document their decisions. However, such
use patterns to capture certain architectural de-
cisions in practice.

Problem overview
Most software architecture documentation
(e.g., method calls, events, or message bus)
A topological layout of the components
tools’ utility has yet to be fully validated. Doc- describes the system’s structure from different
umenting architectural decisions thus remains views.1 Ideally, this documentation also records
difficult and we continue to lose important decisions that architects made while designing
information. the system. Recording only the decision does lit-
Architecture patterns address these docu- tle good, however; for the documentation to be
mentation challenges by capturing structural truly useful, architects must also capture the al-
and behavioral information and encouraging
architects to reflect on decisions in a way that
doesn’t interfere with the natural architectural
design process. Architecture patterns are easy
to use, giving developers a rich set of infor-
ternatives considered, their expected conse-
quences, and the rationale—that is, the reasons
for selecting a particular alternative. Our discus-
sion of decision documentation here refers not
just to the decision but rather to all of its as-
A set of semantic constraints covering topology,
element behavior, and interaction mechanisms
mation about rationale, consequences, and re- pects. Unfortunately, when architects document
lated decisions. Essentially, they offer reusable their decisions, this wider definition is what they
knowledge for the architect’s toolkit. Here, we most neglect.

38 IEEE SOFTWARE Published by the IEEE Computer Society 0740-7459/07/$25.00 © 2007 IEEE

3
3.1 Module Patterns

4
Layer Pattern
Figure 2.17
There may be three layers
here, but this is not a design A
in the layered style, which
forbids upward uses.

B
Key
x Layer

C Allowed to use

Context
Need to develop and evolve portions of complex software systems independently.
Problem
The software needs to be segmented in such a way that the modules can be developed
and evolved separately with little interaction among the parts,
supporting portability, modifiability, and reuse.
Solution
To achieve this separation of concerns, the layered pattern divides the software into units
called layers. Each layer is a grouping of modules that offers a cohesive set of services.
The usage (e.g., import type, invoke method) must be unidirectional. Layers completely
partition a set of software, and each partition is exposed through a public interface.
5
Layer Pattern Solution
Overview
The layered pattern defines layers (groupings of modules that offer a cohesive set of
services) and a unidirectional allowed-to-use relation among the layers.
Elements
Layer, a kind of module.
The description of a layer should define what modules the layer contains.
Relations
Allowed-to-use. The design should define what the layer usage rules are and any
allowable exceptions.
Constraints
Every piece of software is allocated to exactly one layer.
Layer n provides a set of services to layer n+1 and uses the services of layer n-1.
“Layer bridging” is sometimes allowed downwards, but should be avoided.
There is a clearly-defined and stable interface between adjacent layers,
of which only the implementation can change.
Strengths
Promotes modifiability, reuse, portability.
Achieves separation of concerns.
Manages complexity and facilitates communication of code structure to developers.
Weaknesses
The addition of layers adds up-front cost and complexity to a system.
Layers contribute a performance penalty. 6
kernel through system calls. The system call interface layer iso-
lates the kernel implementation details and provides a virtual
Layer Pattern Examples
Figure 2.26

user space
User programs
Unix System V
The primary presentation of
a layered view of the UNIX
System V operating system
implementation (adapted
from Bach 1986)
Libraries

system call interface

kernel space
file subsystem process control subsystem
(ipc, scheduler, memory mgmt)

buffering
mechanism
“The diagram serves as a useful
logical view of the kernel,
character block I/O although in practice the kernel
device drivers device drivers deviates from the model because
some modules interact with the
internal operations of others.”
hardware control
[Bach 1986]

Key
User-level Kernel-level Allowed
layer layer to use

7
using

com.foo.proj.ui.dto
com.foo.proj.ui.act
com.foo.proj.ui.svl
Layer Pattern Examples

com.foo.proj.ui.ctl

com.foo.proj.pojo
com.foo.proj.dao
module

com.foo.proj.svc

com.foo.proj.dto
used
module

com.foo.proj.ui.svl 0 0 0 0 0 0 0 0
com.foo.proj.ui.act 0 0 0 0 0 0 0 0
com.foo.proj.ui.ctl 1 1 0 0 0 0 0 0
com.foo.proj.ui.dto 1 1 1 0 0 0 0 0
J2EE web applications com.foo.proj.svc 0 0 1 0 0 0 0 0
com.foo.proj.dao 0 0 0 0 1
0 0 0 0
2.4 Layered S
com.foo.proj.dto 1 1 1 0 1 1 0 0
data transfer objects: com.foo.proj.pojo 1 1 1 0 1 1 0 0
simple classes grouping data Figure 2.32
DSM for a layered design. The highlighted cells above and below the diagonal represent de
not allowed

Servlets and com.foo. com.foo.

Presentation
—J.S. and P.M.
action classes proj.ui.svl proj.ui.act

Corporate DTOs and POJOs


proj.ui.dto
com.foo.
DTOs
Controller classes com.foo.

proj.pojo
com.foo.
proj.ui.ctl

e.g., CtlRetrievePaymentToDay
implements steps required for one use case Service classes com.foo.
proj.svc

com.foo.
proj.dto
e.g, SvcFulltimeEmployee
implements core business logic DAO classes com.foo.
associated with domain classes proj.dao

data access objects: Key


implement interaction with database
Java
package

Layer

Allowed to use
8
Dependency Inversion: from Layer to Onion

API traditional procedural interpretation:


call into a lower layer using the interface declared there
uses dependency direction is downwards
from high-level layers at the top
Domain to low-level layers at the bottom
high-level layers (e.g., for business logic)
uses depend on low-level utilitarian layers (e.g., for persistence)
changes to the lower-level layers
Infrastructure require running integration tests again

API Layer: public interface to the domain


Domain Layer: domain model implementation
Infrastructure Layer: frameworks, integration with other services, …

9
Dependency Inversion: from Layer to Onion

OO implementation with dependency inversion:


high-level layer declares interface
implemented by low-level layer Infrastructure
coupling direction is inwards:
from outer low-level layer (e.g., for persistence) API
to inner high-level layer (e.g., for business logic)

Messagin
Presentation
outer layers depend on inner layers,
as they implement the interfaces declared there Domain

g
changes to outer layers do not affect inner layers, Model
the inner layers do not know about the outer layers
inner layers can be compiled, run, and tested

s t
Tes
separately from the infrastructure layers

RE
ST
(e.g., swap an outer layer for a mock
Persistence
when testing an inner layer)

10
Onion in Scala: Cook example

API
[Waldron, ScalaDays 2016]

Code from https://github.com/WadeWaldron/scaladays2016/

11
API ring for Cook example: module declaration

self type expresses the dependency


of ApiModule on DomainModule,
which will provide cookRepository

denotes the thread pool all


trait ApiModule: concurrency-related Scala features will use in this scope
this: DomainModule =>
given threadPool: ExecutionContext
val foodPrepApi: FoodPrepApi = new FoodPrepApi(cookRepository)

outer ring depends on inner ring


inner ring decoupled from outer ring

trait DomainModule:
val cookRepository: CookRepository
val eggRepository: EggRepository

12
13

API ring for Cook example: module contents

If less control is desired (i.e., not provided by ApiModule),


the global pre-defined thread pool can be imported through
import ExecutionContext.Implicits.global
in the current scope (files, class, …)
an additional, but implicit class
parameter for which the compiler will find
an argument if we don’t provide one

class FoodPrepApi(cookRepository: CookRepository)(using ExecutionContext):


def prepareEgg(style: EggStyle): Future[CookedEgg] =
for
returns a Future,
cook <- cookRepository.findOne() encapsulating both
egg <- cook.prepareEgg(style) time and failure
yield egg
asynchronous methods,
each returning a future
be returned. This leads to much more efficient usage in terms of
cost, energy, and performance of the underlying resources, as
API ring for Cook example: benefits of asynchrony in interface
Figure 5-3 depicts.

motivation for non-


blocking I/O libraries such
as Java NIO, Netty, …

"Reactive Microsystems” [Bonér, 2017]


14
API ring for Cook example: module contents revisited
less optimal alternatives to using for-comprehension for chaining dependent futures

using a nesting of callbacks

also known as
callback hell

using collection API


def prepareEgg2(style: EggStyle): Future[CookedEgg] =
val cookFuture = cookRepository.findOne()
// using flatMap instead of map to avoid returning a future of a future
cookFuture.flatMap(c => c.prepareEgg(style))

pretend futures are eventually empty (on failure)


or singleton collections (on success)
15
Domain ring for Cook example: module declaration

does not depend on


any other rings

trait DomainModule:
val cookRepository: CookRepository
val eggRepository: EggRepository

16
Domain ring for Cook example: module contents

defines an interface, which can be implemented by outer, more low-


level, rings (i.e., the infrastructure ring) that depend on this one

trait CookRepository:
def findOne(): Future[Cook]

we might run
out of eggs
trait EggRepository:
def findAndRemove(): Future[Option[RawEgg]]
def add(egg: RawEgg): Future[Unit]

17
18

Domain ring for Cook example: module contents


sealed types can only be
extended in the same file
Note how the egg’s interface evolves
over time. This is only possible
sealed trait Egg because we are not using reference
companion object equality for comparing eggs!
object Egg: grouping inner types

sealed trait CookedEgg(val style: EggStyle) extends Egg

case class RawEgg() extends Egg:


def startCooking(style: EggStyle): PartiallyCookedEgg =
PartiallyCookedEgg(style) starting to cook a RawEgg results
in a new PartiallyCookedEgg
(remember that the new keyword
case class PartiallyCookedEgg(s: EggStyle) is not required when instantiating
extends CookedEgg(s): case classes)

private val startTime: Timestamp = Timestamp()

def isDone(): Boolean =


(System.currentTimeMillis() - startTime.value)
> s.cookTime.toMillis cooking of a PariallyCookedEgg
results in a FullyCookedEgg
(after sufficient time has elapsed)
def finishCooking(): CookedEgg =
if isDone() then FullyCookedEgg(s) else this

case class FullyCookedEgg(s: EggStyle) extends CookedEgg(s)


19

Domain ring for Cook example: module contents


sealed trait EggStyle(val cookTime: FiniteDuration)

object EggStyle:
case object Scrambled extends EggStyle(3.minutes)
case object SunnySideUp extends EggStyle(3.minutes)
case object OverEasy extends EggStyle(4.minutes)
case object OverMedium extends EggStyle(5.minutes)
case object OverHard extends EggStyle(6.minutes)
case object HardBoiled extends EggStyle(6.minutes)
case object SoftBoiled extends EggStyle(3.minutes)
case object Poached extends EggStyle(5.minutes)

trait FryingPan eggs can be added to


empty frying pans
case class EmptyFryingPan() extends FryingPan:
def add(egg: RawEgg, style: EggStyle): FullFryingPan =
FullFryingPan(egg.startCooking(style)) but no longer
to full ones
case class FullFryingPan(egg: PartiallyCookedEgg) extends FryingPan:
def checkDoneness(): Boolean =
egg.isDone()
def remove(): (EmptyFryingPan, CookedEgg) = returns a pair of the
cooked egg and the new
(EmptyFryingPan(), egg.finishCooking()) state for the frying pan
20

Domain ring for Cook example: module contents

object Cook:
case object OutOfEggsException
extends IllegalStateException("There are no more eggs")

class Cook(val id: CookId)(eggRepository: EggRepository)


(using ExecutionContext):
import Cook._ // to get OutOfEggsException here
private val fryingPan = new EmptyFryingPan()

private def wait(pan: FullFryingPan) =


while !pan.checkDoneness() do Thread.sleep(10)

def prepareEgg(style: EggStyle): Future[CookedEgg] =


val eggFuture = eggRepository.findAndRemove() call-by-name
eggFuture.map(eggOption =>
val egg = eggOption.getOrElse(throw OutOfEggsException)
val fullFryingPan = fryingPan.add(egg, style)
wait(fullFryingPan)
fullFryingPan.remove()._2 avoids having to allocate run-time objects for
) these simple wrappers of Integers

case class CookId(value: Integer) extends AnyVal


21

Infrastructure ring for Cook example: module declaration

dependencies of the outer, more low-level,


InfrastructureModule on inner, more high-level, modules

trait InfrastructureModule:
this: ApiModule with DomainModule =>

val eggRepository: EggRepository = new InMemoryEggRepository()

val cookRepository: CookRepository =


new InMemoryCookRepository(eggRepository) dummy in-memory implementations provided
by the Infrastructure ring for the repository
interfaces declared in the Domain ring
22

Infrastructure ring for Cook example: module contents

class InMemoryCookRepository(eggRepository: EggRepository


(using ec: ExecutionContext)
extends CookRepository:
def findOne(): Future[Cook] =
Future.successful(new Cook(CookId(Random.nextInt()))(eggRepository))
creates an
already-resolved
future

class InMemoryEggRepository(using ec: ExecutionContext)


extends EggRepository:
private val eggs = mutable.Queue[RawEgg]()

def findAndRemove(): Future[Option[RawEgg]] = Future {


eggs.synchronized {
Try(eggs.dequeue()).toOption idiomatic way of converting
} potential exceptions to options
}

def add(egg: RawEgg): Future[Unit] = Future {


eggs.synchronized {
eggs.enqueue(egg)
}
}
Composing the Cook example from its modules
class Injector
extends DomainModule
with ApiModule
with InfrastructureModule:

val threadPool: ExecutionContext =


scala.concurrent.ExecutionContext.global

module configuration to be used in production


alternative module configuration to be used for testing

trait TestModule
extends DomainModule
with InfrastructureModule
with ApiModule:

val threadPool: ExecutionContext =


23
high-level layer declares interface
implemented by low-level layer Infrastructure
coupling direction is inwards from outer low-

Alternatives for realising dependency inversion level layer (e.g., for persistence) to inner high-
level layer (e.g., for business logic)
API

Messagin
Presentation
outer layers depend on inner layers, as they
implement the interfaces declared there Domain

g
changes to outer layers do not affect inner Model
layers, the inner layers do not know about the
outer layers

s t
Tes
inner layers can be compiled, run, and tested

RE
ST
separately from the infrastructure layers (e.g.,
Persistence
swap an outer layer for a mock when testing
an inner layer)
Cook example implements the so-called “Cake pattern” for dependency inversion
9

Strengths
Realised solely through built-in language constructs such as self types
Module composition is checked for type-safety at compile-time
Weaknesses
[Oderski, OOPSLA05] Has earned the reputation of being difficult to understand
Easy to make mistakes in the implementation of the pattern

real-world trend is to use “dependency injection frameworks” instead


use run-time reflection to inject automatically-created instances of
dependencies in constructor parameters marked with e.g., @Inject annotations

Google Guice, Strengths


Spring DI, Some frameworks support run-time reconfigurations

Weaknesses
Frameworks represent an external project dependency
Often rely on external configuration files e.g., XML
24
Aspect-Oriented Pattern

“Let me try to explain to you, what to my taste is


characteristic for all intelligent thinking. It is, that one
is willing to study in depth an aspect of one’s subject
matter in isolation for the sake of its own consistency,
all the time knowing that one is occupying oneself only
with one of the aspects.

We know that a program must be correct and we can


study it from that viewpoint only; we also know that
it should be efficient and we can study its efficiency
on another day […] But nothing is gained –on the
contrary– by tackling these various aspects
simultaneously. It is what I sometimes have called
“the separation of concerns”
[E. W. Dijkstra]

25
Separation of Concerns in Apache Tomcat
XML Parsing: one module (i.e., class)

URL Handling: two related modules


(i.e., two classes related by inheritance)

Logging: not separated from other concerns!

26
Figure 2.36.

Crosscutting Concerns
code scattering

code
tangling

...
Account Customer Atm

Key
Code to handle access control
Class
Code to handle logging
code
Code to handle transaction management

Figure 2.36
Inappropriately modularising a crosscutting concerns leads to
The traditional object-oriented implementation of a bank automation system would have several classes where
Scattering:
the business logic itswith
is tangled implementation being
code that handles dispersed
crosscutting all oversuch
concerns, theasplace
access control, logging, and
transaction management.
Tangling: itsIn implementation
addition, the code being
that handles a particular
intertwined withcrosscutting concern is repeated
the implementation and
of others
scattered across several classes.
Problems related to comprehension and maintainability
27
Modularizing Cross-cutting Concerns 2.6 Data Model ■ 109

Classes with
business logic
code

. . .

Account Customer Atm

Aspects that
modularize code
of crosscutting
concerns

access logging transaction


control aspect management
aspect aspect

Figure 2.37
Aspect-oriented programming provides programming constructs for factoring out cross-
In the aspect-oriented implementation of the same bank automation system, the classes don’t contain code for
logging, access control, transaction management, and other crosscutting concerns. The code to handle these
cutting concerns from modules into a separate module called an aspect that consists of:
concerns is now inside aspect modules. Classes such as Account, Customer and Atm contain the business logic
only. The AOP compiler will use the weaving process to insert the code inside aspects at the locations in the
classes where it’s needed.
Advice
contains the code for the cross-cutting concern
Pointcut expression
2.6 Data Model
specifies the join points in the base program where base and cross-cutting concerns
should
2.6.1 be composed
Overview
joinmodeling
Data points areis a specific
common to eachin AOP
activity language,
the software according to its join point model:
develop-
ment
e.g., process
method of information
invocation,systems.
method The execution,
output of thisinstance
activ- creation, error throwing, …
ity is the data model, which describes the static information 28
2.5 Aspects Style ■ 107

Aspect-Oriented Architectural Pattern Example


com.ikaru.ikewiki.util
com.ikaru.ikewiki.aspects
IkewikiExceptionHandler
«aspect» «aspect» «use»
TransactionManagement ExceptionHandling handleExceptionInService()
handleExceptionInThread()

checkStatusAndCloseTransaction() ...
Crosscuts:
Crosscuts all public methods of —all public methods of all classes with suffix ServiceImpl
all classes with suffix ServiceImpl —the handleRequest() method of all classes that
AND any method with the implement Spring’s Controller interface
@transactional annotation —the run() method of all threads

«aspect» org.gwtwidgets.server.spring
«aspect» «use»
AuthorizationCheck
Enforcement
... ServletUtils
...
«use»
Compile-time declarations
to identify points in the code com.ikaru.ikewiki.user
that violate the layered Crosscuts any method
Key: UML
design or coding policies with the
Color used to enhance
«entity» @privilegedAccess
readability.
User annotation
... “. . .” indicates there are
other elements in the
package.

Aspect-oriented
Figure 2.35
J2EE application implemented using Spring and Google Web Toolkit.
• TransactionManagement
Primary aspect
presentation for the aspects ensures
view of requests
the IkeWiki received
application. This JavabyEEserver close
application databasewith
implemented
Spring framework and Google Web Toolkit uses aspects for some crosscutting concerns. The TransactionManagement
transactions,
the and
perform
aspect a transaction
makes sure all requestsrollback
received bywhen an exception
the server occurs. and release database resources properly,
will close the transaction
•performing a rollback when
ExceptionHandling an exception
aspect logs, occurs.
displays, The and
ExceptionHandling
notifies theaspect has code to log
administrator the error
of each to the
exception.
database, send e-mail notification if applicable, and wrap the exception with a proper user message to be displayed by
Woven into
threads
the and entryThispoints
client application. aspectto handlers
is woven for HTTPclasses
into server-side requests.
that are either threads or entry points to process
•HTTP requests. The AuthorizationCheck aspect is used to check if the current user has permission to execute a specific
AuthorizationCheck aspect performs access control on specific methods.
method. The Enforcement aspect is different from the others. It doesn’t exactly implement a crosscutting concern, but
• Enforcement
rather it scans the aspect
coding policies.
does
source code NOT implement
at compile time looking fora violations
cross-cutting concern.
of the layered design,Itaslooks
well asfor violations
violations of design
of several
invariants and coding conventions at compile-time. 29
Enterprise AOP with Spring Applications

Canonical aspect: logging


IN ACTION

SAMPLE CHAPTER

Ramnivas Laddad
FOREWORD BY ROD JOHNSON MANNING

vs. AOP tracing 257


[Laddad 2010]

d in
ool- Class_1.java

olkit
mat-
log
ime () Logger

am-
soci-
class
file
Class_n.java
Fig-
ven- ()
lo g

over
add-
eed
stru-
Figure 10.1 Conventional tracing, where all
the conventional logging
log points issue calls to the logger explicitly AOP-based logging

30
Enterprise AOP with Spring Applications

Canonical aspect: logging


IN ACTION

SAMPLE CHAPTER

Ramnivas Laddad
FOREWORD BY ROD JOHNSON MANNING

AspectJ [Laddad 2010]


import org.apache.log4j.*;
import org.aspectj.lang.Signature;
pointcut selecting
public aspect TraceAspect { the methods to be
private Logger logger = Logger.getLogger(TraceAspect.class); traced: every
method in the
system, except for
pointcut traced() those defined in the
: execution(* *.*(..)) && !within(TraceAspect); aspect itself

“before” before() : traced() {


advice will be
executed before Signature sig = thisJoinPointStaticPart.getSignature();
the execution of logger.log(Level.INFO, "Entering [" + sig.toShortString() + "]");
the method that }
is traced
}
signature of the method being traced
obtained by asking for meta-data about the
join point selected by the point cut
AspectJ is an implementation of AOP for Java
weaves the aspect bytecode into the base bytecode at compile-time or load-time
less popular these days
31
Enterprise AOP with Spring Applications

Canonical aspect: logging


IN ACTION
Spring AOP
SAMPLE CHAPTER

@Aspect Ramnivas Laddad


FOREWORD BY ROD JOHNSON MANNING

public class TraceAspect {


private Logger logger = Logger.getLogger(TraceAspect.class); [Laddad 2010]

@Pointcut("execution(* *.*(..))")
public void traced() {
}

@Before("traced()")
public void trace(JoinPoint jp) {
Signature sig = jp.getSignature();
logger.log(Level.INFO, "Entering [" + sig.toShortString() + "]");
NDC.push(" "); pushes indentation on
} the logger’s “nested
diagnostic stack” (Log4J)
@After("traced()")
public void exit() {
NDC.pop();
}
}

Spring AOP is a more limited implementation of AOP for Java


based on auto-generated proxies -> only before/after/around advice on method executions
still used pervasively in applications using the Spring framework
32
AOP the Scala way: Stackable traits
SCALA
&
D E S I G N PAT T E R N S
(EXPLORING LANGUAGE EXPRESSIVITY )

trait Channel {
def send(x : String) = println(x)
} MASTERS THESIS
FREDRIK SKEEL LØKKE 20022555

object LogAspect { ADVISOR: ERIK ERNST 30. MARTS 2009

trait LogBefore extends Channel {


DEPARTMENT OF COMPUTER SCIENCE
UNIVERSITY OF AARHUS

abstract override def send(x : String) = {


println("before!") [Løkke 2002]
super.send(x) possible because super is
} late bound in traits!
built-in feature
}
trait LogAfter extends Channel { but no intensional
abstract override def send(x : String) = { quantification over join
super.send(x) points in pointcut
println("after!") expression
}
} and weaving of aspect
} and base concerns at the
type rather than the
object AspectTest extends App { instance level
val channel = new Channel
with LogAspect.LogAfter with LogAspect.LogBefore mixing composition
channel.send("message")
before!
}
message
after! 33
Aspect-Oriented Pattern
Overview
The aspect-oriented pattern factors out cross-cutting concerns into modules called aspects.
Elements
Aspect, a kind of module that contains the implementation of a cross-cutting concern.
Aspects modify the behaviour of the base code by composing it with advice code at join
points specified by a pointcut expresion.
Relations
Cross-cuts, the relation being an aspect module to a module that will be affected by the
cross-cutting logic of the aspect.
Constraints
An aspect can crosscut one ore more regular modules as well as aspect modules.
An aspect that crosscuts itself may cause infinite recursion, depending on the
implementation.

Strengths
Modularizes cross-cutting concerns.
Supports comprehension and modifiability.
Weaknesses
Little language support.
Prone to the fragility problems: pointcuts and advice make many implicit
assumptions about the modules into which they cross-cut.
34

You might also like