我一直在跟随JonasBonér的this教程,内容涉及如何在Scala中实现类似于AspectJ的面向方面的编程。 mixins使我对abstract overrides
感到困惑。我最终通过匹配parsePointcutExpression
来实现了实现。但是,pointcutExpression
匹配不正确:
我的调用案例类:
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)
}
我的结果表明,我的切入点("execution(* *.bar(..))"
)都获得了foo.bar("bar") and foo.foo("foo")
答案 0 :(得分:0)
问题出在invocation.target.getClass.getDeclaredMethods.exists(pointcut.matchesMethodExecution(_).alwaysMatches)
的{{1}}行中,该行与该类的所有方法匹配。由于两种方法object InterceptorImpl
和foo
都属于bar
并由trait Foo
扩展,因此class FooImpl
匹配日志记录都发生在这两种方法上。