Aspect-oriented programming is, among other things, the attempt to define and centralize cross-cutting concerns. In other words, it is not much more than the tried-and-true principle of modularization. Having possibly unseen aspects operating on a given class however, can complicate an initial examination of the code. Therefore, it is important to be aware of what portions of the OMERO code base are “advised” and where to find the advisors (in the case of OMERO solely interceptors).
In Spring, advisors are declared in the bean definition files (under components/server/resources/ome/services, services.xml, hibernate.xml, and others.
In these configuration files, various Spring beans (shared objects) are defined with names like “proxyHandler”, “eventHandler”, “serviceHandler”, and “transactionHandler”. Each of these is a method interceptor which is passed execution before the actual logic is reached. The interceptor can inspect or replace the return value, but can also stop the method execution from ever taking place.
Unlike with AspectJ, the AOP implementation used by OMERO only allows for the advising of interfaces. Simply creating a new service implementation via “new QueryImpl()” will not produce an advised object, which in turn will not function properly, if at all. Instead, advised objects can only be acquired from the Spring context.
By and large, only the API service methods are advised in OMERO.
Often, when implementing or adding code, it becomes clear just how many requirements are placed by libraries, the application server, and existing code on any new code. This can include transaction handling, session handling, security checks, object validation, logging etc. As a code-base grows, these dependencies slow development and make code unmanageable. AOP tries to reduce these dependencies by defining each of these concerns in a single place.
As a quick example, in OMERO transactions and exceptions are handled through method interceptors. Rather than writing:
void method1(){
try {
Transaction tx = new Transaction();
tx.begin();
// your code goes here
tx.commit();
} catch (TxException e) {
tx.rollback();
} catch (OtherException e) {
}
}
you just write:
void method1(){
// your code goes here
}
See also