You are on page 1of 8

Aspect library discussion at AOSD 2005 | Main | AspectJ 5 M2

released today

March 22, 2005


Hacking with Harrop...
(Rob Harrop that is, of Spring fame...)
Off the back of the AOSD 2005 library meeting, Rob Harrop and I
managed to spend a happy few hours pair programming - made all the
more interesting for Rob by the fact that I use a dvorak keyboard
layout and occassionally forgot to switch it back to qwerty before
giving him the keyboard....
By the time we were done, we could configure any aspect type
(whatever the instantiation model) from Spring simply by using the @
Bean annotation and defining a beans.xml file. In fact, we could
configure any type with the @Bean annotation. We made it so that in
the simplest case there is no need for the programmer to explicitly
initialise spring - aspects do that for you when first detecting a
type with the @Bean annotation, all you have to do is have one or
more beans.xml files on the classpath. Oh, and did I mention that
any type (including aspects) configured this way can be autoexported as MBeans and managed via JMX? (no user code involved).
This represents a pretty neat solution for configuring and managing
aspects.
As ever, I'll sketch out the basics of the implementation for you
here...
I'll use as an example an abstraction of the common session factory
/ session / worker pattern that crops up again and again. A worker
class performs work that takes place in a session. Sessions are
created by the session factory. Here's my Worker class:

p
c
W
{

p
s
v
m
(S
[ a
){
W
w
1=n
W
()
W
w
2=n
W
()
w
1.d
()
w
2.d
()
w
1.d
()
}

p
v
d
(){
S
s
=S
.asp
().g
()
S
.o .p
( Do
wo
in"+s
doWo
1()
doWo
2()
}

p
voiddoWo
1(){
S
s
=S
.asp

S
.o .p
+s
)
}

p
voiddoWo
S
s
().g
()
S
.o .p
+s
)
}

}

("Doingwo

=S

inh

2(){

1fo "

.asp

("Doingwo

inh

2fo "

Worker has a convenience main method that creates two workers and
asks them to do work. Note that the doWorkHelper1() and
doWorkHelper2() methods are called within the cflow of the doWork
method. In each method we print out the current session (from the
SessionManager aspect). The SessionManager aspect is a percflow
aspect that creates a new aspect for each control flow through
doWork....

@B
("S
p
asp
p
p

S
S

")
s

fac

(s

()){

/**
*S
tous isconfigu
*/
pub
voids
(S
facto ){
this.facto =facto
}

/**
*Ma
th cu
s
avai
toan
who
n
it
*/
pub
S
g
(){r
s
}

/**
*An
S
(ands
)b
wh
*w e
doWor
*/
pointcutsession():e
(*doWor (..))
/**
*Createasessionusingthefactor
passedto
*uswhenwewereconfigured
*/

thatwas

session=factor .beginSession()
}

/**
*C
thesessionattheendofthesession()
contro 
*f
.
*/
after():session(){session.c
()}
}

Note that the SessionManager aspect is annotated with @Bean, and has
a setSessionFactory(..) method that is to be called by an IoC
container to pass it the session factory to use.
Here's the Spring beans.xml file for the project. Note that this is
100% standard Spring, no funny stuff.

< xm version="1.0"encoding="U :8"


< D
beansPUB
"://SP
//D
B
//E ""http://
www.springframewor .org/dtd/spring:beans.dtd"
<beans>
<beanname="SessionManager"
c
="org.aspectprogrammer.test.SessionManager">

<propert name="session
">

<refbean="Session
"/>

</propert >
</bean>

<beanname="Session
"
c
="org.aspectprogrammer.test.Session
">
</bean>
</beans>

Just compile this with the Spring AspectJ library on your aspectpath
and run main:

Doingwor
Doingwor
Doingwor
Doingwor
Doingwor
Doingwor
Doingwor
Doingwor
Doingwor

insession#1001
inhe
1forsession#1001
inhe
2forsession#1001
insession#1002
inhe
1forsession#1002
inhe
2forsession#1002
insession#100
inhe
1forsession#100
inhe
2forsession#100

We created 3 SessionManager aspect instances, one per control flow,


and each was correctly configured by Spring. In true Spring style,
note that we did this without using one single Spring API in our
program
To get this to work, we used a couple of library aspects as follows.
The abstract BeanConfigurator aspect will configure (and validate)
any object whose type is annotated with @Bean:

/**
*Configureandva
an ob
whoset
is
annotatedwith@Bean.
*Va
occursforan t
imp
the
Va
*interface.Tobesubc
foreachIoCmechanism
youwantto
*support(eg.Spring,HiveMind,Pico,JD ,...).
*/
pub
abstractaspectBeanConfigurator{
/**
*Weon
va
@Beans...
*/
dec
warning:staticinitia
(Va
+)&&
!staticinitia
(@Bean*)&&
!staticinitia
(Va
)
:"Imp
ofVa
must
havethe@Beanannotation"

/**
*Thecreationofanewbean(anob
withthe@
Beanannotation)
*/
pointcutbeanCreation(BeanbeanAnnotation,Ob
beanInstance):
initia
((@Bean*).new(..))&&
@this(beanAnnotation)&&
this(beanInstance)
/**
*A
beansshou
beconfiguredafterconstruction.
*/
after(BeanbeanAnnotation,Ob
beanInstance)
returning:
beanCreation(beanAnnotation,beanInstance)
{
configureBean(beanInstance,getBean
(beanAnnotation,beanInstance))
}

/**
*Ifabeanimp
theVa

*va
()onitonceithasbeenconfigured
(thisadvicerunsafterthe
*configurationadvice).
*/
after(BeanbeanAnnotation,Va
beanInstance)returning:
beanCreation(beanAnnotation,Ob
)&&this
(beanInstance){
beanInstance.va
()
}

/**
*Thebeannameiseithertheva
giveninthe
annotation(@Bean("MyBean")),
*orthenameofthetypeifnova
isgiven
(@Bean).
*/
privateStringgetBean
(BeanbeanAnnotation,
Ob
beanInstance){
Stringbean
=beanAnnotation.va
()
if(bean
.e
(""))bean
=
beanInstance.getC
().get
()
returnbean

}
/**
*Tobeoverridenbysub:aspects.Configurethe
beaninstanceusingthegiven
*beanname.
*/
protectedabstractvoidconfigureBean(Ob
bean,Stringbean
)
}

This abstract aspect has been designed to allow you to plug-in any
IoC container you choose. We chose Spring ;). So here's the concrete
Spring sub-aspect:

/**
*Configurationofany@BeanusingSpring
*/
pub
aspectSpringBeanConfiguratorextends
BeanConfigurator
imp
App
{

privateConfigurab
bean


/**
*DItheSpringapp
contextinwhichthis
aspectshou
configurebeans.

pub
voidsetApp
(App
ctx){
if(!(ctxinstanceof
Configurab
)){
thrownewAspectConfigurationException(
"App
["+ctx+" 
doesnotimp
Configurab
.")
}

bean
=((Configurab
)
ctx).getBean
()
}

/**
*Imp
ofconfigureBeanfromthesuper:
aspect
*/
protectedvoidconfigureBean(Ob
bean,String
bean
){
if(bean
!=nu &&
bean
.containsBeanDefinition(bean
)){
bean
.app
(bean,bean
)
}
}
}

The final piece of the puzzle is how Spring gets bootstrapped. We


use an aspect for that too. Here's the abstract Spring
initialization aspect - it's abstract because we don't know what
strategy you want to use for the creation of an application context.

/**
*Imp
la
initiali
ofSpringbasedon
firstuseofan
*@Beantype.
*/
publicabstractaspectAbstractSpringInitiali
{
/**
*weonlywanttocreatetheapplicationcontext
once
*/
staticbooleaninitiali
=false

/**
*thefirsttimeweloadatypewiththe@Bean
annotation
*/
pointcutfirstTime
():

(!initiali
)

/**
*CreatetheSpringapplicationcontext,delegate
creationstrategyto
*concretesub:aspects.
*/
after()returning:firstTime
(){
ApplicationContextcontext=
createApplicationContext()
SpringBeanConfigurator.aspectOf
().setApplicationContext(context)
}

/**
*Sub:aspectsoverridethismethodtoprovidea
concretestrategyfor
*applicationcontextcreation.
*/
protectedabstractApplicationContext
createApplicationContext()
}

For my program above, I used a DefaultSpringInitializer that


configures the application context based on one or more beans.xml
files available on the classpath

/**
*Adefaultimplementationofthe
AbstractSpringInitiali
aspect.Thiswillconfigure
*theSpringapplicationcontextusingthesetof
beans.xmlfilesavailableintheclasspath
*(whatyouwantformanyapplications).Configuration
filescanbeoverridenbyspecifying
*the
org.aspect .a
.configuration.spring.config
property(usefulfortestingetc.).
*/
publicaspectDefaultSpringInitiali
extends
AbstractSpringInitiali
{
publicstaticfinalStringCO
_LOCATIO
=
"org.aspect .a
.configuration.spring.configLocations"

privatestaticfinalStringDE
_LOCATIO _PATTE 
="classpath*:/**/beans.xml"

protectedApplicationContextcreateApplicationContext

Stringconfig
=null
try{
config
=System.getProperty
(CO
_LOCATIO )
if(config
==null)
config
=DE
_LOCATIO _PATTE
}catch(SecurityExceptionsecEx){
config
=DE
_LOCATIO _
PATTE
}
returnnewClassPath
(

StringUtils.commaDelimitedListToStringArray
(config
))
}

}

The result of all this, is that with a few very simple building
blocks you can configure aspects (and any other type) simply by
writing a standard beans.xml file and using the @Bean annotation no Spring APIs required in your code at all. There's more coming out
of the joint Spring / AspectJ development effort, but I hope this
whets your appetite for now.
Posted by adrian at March 22, 2005 03:47 PM [permalink]

Comments
Very cool. Now, when you say any type, does that refer to plain java
beans?
Posted by: Peter Morelli at March 22, 2005 04:01 PM
Yes, although bear in mind this solution works best in situations
where you are programmatically creating instances (or in the case of
AspectJ, the AspectJ runtime is creating instances of aspects for
you) that you subsequently want to be configured. For the "normal"
pre-instantiated and wired-together singletons model that Spring
supports you wouldn't need to use @Bean since Spring handles
instantiation and configuration in one go.
Posted by: Adrian at March 22, 2005 06:34 PM

Post a comment
You are not signed in. You need to be registered to comment on this
site. Sign in

You might also like