我对AspectJ和AOP很新。我知道AspectJ有许多Annotations(After,AfterReturning等)在调用方法之前,调用方法之后,返回之后,抛出异常等时执行代码。
我想将它用于日志记录,这是一个非常典型的用例。我一直在看这篇文章,我认为这是我需要的大部分内容。它使用AspectJ以及" jcambi方面"执行记录。
但我想做类似以下的事情:
public void login(User user) {
String userType = user.getType();
if (!user.isActive()) {
// point cut 1 -- log inactive user
} else if (!user.isPasswordValid()) {
// point cut 2 -- log wrong password
} else {
// point cut 3 -- log successful login
}
}
我们有一个既定的日志格式。类似的东西:
<actor>|<action_code>|<error_code>|<extra_info>
所有Actor类型,操作和错误代码都包含在枚举中。
有没有办法告诉AspectJ:
记录&#39; ifs&#39;和 记录不同的信息,取决于发生了什么?例如,在切入点1中记录下列之一:
admin|login|001|Admin user inactive
user|login|001|Normal user inactive
...并在第2点中记录以下其中一项:
admin|login|002|Invalid Admin password
user|login|002|Invalid normal user password
...并在第3点中记录下列其中一项:
admin|login|000|Successful Admin login
user|login|000|Successful Normal user login
有些东西告诉我这是不可能的。或者至少不容易。但我不确定它是否值得尝试。所以我被撕裂了。一方面,我希望&#34;消毒&#34;我的所有日志记录的代码。另一方面,我不确定实施这项工作是否会花费太多。
有什么想法吗?
***************************************编辑******* *********
谢谢你们的回答!我现在意识到两件事:1。我在我之前做了很多工作。 2.我认为我过分强调&#34;登录&#34;示例
登录只是一个小用例。我的任务是在很多很多类中的一堆方法中添加无处不在的 ...基本上我在应用程序的任何地方看到LOG.debug()或LOG.info(),用Aspect日志替换它。这也意味着,尽管我喜欢,但我不能重构所有代码以使我的生活更轻松。我喜欢使用例外登录,但它超出了我的任务范围:添加日志记录。
当然,在每种方法中,业务逻辑都是不同的,因此,日志记录也是如此。所以我的问题变成了:做这个的最佳做法是什么?我的意思是,每个方法都有自己的逻辑,它的ifs ......并且会有条件地记录不同的东西。因此,我是否继续为这些用例中的每一个创建一个方面类,并且基本上具有相同的&#34; ifs&#34;那还有?
一个例子(没有登录!):一种导入数据的方法。
public void import(String type) {
if (type.equals("people")) {
try {
int result = importPeople();
if (result > 0) {
// do some stuff
LOG.info("ok");
} else {
// do some stuff
LOG.info("problem");
}
} catch (Exception e) {
// do some stuff
LOG.debug("exception ...");
}
} else if (type.equals("places")) {
try {
int result = importPlaces();
if (result > 0) {
// do some stuff
LOG.info("ok");
} else {
// do some stuff
LOG.info("problem");
}
} catch (Exception e) {
// do some stuff
LOG.debug("exception ...");
}
}
}
请注意,这是一个废话的例子,重复的代码等等。但是你明白了。我是否还应该创建一个&#34; import&#34;方面,用于记录此方法...所有随附的&#34; ifs&#34;记录&#34; ok&#34;,&#34;问题&#34;,&#34;例外&#34; ?并为每个用例执行此操作?
我全部都是为了摆脱侵入式日志记录代码,但是......似乎需要有一些代码气味,必须要有逻辑,以及它的&#34; ifs&#34;等等。在原始方法中(因为该方法是&#34;做更多的东西&#34;而不是记录)以及相应的方面......
无论如何,你们都回答了我原来的问题...但我只能有一个 的答案,所以我要接受kriegaex,因为他似乎有把很多的工作加入其中!
答案 0 :(得分:0)
它可能。 在login方法中创建一个切入点/内部并在方面类中获取用户对象,一旦获得User对象,就可以有条件地进行日志记录。 要获取用户对象,请查看以下已回答的问题以及它如何获得surveyId.Same的值,以获取User对象。
@Around("updateDate()"
public Object myAspect(final ProceedingJoinPoint pjp) {
//retrieve the runtime method arguments (dynamic)
Object returnVal = null;
for (final Object argument : pjp.getArgs())
{
if (argument instanceof SurveyHelper)
{
SurveyHelper surveyHelper = (SurveyHelper) argument;
surveyId = surveyHelper.getSurveyId();
}
}
try
{
returnVal = pjp.proceed();
}
catch (Throwable e)
{
gtLogger.debug("Unable to use JointPoint :(");
}
return returnVal;
}
以下是供您参考的完整链接: Spring AOP for database operation
答案 1 :(得分:0)
是的,有可能。但如果我是你,我会以不同的方式模拟整个故事。首先,由于未知或不活动的用户或错误的密码,我会抛出失败登录的异常。或者,login方法可以返回一个布尔值(成功登录时为true,否则为false)。但在我看来,这似乎是老式的C风格,而不是现代的OOP。
这是一个自洽的例子。抱歉,丑陋的UserDB
类有很多静态成员和方法。实际上,你不会存储明文密码,而是随机盐和盐渍哈希。但毕竟它只是基于方面的条件记录的概念证明。
用于登录的用户bean:
package de.scrum_master.app;
public class User {
private String id;
private String password;
public User(String id, String password) {
this.id = id;
this.password = password;
}
public String getId() {
return id;
}
public String getPassword() {
return password;
}
}
用户数据库:
为简单起见,有硬编码的DB条目,静态枚举,成员和方法以及静态内部类。抱歉!我希望你可以很容易地想象如何用更好的设计做同样的事情。
package de.scrum_master.app;
import java.util.HashMap;
import java.util.Map;
public class UserDB {
public static enum Role { admin, user, guest }
public static enum Action { login, logout, read, write }
public static enum Error { successful_login, user_inactive, invalid_password, unknown_user }
private static class UserInfo {
String password;
Role role;
boolean active;
public UserInfo(String password, Role role, boolean active) {
this.password = password;
this.role = role;
this.active = active;
}
}
private static Map<String, UserInfo> knownUsers = new HashMap<>();
static {
knownUsers.put("bruce", new UserInfo("alm1GHTy", Role.admin, true));
knownUsers.put("john", new UserInfo("LetMe_in", Role.user, true));
knownUsers.put("jane", new UserInfo("heLL0123", Role.guest, true));
knownUsers.put("richard", new UserInfo("dicky", Role.user, false));
knownUsers.put("martha", new UserInfo("paZZword", Role.admin, false));
}
public static class UserDBException extends Exception {
private static final long serialVersionUID = 7662809670014934460L;
public final String userId;
public final Role role;
public final Action action;
public final Error error;
public UserDBException(String userId, Role role, Action action, Error error, String message) {
super(message);
this.userId = userId;
this.role = role;
this.action = action;
this.error = error;
}
}
public static boolean isKnown(User user) {
return knownUsers.get(user.getId()) != null;
}
public static boolean isActive(User user) {
return isKnown(user) && knownUsers.get(user.getId()).active;
}
public static boolean isPasswordValid(User user) {
return isKnown(user) && knownUsers.get(user.getId()).password.equals(user.getPassword());
}
public static Role getRole(User user) {
return isKnown(user) ? knownUsers.get(user.getId()).role : null;
}
public static void login(User user) throws UserDBException {
String userId = user.getId();
if (!isKnown(user))
throw new UserDBException(
userId, getRole(user), Action.login,
Error.unknown_user, "Unknown user"
);
if (!isActive(user))
throw new UserDBException(
userId, getRole(user), Action.login,
Error.user_inactive, "Inactive " + getRole(user)
);
if (!isPasswordValid(user))
throw new UserDBException(
userId, getRole(user), Action.login,
Error.invalid_password, "Invalid " + getRole(user) + " password"
);
}
}
请注意login(User)
方法如何抛出异常,其中包含有助于记录的详细信息。
模拟多个用户/密码组合登录的驱动程序应用程序:
package de.scrum_master.app;
import java.util.Arrays;
import java.util.List;
public class Application {
public static void main(String[] args) {
List<User> users = Arrays.asList(
new User("mr_x", "foobar"),
new User("bruce", "foobar"),
new User("bruce", "alm1GHTy"),
new User("john", "foobar"),
new User("john", "LetMe_in"),
new User("jane", "foobar"),
new User("jane", "heLL0123"),
new User("richard", "foobar"),
new User("richard", "dicky"),
new User("martha", "foobar"),
new User("martha", "paZZword")
);
for (User user : users) {
try {
UserDB.login(user);
System.out.printf("%-8s -> %s%n", user.getId(), "Successful " + UserDB.getRole(user) + " login");
} catch (Exception e) {
System.out.printf("%-8s -> %s%n", user.getId(), e.getMessage());
}
}
}
}
请注意,我们只是捕获并记录所有异常,以避免在登录尝试失败后退出应用程序。
控制台日志:
mr_x -> Unknown user
bruce -> Invalid admin password
bruce -> Successful admin login
john -> Invalid user password
john -> Successful user login
jane -> Invalid guest password
jane -> Successful guest login
richard -> Inactive user
richard -> Inactive user
martha -> Inactive admin
martha -> Inactive admin
登录记录器方面:
我建议您先在System.out.printf(..)
中注释掉两个Application.main(..)
来电,以免将其与方面记录混合起来。
package de.scrum_master.aspect;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import de.scrum_master.app.User;
import de.scrum_master.app.UserDB;
import de.scrum_master.app.UserDB.Action;
import de.scrum_master.app.UserDB.Error;
import de.scrum_master.app.UserDB.UserDBException;
@Aspect
public class UserActionLogger {
@Around("execution(void de.scrum_master.app.UserDB.login(*)) && args(user)")
public void captureLogin(ProceedingJoinPoint thisJoinPoint, User user) throws Throwable {
try {
thisJoinPoint.proceed();
System.out.printf("%s|%s|%d03|%s%n",
user.getId(), Action.login, Error.successful_login.ordinal(),
"Successful " + UserDB.getRole(user) + " login"
);
} catch (UserDBException e) {
System.out.printf("%s|%s|%03d|%s%n",
e.userId, e.action, e.error.ordinal(),
e.getMessage()
);
throw e;
}
}
}
方面的控制台日志:
mr_x|login|003|Unknown user
bruce|login|002|Invalid admin password
bruce|login|003|Successful admin login
john|login|002|Invalid user password
john|login|003|Successful user login
jane|login|002|Invalid guest password
jane|login|003|Successful guest login
richard|login|001|Inactive user
richard|login|001|Inactive user
martha|login|001|Inactive admin
martha|login|001|Inactive admin
Etvoilà!我希望这大致是你想要的。