我有注释:
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface Loggable { }
和方面:
@Aspect
public class AspectLogger {
@Around("@annotation(aspects.Loggable)")
public void aroundLogging(ProceedingJoinPoint joinPoint) {
System.out.println("aroundLogging()");
throw new AuthentificationFailException();
}
}
我也有界面和课程:
public interface IAuthInteractor {
public User authorization(String login, String password);
}
public class AuthInteractor implements IAuthInteractor {
private EntityDAO<User> userDAO;
private ITokenGenerator tokenGenerator;
public AuthInteractor(EntityDAO<User> userDAO,
ITokenGenerator tokenGenerator) {
this.userDAO = userDAO;
this.tokenGenerator = tokenGenerator;
}
@Loggable
public User authorization1(String login, String password) {
return null;
}
@Loggable
public User authorization(String login, String password) {
return null;
}
}
对于第一种方法( authorization1 ),注释不起作用。对于方法授权(在interafce中描述),注释可以正常工作。
为什么这样工作?以及如何在没有界面的情况下工作?
答案 0 :(得分:1)
首先,方面的建议有一个void
返回类型,即对于返回其他类型的方法(例如User
),它永远不会启动。方面甚至不应该编译。在任何情况下它都不适合我。 AspectJ编译器说:
applying to join point that doesn't return void: method-execution(de.scrum_master.app.User de.scrum_master.app.AuthInteractor.authorization(java.lang.String, java.lang.String))
因此,假设您将建议改为
@Around("@annotation(aspects.Loggable)")
public Object aroundLogging(ProceedingJoinPoint joinPoint) {
System.out.println("aroundLogging()");
throw new AuthentificationFailException();
}
它将编译并启动。我在本地进行了测试。
现在让我快速更改建议以实际进入原始方法,而不是总是抛出异常,这样我们可以测试更多,而不会一直捕获异常。我还想打印实际的连接点签名,这样我们就可以看到发生了什么:
@Around("@annotation(aspects.Loggable)")
public Object aroundLogging(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println(joinPoint);
//throw new AuthentificationFailException();
return joinPoint.proceed();
}
如果那么你将这个main
方法添加到你的接口实现类:
public static void main(String[] args) {
System.out.println("Interface object");
IAuthInteractor iAuthInteractor = new AuthInteractor(null, null);
iAuthInteractor.authorization("user", "pw");
System.out.println("\nImplementation object");
AuthInteractor authInteractor = new AuthInteractor(null, null);
authInteractor.authorization("user", "pw");
authInteractor.authorization1("user", "pw");
}
控制台日志应该打印这样的东西,假设您使用AspectJ而不仅仅是通过不支持call()
个连接点的Spring AOP的“AOP lite”:
Interface object
execution(User de.scrum_master.app.AuthInteractor.authorization(String, String))
Implementation object
call(User de.scrum_master.app.AuthInteractor.authorization(String, String))
execution(User de.scrum_master.app.AuthInteractor.authorization(String, String))
call(User de.scrum_master.app.AuthInteractor.authorization1(String, String))
execution(User de.scrum_master.app.AuthInteractor.authorization1(String, String))
如您所见,执行总是被捕获,但调用不适用于接口类型实例,因为接口方法没有注释,只有实现。
BTW,方法注释无论如何都不会被继承,因此@Inherited
注释类型的@Target({ElementType.METHOD})
元注释有点无用。