如何在通知之前增加spring方法中使用的参数

pxyaymoc  于 2021-07-06  发布在  Java
关注(0)|答案(2)|浏览(319)

我从java语言老师那里得到一个任务,在建议之前使用SpringAOP增加RESTfulWeb服务中的计数器(id)。找不到怎么做。我们使用spring.io中的默认restful应用程序。这是我修改过的代码:
应用程序:

package sut.ist012m.Ruygo.hello_goodbye;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@SpringBootApplication
@EnableAspectJAutoProxy(proxyTargetClass=true)

public class Application {

    public static void main(String[] args) {

        final ConfigurableApplicationContext run = SpringApplication.run(Application.class, args);
        final Controller Controller = run.getBean(Controller.class);
    }
}

控制器:

package sut.ist012m.Ruygo.hello_goodbye;

import java.util.concurrent.atomic.AtomicLong;

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class Controller {

    private static final String hellotemplate = "Hello, %s!";
    private static final String adrtemplate = "Welcome to %s";
    public AtomicLong counter1 = new AtomicLong();

    @RequestMapping("/greeting")
    public Greeting greeting(@RequestParam(value="name", defaultValue="World") String name,
                             @RequestParam(value="city", defaultValue="Moscow") String city) {
        return new Greeting(counter1.incrementAndGet(),
                String.format(hellotemplate, name),
                    String.format(adrtemplate, city));
    }

}

招呼:

package sut.ist012m.Ruygo.hello_goodbye;

public class Greeting {
    private final long id;
    private final String content;
    private final String adrcontent;

    public Greeting( long id,
                     String content,
                     String adrcontent) {
        this.id = id;
        this.content = content;
        this.adrcontent = adrcontent;
    }

    public long getId() {

        return id;
    }

    public String getContent() {

        return content;
    }

    public String getAdrcontent() {

        return adrcontent;
    }

反面(我写):

package sut.ist012m.Ruygo.hello_goodbye;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class CounterAspect {
    long id;
    @Before(value="execution(* sut.ist012m.Ruygo.hello_goodbye.Greeting.*(..)) ")
    public void beforeAdvice(JoinPoint joinPoint){

     }

}

在正常情况下,然后你刷新网页你看到id=1,id=2,id=3。。。我们想看到id=1,11,21,23等等。我不明白在“建议前公开无效”里写什么。spring不控制“问候语”类可以吗?

pes8fvy9

pes8fvy91#

springaop只会通知springbeans。所以你所关心的“spring不能控制“meeting”类吗?”(我猜你在这里指的是问候语)是正确的。这是不好的,因为你试图建议一个问候豆。
还要注意的是,使用springaop不能通知构造函数。参考
如果您的拦截需要在目标类中包含方法调用甚至构造函数,请考虑使用spring驱动的本机aspectj编织,而不是spring基于代理的aop框架。
为了更好地理解下面的代码,您必须通读下面的参考资料。
@请求范围
spring aop参考文档
使用springaop有多种方法来实现您的需求,我只是遵循您的建议。
修改了greetingcontroller并自动连接了一个具有范围请求的问候bean。

@RestController
public class GreetingController {
    private static final String hellotemplate = "Hello, %s!";
    private static final String adrtemplate = "Welcome to %s";

    @Autowired
    Greeting greeting;

    @RequestMapping("/greeting")
    public Greeting greeting(@RequestParam(value = "name", defaultValue = "World") String name,
            @RequestParam(value = "city", defaultValue = "Moscow") String city) throws Exception {
        greeting.setAdrcontent(String.format(adrtemplate, city));
        greeting.setContent(String.format(hellotemplate, name));
        Greeting g = getTarget(greeting);
        return g;
    }

    // Get the actual target object to avoid exception when returning
    // Comment out this method to observe what happens.
    private Greeting getTarget(Greeting greeting) throws Exception {
        while (AopUtils.isAopProxy(greeting) && greeting instanceof Advised) {
            Object target = ((Advised) greeting).getTargetSource().getTarget();
            greeting = (Greeting) target;
        } 
        return greeting;
    }
}

将问候语类修改为springbean。

@Component
@RequestScope
public class Greeting {
    private long id;
    private String content;
    private String adrcontent;

    // Getters and setters
}

反相位

@Aspect
@Component
public class CounterAspect {

    public AtomicLong counter1 = new AtomicLong(1);

    @Before(value = "execution(* sut.ist012m.Ruygo.hello_goodbye.Greeting.*(..)) && target(greeting)")
    public void beforeAdvice(Greeting greeting) {
        if (greeting.getId() == 0) {
            greeting.setId(counter1.getAndAdd(10));
            System.out.println(greeting.getId());
        }
    }

}

此通知对greetingbean上的任何公共方法调用执行,并通过 greeting 参数(参考:https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#aop-ataspectj通知参数(正在传递)。
作为工作的一部分,您可以尝试不同的方法来优化此代码。

up9lanfz

up9lanfz2#

不能使用before advice修改参数,必须使用around advice修改参数。

@Around(value="execution(* sut.ist012m.Ruygo.hello_goodbye.Greeting.*(..)) ")
public void aroundAdvice(ProceedingJoinPoint pjp){
   Object[] args = pjp.getArgs();
   // you can modify it by modifying args
   args[0] = .....; // modify your first parameter (id)
   args[1] = .....; // modify your second parameter (content)
   args[2] = .....; // modify your third parameter (adrcontent)
   // call proceed method from pjp and pass args as its parameter
   pjp.proceed(args);
}

相关问题