Я следил за этим учебным пособием Джонаса Бонера о том, как добиться AspectJ-подобного аспектно-ориентированного программирования в Scala. Миксины меня сильно спутали с abstract overrides
. В конце концов я получил реализацию, сопоставив parsePointcutExpression
. Тем не менее, pointcutExpression
соответствие неверно:
Класс кейса My Invocation:
package aspect2
import java.lang.reflect.Method
object aspect {
case class Invocation(val method: Method, val args: Array[AnyRef], val target: AnyRef) {
def invoke: AnyRef = method.invoke(target, args:_*)
override def toString: String = "Invocation [method: " + method.getName + ", args: " + args + ", target: " + target + "]"
}
}
Мои методы перехватчика и рекомендации для сопоставления pointcutExpressions
и ведения журнала: Примечание. Я хочу сопоставить с "execution(* *.bar(..))"
.
package aspect2
import aspect2.aspect.Invocation
import org.aspectj.weaver.tools.{PointcutExpression, PointcutParser}
object InterceptorImpl {
trait Interceptor {
protected val parser = PointcutParser.getPointcutParserSupportingAllPrimitivesAndUsingContextClassloaderForResolution
protected def matches(pointcut: PointcutExpression, invocation: Invocation): Boolean = {
pointcut.matchesMethodExecution(invocation.method).alwaysMatches ||
invocation.target.getClass.getDeclaredMethods.exists(pointcut.matchesMethodExecution(_).alwaysMatches) ||
false
}
def invoke(invocation: Invocation): AnyRef
}
trait LoggingInterceptor extends Interceptor {
val loggingPointcut = parser.parsePointcutExpression("execution(* *.bar(..))")
abstract override def invoke(invocation: Invocation): AnyRef =
if (matches(loggingPointcut , invocation)) {
println("=====> Enter: " + invocation.method.getName + " @ " + invocation.target.getClass.getName)
val result = super.invoke(invocation)
println("=====> Exit: " + invocation.method.getName + " @ " + invocation.target.getClass.getName)
result
} else super.invoke(invocation)
}
}
Мои фабричные методы для соединения перехватчиков с использованием Java Dynamic Proxy API
package aspect2
import java.lang.reflect.{InvocationHandler, Method, Proxy}
import aspect2.aspect.Invocation
object ManagedComponentFactory {
def createComponent[T](intf: Class[T] forSome {type T}, proxy: ManagedComponentProxy): T =
Proxy.newProxyInstance(
proxy.target.getClass.getClassLoader,
Array(intf),
proxy).asInstanceOf[T]
}
class ManagedComponentProxy(val target: AnyRef) extends InvocationHandler {
override def invoke(proxy: AnyRef, m: Method, args: Array[AnyRef]): AnyRef = invoke(Invocation(m, args, target))
def invoke(invocation: Invocation): AnyRef = invocation.invoke
}
Моя основная функция для запуска демонстрации:
package aspect2
import aspect2.InterceptorImpl.LoggingInterceptor
import aspect2.aspect.Invocation
object aspectDemo extends App{
var foo = ManagedComponentFactory.createComponent[Foo](
classOf[Foo],
new ManagedComponentProxy(new FooImpl)
with LoggingInterceptor{
override def invoke(invocation:Invocation):AnyRef={
super.invoke(invocation)
}
})
foo.foo("foo")
foo.bar("bar")
}
Foo и Bar реализованы следующим образом:
trait Foo {
def foo(msg: String)
def bar(msg: String)
}
class FooImpl extends Foo {
val bar: Bar = new BarImpl
def foo(msg: String) = println("msg: " + msg)
def bar(msg: String) = bar.bar(msg)
}
trait Bar {
def bar(msg: String)
}
class BarImpl extends Bar {
def bar(msg: String) = println("msg: " + msg)
}
Мои результаты показывают, что мой pointcut ("execution(* *.bar(..))"
) получает оба foo.bar("bar") and foo.foo("foo")