我正在尝试用aspectj学习springaop,通过构建一个小型银行事务模拟。但是我无法向aspect类本身的方法添加建议(@before,@after,@afterthrowing)。
这就是模型
银行.java
@Component
public class Bank {
private int balance;
private int pinCode;
private int tempPin;
public int getBalance() {
return balance;
}
@Value("10000")
public void setBalance(int balance) {
this.balance = balance;
}
public int getPinCode() {
return pinCode;
}
@Value("6789")
public void setPinCode(int pinCode) {
this.pinCode = pinCode;
}
public int getTempPin() {
return tempPin;
}
public void setTempPin(int tempPin) {
this.tempPin = tempPin;
}
public void withDraw(int amount) {
if (amount <= balance) {
balance -= amount;
System.out.println("Successful Withdraw");
} else {
System.out.println("Insufficient Balance");
}
}
}
这是aspect类
bankaspect.java版本
@Component
@Aspect
public class BankAspect {
private Bank bank;
public Bank getBank() {
return bank;
}
@Autowired
public void setBank(Bank bank) {
this.bank = bank;
}
@Before("execution(public void dev.ritam.model.Bank.withDraw(..))")
public void validatePin() {
if (bank.getPinCode() != bank.getTempPin()) {
throw new RuntimeException();
}
}
@AfterThrowing("execution(public void dev.ritam.aspect.BankAspect.validatePin(..))")
public void logException() {
System.out.println("Wrong Pin");
}
}
这是配置类
appconfig.java文件
@Configuration
@EnableAspectJAutoProxy
@ComponentScan("dev.ritam")
public class AppConfig {
@Bean
Bank bank() {
return new Bank();
}
@Bean
BankAspect bankAspect() {
return new BankAspect();
}
}
这是主要的方法
应用程序.java
public class App {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
Bank bank = context.getBean(Bank.class);
try {
bank.setTempPin(1234);
bank.withDraw(1000000);
} catch (Exception ignore) {
}
}
}
仅限
validatePin() @Before
建议正在被执行。我想得到'错误的引脚'作为输出,但 @AfterThrowing
建议不被认可。
2条答案
按热度按时间xxls0lw81#
参考文件:
建议其他方面?在springaop中,方面本身不能成为来自其他方面的建议的目标。类上的@aspect注解将其标记为方面,因此将其从自动代理中排除。
您不能在springaop中建议一个方面,这就是
@AfterThrowing
不执行。要抛出异常并记录消息,可以建议使用相同的方法
Bank.withDraw()
与@AfterThrowing
. 那样的话validatePin()
建议将在Bank.withDraw()
以及logException()
如果验证引发异常,则将执行通知。这是@dreamcash的答案中提到的第二个选项。示例代码
这将导致以下控制台输出序列
几个要点要考虑。
Bank
以及BankAspect
用注解@Component
以及@ComponentScan
将它们注册为bean。也就是说豆子注册了@Bean
在appconfig中不需要。两者中的任何一个都是必需的。@dreamcrash的答案中提到的最后一个选项在springaop中不受支持:请参阅从其他切入点类型开始的部分
更新:
这是一个棘手的问题,我建议的答案是基于springboot版本:2.2.6.release,它使用版本:5.2.5.release的spring库
op共享的代码基于spring版本:5.3.1,建议没有按预期执行。
共享代码中的spring aop建议按预期工作,spring版本应该是<=5.2.6.release
请从更新pom.xml条目
到
为了快速参考,下面是op的代码,它不适用于这个版本
5.3.1
```@After("execution(public void dev.ritam.model.Bank.setTempPin(..))")
public void validatePin() {
if (bank.getPinCode() != bank.getTempPin()) {
throw new RuntimeException("Wrong Pin");
} else {
System.out.println("Correct Pin");
}
}
@AfterThrowing(value = "execution(public void dev.ritam.model.Bank.setTempPin(..))", throwing = "e")
public void logException(Exception e) {
System.out.println(e.getMessage());
}
r7knjye22#
方法
public void validatePin()
(在课堂上)BankAspect
)作为建议;因此,如果你使用AspectJ
单凭你自己,你不可能以你所做的方式截取它(例如,你需要使用切入点)adviceexecution
). 如果是Spring AOP
事情更加严格;Spring AOP
不允许方面成为建议的目标。要解决您的问题,您可以截取与切入点之前截取的方法相同的方法,即:
因为异常将在方法的范围内引发
Bank.withDraw
你的@AfterThrowing
切入点将能够捕获该异常。仅适用于aspectj
一个简单的解决方案是 Package 以下代码:
到方法中,例如:
现在截取该方法:
另一种可供选择的方法是使用
adviceexecution()
```@AfterThrowing("within(BankAspect) && adviceexecution()")
public void logException() {
System.out.println("Wrong Pin");
}