2016-09-16 7 views
0

Я довольно новичок в AspectJ и AOP в целом. Я знаю, что у AspectJ есть много аннотаций (After, AfterReturning и т. Д.) Для выполнения кода перед вызовом метода после его вызова после его возврата, когда возникает исключение и т. Д.Как использовать AspectJ для регистрации разных данных, условно?

Я бы хотел использовать это для ведения журнала, довольно типичный вариант использования. Я смотрел эту статью, и я думаю, что это большая часть того, что мне нужно. Он использует 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> 

Все типы действующих лиц, действия и коды ошибок содержатся в перечислениях.

Есть ли способ сказать AspectJ к:

войти в «если» и журнал отличается информация, в зависимости от того, что случилось? например, в точке вырезать 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 

... и в точке-вырезать журнал одно из следующего:

admin|login|000|Successful Admin login 
user|login|000|Successful Normal user login 

Что-то подсказывает мне, что это невозможно. Или, по крайней мере, нелегко. Но я не уверен, что это даже стоит попробовать. Поэтому я порван. С одной стороны, я хотел бы «дезинформировать» мой код всех протоколов. С другой стороны, я не уверен, что это будет слишком много, чтобы реализовать это.

Любые идеи?

*************************************** EDIT ****** *********************************

Благодарим вас обоих за ответы! Теперь я понимаю две вещи: 1. У меня впереди много работы. И 2. Думаю, я уделяю слишком много внимания примеру «входа».

Войти только один крошечный прецедент. Моя задача - добавить журнал всюду ... в кучу методов во многих, многих классах. В основном везде я вижу LOG.debug() или LOG.info() в любом месте приложения, чтобы заменить его регистрацией Aspect. Это также означает, что, насколько я бы хотел, я не могу просто реорганизовать весь код, чтобы облегчить мою жизнь. Я хотел бы использовать Исключения для входа в систему, но это выходит за рамки моей задачи: добавьте протоколирование.

И, конечно, в каждом методе бизнес-логика будет отличаться, и как таковой, так будет вести журнал. Поэтому мой вопрос: какова наилучшая практика? Я имею в виду, что каждый метод будет иметь свою собственную логику, ее ifs ... и будет регистрировать разные вещи условно. Итак, я продолжу и создаю класс аспект для каждого из этих вариантов использования и в основном имею то же самое «ifs» там?

Пример (это не логин!): Метод, который импортирует данные.

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 ..."); 
     } 
     } 
    } 

Помните, что это пример дерьма, с повторяющимся кодом и т. Д. Но вы получаете идею. Должен ли я также создать аспект «импорта» для регистрации этого метода ... со всеми сопровождающими «ifs» для регистрации «ok», «problem», «exception»? И сделать это для каждый прецедент?

Я все для того, чтобы избавиться от интрузивного кода регистрации, но ... похоже, что что-то вроде запаха кода, чтобы иметь логику с ее «ifs» и т. Д., Как в оригинальном методе (потому что метод «делать больше материала», чем в каротаже), а также в соответствующем аспекте ...

В любом случае, вы оба ответили на мой первоначальный вопрос ... но я могу только иметь 1 ответ, поэтому я Я собираюсь принять kriegaex, потому что он, кажется, положил лот работы в него!

+0

Извините, забыли добавить ссылку на статью: http://www.yegor256.com/2014/06/01/aop-aspectj-java-method-logging.html –

ответ

0

Да, это возможно. Но если бы я был вами, я бы по-разному моделировал всю историю. Прежде всего, я бы выбрал исключения для неудачных логинов из-за неизвестных или неактивных пользователей или неправильных паролей. Кроме того, метод login может возвращать логическое значение (true для успешного входа в систему, в противном случае - false). Но, на мой взгляд, это скорее старомодный стиль C, чем современный ООП.

Вот пример самосогласования. Извините за уродливый класс UserDB с множеством статических элементов и методов. И на самом деле вы не храните ясные текстовые пароли, а рандомизированные соли и соленые хеши. Но в конце концов это всего лишь доказательство концепции аспектного, условного ведения журнала.

боб пользователя используется для входа в систему:

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; 
    } 
} 

Баз данные пользователей:

Есть жестко закодированные записи БД, статические перечисления, члены и методы, а также статические внутренние классы для простоты ради. Сожалею! Вы можете легко представить, как сделать то же самое с лучшим дизайном, я надеюсь.

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 

вуаля! Я надеюсь, что это примерно то, что вы хотите.

0

Его возможно. Создайте метод определения точки/внутри круга и получите объект пользователя также в своем классе аспект, и как только вы получите объект User, вы можете выполнить регистрацию условно. Чтобы получить объект пользователя, пожалуйста, проверьте ниже ответ на вопрос и как он получил значение surveyId.Таким образом вы можете получить объект 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

 Смежные вопросы

  • Нет связанных вопросов^_^