java - 如何使用 Spring Before Advice 增加方法中使用的参数
问题描述
我从我的 Java 语言老师那里得到了一项任务,即在建议之前使用 spring AOP 来增加 Restful web 服务中的计数器(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;
}
CounterAspect(由我编写):
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 等等。我不明白在“public void beforeAdvice”中写什么。Spring 不控制“Greeting”类可以吗?
解决方案
Spring AOP 只会建议 spring beans。因此,您对“ Spring 不控制“会议”类是否可以? ”(我猜您的意思是 Greeting 在这里)的担忧是有效的。不行,因为您正在尝试建议 Greeting bean。
另请注意,使用 Spring AOP 您不能建议构造函数。参考
如果您的拦截需求包括目标类中的方法调用甚至构造函数,请考虑使用 Spring 驱动的原生 AspectJ 编织,而不是 Spring 的基于代理的 AOP 框架。
要更好地理解以下代码,您必须通读以下参考资料。
使用 Spring AOP 有多种方法可以实现您的要求,我只是按照您的建议进行操作。
修改了 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;
}
}
将 Greeting 类修改为 Spring bean。
@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());
}
}
}
此通知针对Greeting bean上的任何公共方法调用执行,并通过参数使实际的Greeting对象可用于通知greeting
。(参考:https ://docs.spring.io/spring-framework/docs/current/reference/html/core.html#aop-ataspectj-advice-params-passing )。
作为工作的一部分,您可以尝试不同的方法来优化此代码。
推荐阅读
- python-3.x - Python 到 csv 分栏符
- node.js - OpenID Connect 实现(node.js 打字稿)
- apache - Haproxy“send-proxy”未知协议——不是说 SSL 到 HTTPS 端口?
- android - Lambda作为Android onClicklistener中的函数参数
- excel - Visual Basic 程序返回“运行时错误 '-2147024726 (800700aa)”
- python-3.x - 我可以在 Django 中使用 IntegerField 生成系列数字吗
- kde - KDE 第一步:dolphin 构建失败,gpgme 失败'未定义的引用 `qt_version_tag@Qt_5.12''
- node.js - 将值设置为异步块内的变量
- angular - Angular 6:[(ngModel)] 并不总是有效
- c# - 如何在 NSwag 生成的 C# 代码中包含自定义语句/指令?