2017-01-18 2 views
0

У нас есть большая база кода, которая была разработана в Spring MVC. Следующий код повторяется повсюду.Рефакторинг исключений в аспект?

public @ResponseBody BaseResponse<String> getSomething() { 
    BaseResponse<String> response = new BaseResponse<String>(); 
    try { 
     //something 
    } catch (Exception e) { 
     BaseError be = ExceptionHandler.errorResponse(e); 
     response.setError(be); 
    } 
    return response; 
} 

Мне любопытно, если это можно реорганизовать или упростить с помощью аспектов?

ie: ExceptionHandler можно вызывать в рамках аспекта, но как насчет установки ошибки в ответ?

Спасибо.

+0

Если вы используете Java8, я бы сделал это с помощью вспомогательного метода, использующего лямбду, это минимальные накладные расходы как в коде, так и во время выполнения, и не нуждается в новой зависимости, такой как AspectJ. Если вы используете Java7 или меньше, AspectJ может быть вариантом, использование 'around()' advice - типичный пример учебника для вашего варианта использования. –

+0

Использование JDK 6. заглянет в ваш совет – DarthVader

ответ

1

Я воссоздал вашу ситуацию с простой Java + родной AspectJ, потому что я не пользователь Spring. Но аспект как таковой и его pointcut должны быть одинаковыми в Spring AOP, только аспект также должен быть @Component.

Несколько холостые классы:

package de.scrum_master.app; 

import java.lang.annotation.ElementType; 
import java.lang.annotation.Retention; 
import java.lang.annotation.RetentionPolicy; 
import java.lang.annotation.Target; 

@Retention(RetentionPolicy.RUNTIME) 
@Target(ElementType.METHOD) 
public @interface ResponseBody {} 
package de.scrum_master.app; 

public class BaseError { 
    private Exception e; 

    public BaseError(Exception e) { 
     this.e= e; 
    } 

    public String getMessage() { 
     return e.getMessage(); 
    } 
} 
package de.scrum_master.app; 

public class ExceptionHandler { 
    public static BaseError errorResponse(Exception e) { 
     return new BaseError(e); 
    } 
} 
package de.scrum_master.app; 

public class BaseResponse<T> { 
    private String body; 
    private String error = "OK"; 

    public void setBody(String body) { 
     this.body = body; 
    } 

    public void setError(BaseError be) { 
     error = be.getMessage(); 
    } 

    @Override 
    public String toString() { 
     return "BaseResponse [body=" + body + ", error=" + error + "]"; 
    } 
} 

приложение Driver:

Есть две целевые методы, возвращающие BaseResponse<String>, в основном DOI ng то же, что и ваш метод, исключая случайные исключения, но с обработкой исключений. Наверное, это то, чего вы хотите достичь.

Существует также метод анотера, который не должен быть нацелен на аспект (в качестве отрицательного тестового примера).

package de.scrum_master.app; 

import java.util.Random; 

public class Application { 
    private static final Random RANDOM = new Random(); 

    public static void main(String[] args) { 
     Application application = new Application(); 
     for (int i = 0; i < 5; i++) { 
      System.out.println(application.doSomething()); 
      System.out.println(application.getSomething()); 
      System.out.println(application.getSomethingElse()); 
     } 
    } 

    public String doSomething() { 
     return "Doing something"; 
    } 

    public @ResponseBody BaseResponse<String> getSomething() { 
     BaseResponse<String> response = new BaseResponse<String>(); 
     if (RANDOM.nextBoolean()) 
      throw new RuntimeException("cannot get something"); 
     response.setBody("getting something"); 
     return response; 
    } 

    public @ResponseBody BaseResponse<String> getSomethingElse() { 
     BaseResponse<String> response = new BaseResponse<String>(); 
     if (RANDOM.nextBoolean()) 
      throw new RuntimeException("cannot get something else"); 
     response.setBody("getting something else"); 
     return response; 
    } 
} 

Ошибка аспект обработки:

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.BaseError; 
import de.scrum_master.app.BaseResponse; 
import de.scrum_master.app.ExceptionHandler; 

@Aspect 
public class ErrorHandler { 
    @Around("execution(de.scrum_master.app.BaseResponse<String> *(..))") 
    public Object handleError(ProceedingJoinPoint thisJoinPoint) throws Throwable { 
     //System.out.println(thisJoinPoint); 
     try { 
      return thisJoinPoint.proceed(); 
     } catch (Exception e) { 
      BaseError be = ExceptionHandler.errorResponse(e); 
      BaseResponse<String> response = new BaseResponse<String>(); 
      response.setBody("uh-oh!"); 
      response.setError(be); 
      return response; 
     } 
    } 
} 

консоли журнала:

Здесь вы можете увидеть красиво, как каждый BaseResponse либо создается и заполняется кодом приложения промывать или ошибкой обрабатывающий аспект:

Doing something 
BaseResponse [body=getting something, error=OK] 
BaseResponse [body=uh-oh!, error=cannot get something else] 
Doing something 
BaseResponse [body=uh-oh!, error=cannot get something] 
BaseResponse [body=getting something else, error=OK] 
Doing something 
BaseResponse [body=getting something, error=OK] 
BaseResponse [body=getting something else, error=OK] 
Doing something 
BaseResponse [body=getting something, error=OK] 
BaseResponse [body=getting something else, error=OK] 
Doing something 
BaseResponse [body=getting something, error=OK] 
BaseResponse [body=uh-oh!, error=cannot get something else] 
+0

Большое спасибо за ваши усилия. Я это одобряю. Только быстрый вопрос, который у меня есть, у нас есть тот же дизайн. Будет ли BaseResponse работать в этом случае для аспекта? – DarthVader

+0

Нет, это было бы нелогично. Вне определения класса вы не можете использовать общие переменные типа, известные только внутри. Если вы хотите сопоставить все базовые ответы, используйте «BaseResponse» или, если хотите, «BaseResponse <*>'. В качестве альтернативы, сделайте свой аспект общим, если вы видите в нем какое-либо значение. Но тогда вы должны объявить его «абстрактным» и создать конкретные подклассы, такие как «@Aspect public class StringErrorHandler extends ErrorHandler {}' – kriegaex

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