Scala Cross Cutting Концерны со стеками смешанных композиций - PullRequest
0 голосов
/ 17 марта 2019

Я следил за этим учебным пособием Джонаса Бонера о том, как добиться 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")

enter image description here

1 Ответ

0 голосов
/ 17 марта 2019

Проблема была в строке invocation.target.getClass.getDeclaredMethods.exists(pointcut.matchesMethodExecution(_).alwaysMatches) в object InterceptorImpl, которая соответствует всем методам класса. Поскольку оба метода foo и bar принадлежат trait Foo, который расширен на class FooImpl, регистрация pointcutExpression совпадений происходит для обоих методов.

...