460 likes | 465 Views
Learn how to use AspectWerkz framework for real-world enterprise applications, covering concepts, examples, dynamic runtime, and more.
E N D
JavaPolis 2003 AspectWerkz dynamic AOP for Java Jonas Bonér Senior Software Engineer BEA Systems
Overall Presentation Goal Learn how to use the AspectWerkz AOP framework to enable AOP in real-world enterprise applications
Agenda • Background • Concepts and constructs • Definition models • Real-world examples • Dynamic runtime model • Questions
Agenda • Background • Concepts and constructs • Definition models • Real-world examples • Dynamic runtime model • Questions
Limitations • AspectJ • too academic, steep learning curve • not dynamic • language extension • Nanning and Spring (dynamic proxy based) • join point model very limited (interception on callee side) • not high-performant (uses reflection) • BEA’s AspectSystem • not vendor and/or platform independent • only a hooking mechanism • JBoss AOP • no JVM wide hook (uses custom class loader)
Requirements Usability • Pure Java • XML and runtime attribute definition • Easy to learn and use Dynamicity • Dynamic runtime model • Hot-deployment of aspects, advices and introductions Ease of integration • Platform and vendor independent • Runtime bytecode weaving and static compilation Production quality • Lightweight and high-performant • Tool support (debugging etc.) • AspectWerkz
Agenda • Background • Concepts and constructs • Definition models • Real-world examples • Dynamic runtime model • Questions
Pointcut pattern language • Fine-grained pattern language for picking out join points • Pattern format: • [type] [package].[class].[method]([types]) • String foo.baz.Bar.method(int, Object) • Supports wildcards: • * foo.baz.Bar.*(..) • * foo..*.*(..) • Subtype patterns • foo.baz.Bar+ • Can be composed • (pc1 || pc2) && pc3 • pc1 && !pc3
Pointcut types • Execution - picks out join points defining method execution (callee side) • Call - picks out join points defining method call (caller side) • Get/Set - picks out join points defining field access or modification • Cflow - picks out join points defining a control flow • Throws - picks out join points defining where an exception is thrown out of a method
Deployment models • Defines the ‘scope’ or life-cycle of the advice or introduction • AspectWerkz supports four different deployment models: • perJVM - one sole instance per JVM (singleton) • perClass - one instance per target class • perInstance - one instance per target class instance • perThread - one instance per thread
Advices • Allows you to add additional code at matching pointcuts • Three types of advices: • Around advice - is invoked “around” the join point • After advice - is invoked after the join point • Before advice - is invoked before the join point
“caller instance” object.myMethod() “callee instance” around advice around advice public void myMethod() { ... } Advices • Example – around advice: public Object myAdvice(JoinPoint joinPoint) throws Throwable { // do stuff Object result = joinPoint.proceed(); // do more stuff return result; }
Join point introspection • Each advice is passed a JoinPoint instance • Allows introspection possibilities • RTTI about a specific join point • For example at a execution join point could we get: • target instance and class • method instance • parameter values and types • return value and type • Possible to modify parameters and return value at runtime
Mixins • Introductions allows you to add code to existing classes • Implemented in AspectWerkz using mixins • Mixins are: • a way of simulating multiple inheritance • common in dynamic languages like Ruby, CLOS and Groovy • The mixin must consist of: • an interface • an implementation of that interface • The mixin implementation can be any regular Java class
Mixin1 Mixin2 Mixin3 Mixin4 MixinImpl1 methodInMixin1() MixinImpl2 methodInMixin2() methodInMixin3() MixinImpl3 methodInMixin4() MixinImpl4 Mixins perJVM perClass perInstance perThread target instance
Agenda • Background • Concepts and constructs • Definition models • Real-world examples • Dynamic runtime model • Questions
Definition models • Supports two different definition models: • XML • Runtime attributes • XML definition model • Advantages: • Widely used and intuitive format • Great tool support • Disadvantages: • Separates the implementation from the definition • Overly complex, hard to read • No refactoring support
Runtime attribute definition model • Aspect components • aspects are self-defined and self-contained • implementation and definition in one single class • supports abstraction and inheritance • easy to build reusable aspect libraries • Custom runtime attributes implementation • JavaDoc tags (parsed using QDox) • attributes inserted in bytecode of compiled class/method/field • ready for JSR-175 (Metadata Facility for Java)
Runtime attribute definition model • Example /** @Aspect perInstance */ public class LoggingAspect extends Aspect { } • /** @Call * foo.bar.*.*(..) */ • Pointcut logMethodCall; • /** @Execution * foo.baz.*.*(..) */ • Pointcut logMethodExecution; /** @BeforelogMethodCall */ public void logEntry(JoinPoint joinPoint) { ... } /** @AfterlogMethodCall */ public void logExit(JoinPoint joinPoint) { ... } /** @AroundlogMethodExecution */ public Object logExecution(JoinPoint joinPoint) { ... }
Runtime attribute definition model • Example – mixin /** * @Aspect perInstance */ public class PersistenceAspect extends Aspect { ... // advices and pointcuts /** * @Introduce *..domain.* */ public class PersistableMixin extends MyBase implements Persistable, Traceable, Metered { ... // implementation of the mixin } ... // more mixins }
Agenda • Background • Concepts and constructs • Definition models • Real-world examples • Dynamic runtime model • Questions
Real-world examples • Good candidates for AOP: • role based security • transaction demarcation • persistence • lazy loading • eager loading (loading policies) • asynchronous calls • synchronization • virtual mock objects for unit testing • performance optimization • design patterns • business rules • pure mixin based implementations (quantum AOP)
Role Based Security • Abstract aspect with pointcuts /** * @Aspect perThread */ public abstract class AbstractRoleBasedAccessProtocol extends Aspect { protected Subject m_subject = null; protected final SecurityManager m_securityManager = ... /** To be defined by the concrete aspect. */ Pointcut authenticationPoints; /** To be defined by the concrete aspect. */ Pointcut authorizationPoints; ... // advices }
Role Based Security • Authentication advice /** *@AroundauthenticationPoints */ public Object authenticateUser(JoinPoint joinPoint) throws Throwable { if (m_subject == null) { // no subject => authentication required Context ctx = ... // get the principals and credentials m_subject = m_securityManager.authenticate(ctx); } Object result = Subject.doAsPrivileged( m_subject, new PrivilegedExceptionAction() { public Object run() throws Exception { return joinPoint.proceed(); }; }, null ); return result; }
Role Based Security • Authorization advice /** * @Around authorizationPoints */ public Object authorizeUser(JoinPoint joinPoint) throws Throwable { MethodJoinPoint jp = (MethodJoinPoint)joinPoint; if (m_securityManager.checkPermission( m_subject, jp.getTargetClass(), jp.getMethod())) { // user is authorized => proceed returnjoinPoint.proceed(); } else { throw new SecurityException(...); } }
Role Based Security • Concrete aspect /** * @Aspect perThread */ public class RoleBasedAccessProtocol extends AbstractRoleBasedAccessProtocol { /** * @Execution * testapp.facade.*.*(..) */ Pointcut authenticationPoints; /** * @Execution * testapp.service.*.*(..) */ Pointcut authorizationPoints; }
Unit Of Work • Unit Of Work • Common pattern in enterprise application architectures • Implements a transaction • Keeps track of new, removed and dirty objects • Can be used to implement: • Transaction demarcation for POJOs • Persistence handling for POJOs
Unit Of Work • UnitOfWork API public class UnitOfWork { public staticUnitOfWorkbegin() {…} public void commit() {…} public void rollback() {…} // registers the transactional objects public void registerNew(Object obj) {…} public void registerRemoved(Object obj) {…} public void registerDirty(Object obj) {…} // template methods public void doBegin() {…} public void doCommit() {…} public void doRollback() {…} } public class JtaAwareUnitOfWork extends UnitOfWork { public void doBegin() {…} public void doCommit() {…} public void doRollback() {…} }
Unit Of Work • Problems with regular non-AOP implementation: • Is a cross-cutting concern • Introduces code scattering • Introduces code tangling
Unit Of Work • For example, this code: ... Address address = new Address(...); customer.addAddress(address); ... • Will have to be replaced by: UnitOrWork unitOfWork = UnitOfWork.begin(); try { Address address = new Address(...); unitOfWork.registerNew(address); customer.addAddress(address); unitOfWork.registerDirty(customer); unitOfWork.commit(); } catch(Exception e) { unitOfWork.rollback(); }
Unit Of Work • Enter Aspect-Oriented Programming • Can make the UnitOfWork completely transparent • Abstract Aspect /** @AspectperJVM */ public abstract class AbstractUnitOfWorkProtocol extends Aspect { /** To be defined by the subclass. */ Pointcut transactionalObjectCreationPoints; /** To be defined by the subclass. */ Pointcut transactionalObjectModificationPoints; /** To be defined by the subclass. */ Pointcut transactionalMethods; ... // advices and introductions }
Unit Of Work • Advice - registerNew • Registers the newly created object as new /** * @Around transactionalObjectCreationPoints */ public Object registerNew(JoinPoint joinPoint) throws Throwable { Object newInstance = joinPoint.proceed(); if (UnitOfWork.isInUnitOfWork()) { UnitOfWork unitOfWork = UnitOfWork.getCurrent(); unitOfWork.registerNew(newInstance); } return newInstance; }
Unit Of Work • Advice - registerDirty • Registers an object as dirty just before a field is modified /** * @Before transactionalObjectModificationPoints */ public void registerDirty(JoinPoint joinPoint) throws Throwable { if (UnitOfWork.isInUnitOfWork()) { FieldJoinPoint jp = (FieldJoinPoint)joinPoint; UnitOfWork unitOfWork = UnitOfWork.getCurrent(); unitOfWork.registerDirty( jp.getTargetInstance(), jp.getFieldName() ); } }
Unit Of Work • Advice – proceedInTransaction /** @Around transactionalMethods */ public Object proceedInTransaction(JoinPoint joinPoint) { if (UnitOfWork.isInUnitOfWork()) { return joinPoint.proceed(); } UnitOfWork unitOfWork = UnitOfWork.begin(); final Object result; try { result = joinPoint.proceed(); if (unitOfWork.isRollbackOnly()) { unitOfWork.rollback(); } else { unitOfWork.commit(); } } catch (Throwable throwable) { throw handleException(throwable, unitOfWork); } finally { UnitOfWork.dispose(); } return result; }
Unit Of Work • Handle exception method • Uses the same approach as in EJB private Throwable handleException( Throwable throwable, UnitOfWork unitOfWork) { if (throwable instanceof RuntimeException) { unitOfWork.rollback(); } else { unitOfWork.commit(); } return throwable; }
Unit Of Work • Mixin - Transactional • Mixin with life-cycle and utility methods • Applied to the transactional objects • Inner class in the abstract aspect /** @Introduce TO_BE_DEFINED */ public abstract class TransactionalImpl implements Transactional, Serializable { public void setRollbackOnly() {…} public UnitOfWork getUnitOfWork() {…} public TransactionContext getTransaction() {…} public void create() {…} public void remove() {…} public void markDirty() {…} public boolean exists() {…} }
Agenda • Background • Concepts and constructs • Definition models • Real-world examples • Dynamic runtime model • Questions
Dynamic runtime model • Allows you to redefine the system at runtime • Swap mixin implementation at runtime SystemLoader.getSystem(systemId). getMixin(oldMixinName). swapImplementation(newMixinClassName); • Add new aspects and advices at runtime SystemLoader.getSystem(systemId).createAspect( aspectName, className, DeploymentModel.PER_INSTANCE, classLoader );
Dynamic runtime model • Reorder advices at runtime • Remove advices at runtime List pointcuts = SystemLoader.getSystem(systemId). getAspect(aspectName). getPointcuts(className, method); for (Iterator it = pointcuts.iterator(); it.hasNext();) { Pointcut pointcut = (Pointcut)it.next(); if (pointcut.hasAdvice(adviceName)) { pointcut.removeAdvice(adviceName); } }
Links • http://aspectwerkz.codehaus.org/ • http://wiki.codehaus.org/aspectwerkz • http://blogs.codehaus.org/projects/aspectwerkz/ • http://blogs.codehaus.org/people/jboner/ • http://blogs.codehaus.org/people/avasseur/ • http://www.aosd.net/
JavaPolis 2003 Thanksfor listening