在 Web 服务中添加 AspectJ

2022-09-04 21:21:42

我有一个Java EE Webservice(REST),现在想使用AspectJ来创建一个规则,该规则将打印出每个传入的服务调用及其参数。

我刚刚阅读了本教程并实现了以下代码:

聚甲醛.XML

        <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjrt</artifactId>
        <version>1.8.10</version>
    </dependency>
    
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.8.10</version>
    </dependency>
    
</dependencies>
<build>
  <plugins>
    <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>aspectj-maven-plugin</artifactId>
        <version>1.7</version>
        <configuration>
            <complianceLevel>1.8</complianceLevel>
            <source>1.8</source>
            <target>1.8</target>
            <showWeaveInfo>true</showWeaveInfo>
            <verbose>true</verbose>
            <Xlint>ignore</Xlint>
            <encoding>UTF-8 </encoding>
        </configuration>
        <executions>
            <execution>
                <goals>
                    <!-- use this goal to weave all your main classes -->
                    <goal>compile</goal>
                    <!-- use this goal to weave all your test classes -->
                    <goal>test-compile</goal>
                </goals>
            </execution>
        </executions>
    </plugin>
</plugins>

...并创建了一个 Test.aj 文件,其中包含一个 Pointcut,该文件应在调用 getSignOfLife() 后打印出测试字符串:

import de.jack.businesspartner.service.BusinessPartnerServiceImpl;
public aspect TestAspectJ {

    pointcut getSignOfLife() : 
      call(void BusinessPartnerServiceImpl.getSignOfLife());

    before() : getSignOfLife() {
        System.err.println("ADKL TEST ASPECT");
    }

}

--> 但是如果我调用getSignOfLife()方法,则不会发生任何事情。你可以帮我吗?


答案 1

您的切入点表达式可能是错误的:

pointcut getSignOfLife() : 
  call(void BusinessPartnerServiceImpl.getSignOfLife());

中的表达式应与真实方法的签名匹配。call

清单

  • 返回类型:似乎有一个返回值,你在表达式中写一个返回类型,这将使匹配失败;getSignOfLifevoid
  • 参数类型:您可以使用任何参数来表示方法,但是如果将其留空,则表示没有参数。如果您的实际方法有参数,它将失败匹配;f(..)f
  • 请注意,和 在表达式上是不同的,因为基元和装箱类型是不同的;intInteger
  • 你需要在你的pom中的原始编译器插件的maven;

        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.1</version>
            <configuration>
                <source>1.8</source>
                <target>1.8</target>
                <encoding>UTF-8</encoding>
            </configuration>
        </plugin>
    

更多

  • 如果您想深入了解AspectJ,可以参考此处
  • 在最常见的情况下,Spring AOP足以处理日志记录,身份验证等作业,这些作业可以与注释一起使用,我认为更方便。
  • 可运行的代码

答案 2

@Tony很好地解释了这一点。

关于您指出的教程,我通过稍微修改帐户方面对其进行了测试:

public aspect AccountAspect {
    final int MIN_BALANCE = 10;

    pointcut callWithDraw(int amount, Account acc) : 
     call(boolean Account.withdraw(int)) && args(amount) && target(acc);

    before(int amount, Account acc) : callWithDraw(amount, acc) {
    }

    boolean around(int amount, Account acc) : 
      callWithDraw(amount, acc) {
        acc.balance -= 5;
        if (acc.balance < amount) {
            return false;
        }
        return proceed(amount, acc);
    }

    after(int amount, Account balance) : callWithDraw(amount, balance) {
        System.out.println("After withdraw " + amount);
    }
}

然后在一个简单的 servlet 中:

@WebServlet("/Hello")
public class Hello extends HttpServlet {

    /**
     * 
     */
    private static final long serialVersionUID = 482093033327453159L;

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        Account acc = new Account();
        resp.setContentType("text/html");
        PrintWriter out = resp.getWriter();
        out.println("Account before withdraw: " + acc.balance + "<br/>");
        acc.withdraw(10);
        out.println("Account after withdraw: " + acc.balance + "");
        out.close();
    }
}

我用过:

  • 爪哇 8
  • 野蝇 10.1.0.最终版

它按预期工作(当调用撤回帐户时,帐户又撤回了5个,正如您从我的aspectaj文件中看到的那样,并且打印内容写在控制台上)around


推荐