ProgramingTip

주석을 지향하는 Java Aspect 지향 프로그래밍

bestdevel 2020. 11. 28. 10:14
반응형

주석을 지향하는 Java Aspect 지향 프로그래밍


"AOP Fundamentals" 라는 제목의 게시물에서 AOP가 무엇인지, 무엇을하는지 King의 영어 설명을 요청 합니다. 나는 모든 이론에 대해 나를 채우는 데 도움이 매우 유용한 도움말 링크를 충족합니다.

이제 AOP가 내 모든 관심을 끌리는 모든 기사와 장 발췌문은 환상적이지만 모든 경우 에는 고상한 이론, 모호한 UML 모델 및 내 취향에 비해 너무 높은 그러나 순서로 구성됩니다.

여기에 AOP 이론에 대한 이해가 있습니다. 명확하게하기 위해 뭔가 잘못 보이면 알려주세요! :

  1. 로깅, 인증, 동기화, 유효성 검사, 예외 처리 같은 교차 절단 문제는 코드베이스의 거의 모든 구성 요소 / 모듈에서 보편적으로 사용되는 비 AOP 시스템에서 고도로 결합됩니다.

  2. AOP는 조인 포인트 , 어드바이스포인트-cut을 사용하여 이러한 교차 문제를 추상화하는 측면 (클래스 / 메소드)을 정의합니다 .

    ㅏ. 조언 -교차 절단 문제를 구현하는 실제 코드 (아마도 체계의 방법일까요?) (예 : 실제 로깅, 유효성 검사, 인증 등)

    비. Join Point- 특정 보장의 어드바이스가 실행 가능한 비 AOP 코드에서 트리거되는 이벤트 (비 AOP 코드에 "직조"됨)

    씨. Pointcut- 본질적으로 어드바이스 실행에 대한 조인 포인트 (트리거링 이벤트) 매핑

  3. 모든 구성 요소로 모듈화 (LoggingAspect, AuthenticationAspect, ValidationAspect 등)되고 AspectWeaver에 등록 됩니다. 비 AOP / POJO 코드가 조인 포인트를 만나면 AspectWeaver는 비 AOP 코드 주위에 매핑 된 어드바이스를 "위브"(통합)합니다.

공용 클래스 LoggingAspect
{
    // ...

    공개 무효 로그 (문자열 메시지) {...}
}

공용 클래스 ExceptionHandlingAspect
{
    // ..

    공개 무효 핸들 (예외 예외) {...}
}

공용 클래스 NonAOPCode
{
    // ...

    너 담아 가기
    공개 무효 foo ()
    {
        // 몇 가지 작업을 ...
    }
}

// 이제 드라이버에서
public static int main void (String [] args)
{
    NonAOPCode nonAOP = 새로운 NonAOPCode ();
    nonAOP.foo ();
}

// AspectWeaver는 * 마법처럼 * 메소드 호출을 짜낼 수 있으므로 main은 다음과 가능합니다.
{
    NonAOPCode nonAOP = 새로운 NonAOPCode ();

    로그 (someMsg);
    nonAOP.foo ();
    핸들 (someExc);
}

$ 64,000 질문 : Java 기반 AOP에 대한 이해가 목표에 도달 했습니까? 아니면 그 이유가 무엇입니까? 수 어떻게이 올바르게 측면을 구현하기 위해 주석을 사용, 조언, 포인트, 포인트 컷이 소위 측면 직조 가입?


@LogExecTime어노테이션을 사용하여 어노테이션이 있는 일부 메소드에 소요 된 시간을 기록하고 싶다고 가정 해봅시다 .

먼저 주석을 만듭니다 LogExecTime.

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface LogExecTime {

}

그런 다음 모든을 정의합니다.

@Component  // For Spring AOP
@Aspect
public class LogTimeAspect {
    @Around(value = "@annotation(annotation)")
    public Object LogExecutionTime(final ProceedingJoinPoint joinPoint, final LogExecTime annotation) throws Throwable {
        final long startMillis = System.currentTimeMillis();
        try {
            System.out.println("Starting timed operation");
            final Object retVal = joinPoint.proceed();
            return retVal;
        } finally {
            final long duration = System.currentTimeMillis() - startMillis;
            System.out.println("Call to " + joinPoint.getSignature() + " took " + duration + " ms");
        }

    }
}

주석이 달린 클래스를 만듭니다 LogExecTime.

@Component
public class Operator {

    @LogExecTime
    public void operate() throws InterruptedException {
        System.out.println("Performing operation");
        Thread.sleep(1000);
    }
}

그리고 Spring AOP를 사용하는 메인 :

public class SpringMain {

    public static void main(String[] args) throws InterruptedException {
        ApplicationContext context = new GenericXmlApplicationContext("applicationContext.xml");
        final Operator bean = context.getBean(Operator.class);
        bean.operate();
    }
}

이 클래스를 실행하면 stdout에 다음 출력이 표시됩니다.

Starting timed operation
Performing operation
Call to void testaop.Operator.Operate() took 1044 ms

이제 마술 과 함께 . AspectJ weaver가 아닌 Spring AOP를 사용하기 때문에 프록시 방식을 사용하여 작동에 마술이 발생합니다. 따라서 .class파일은 그대로 유지됩니다. 예를 들어이 프로그램을 디버그하고 중단 점을 제안면 operateSpring이 어떻게 마법을 수행했는지 알 수 있습니다.

디버그 스크린 샷

스프링 AOP은 구현 non-간섭 적 이며 스프링을 사용하므로 메커니즘 @Component주석 을 추가하고 또는 일반 대신 봄 컨텍스트를 사용하여 객체를 생성해야 합니다 new.

다른 쪽의 AspectJ는 .class파일 을 변경 합니다. AspectJ 로이 프로젝트를 시도하고 jad로 Operator 클래스를 디 테스트했습니다. 결과 :

public void operate()
    throws InterruptedException
{
    JoinPoint joinpoint = Factory.makeJP(ajc$tjp_0, this, this);
    operate_aroundBody1$advice(this, joinpoint, LogTimeAspect.aspectOf(), (ProceedingJoinPoint)joinpoint, (LogExecTime)(ajc$anno$0 == null && (ajc$anno$0 = testaop/Operator.getDeclaredMethod("operate", new Class[0]).getAnnotation(testaop/LogExecTime)) == null ? ajc$anno$0 : ajc$anno$0));
}

private static final void operate_aroundBody0(Operator ajc$this, JoinPoint joinpoint)
{
    System.out.println("Performing operation");
    Thread.sleep(1000L);
}

private static final Object operate_aroundBody1$advice(Operator ajc$this, JoinPoint thisJoinPoint, LogTimeAspect ajc$aspectInstance, ProceedingJoinPoint joinPoint, LogExecTime annotation)
{
    long startMillis = System.currentTimeMillis();
    Object obj;
    System.out.println("Starting timed operation");
    ProceedingJoinPoint proceedingjoinpoint = joinPoint;
    operate_aroundBody0(ajc$this, proceedingjoinpoint);
    Object retVal = null;
    obj = retVal;
    long duration = System.currentTimeMillis() - startMillis;
    System.out.println((new StringBuilder("Call to ")).append(joinPoint.getSignature()).append(" took ").append(duration).append(" ms").toString());
    return obj;
    Exception exception;
    exception;
    long duration = System.currentTimeMillis() - startMillis;
    System.out.println((new StringBuilder("Call to ")).append(joinPoint.getSignature()).append(" took ").append(duration).append(" ms").toString());
    throw exception;
}

private static void ajc$preClinit()
{
    Factory factory = new Factory("Operator.java", testaop/Operator);
    ajc$tjp_0 = factory.makeSJP("method-execution", factory.makeMethodSig("1", "operate", "testaop.Operator", "", "", "java.lang.InterruptedException", "void"), 5);
}

private static final org.aspectj.lang.JoinPoint.StaticPart ajc$tjp_0; /* synthetic field */
private static Annotation ajc$anno$0; /* synthetic field */

static 
{
    ajc$preClinit();
}

몇 달 전에 저는 Aspect / J 측면을 Java 주석과 결합하는 실제 사례를 구현 한 방법에 대한 예제가 포함 된 기사를 작성했습니다.

http://technomilk.wordpress.com/2010/11/06/combining-annotations-and-aspects-part-1/

나는 주석에 적용된 측면이 코드에서 측면을 더 명확하게 만들기 때문에 좋은 조합을 만든다고 생각하지만, 깔끔한 방식으로 주석에 매개 변수를 사용하여 더 많은 유연성을 얻을 수 있습니다.

Aspect / J가 작동하는 방식은 런타임이 아닌 컴파일 타임에 클래스를 수정하는 것입니다. Aspect / J 컴파일러를 통해 소스와 aspect를 실행하고 수정 된 클래스 파일을 생성합니다.

내가 이해하는 한 Spring AOP는 프록시 객체를 생성함으로써 다른 방식으로 위빙 (측면 처리를 포함하도록 클래스 파일 조작)을 수행합니다. 인스턴스화 시간에 (하지만 내 말을 받아들이지 마십시오) .


많이 파고 팔꿈치 기름을 바른 후 직접 답을 찾았습니다 ...

예, AOP는 Java 세계에서 주석 기반이어야하지만 일반 (메타 데이터) 주석과 같은 측면 관련 주석을 처리 할 수 ​​없습니다. 태그가 지정된 메서드 호출을 가로 채고 그 전후에 "위브"어드바이스 메서드를 가로 채려면 AspectJ와 같은 매우 멋진 AOP 중심 엔진의 도움이 필요합니다. @Christopher McCann은 다른 주석 관련 스레드에서 정말 멋진 솔루션을 제공했습니다. 그는 Google Guice와 함께 AOP Alliance를 사용할 것을 제안했습니다. AOP 지원에 대한 Guice의 문서를 읽은 후 바로 이것이 바로 제가 찾고있는 것입니다. 로깅, 유효성 검사, 캐싱, 캐싱, 기타

이것은 어리석은 일이었습니다.


댓글 변경

// The AspectWeaver *magically* might weave in method calls so main now becomes

...에

// The AspectWeaver *magically* might weave in method calls so main now
// becomes effectively (the .class file is not changed)

나는 AOP의 봄 글을 좋아한다. 7 장 확인


이 매우 유용한 게시물에 대한 저의 기여입니다.

아주 간단한 예를 들어 보겠습니다. 일부 메서드의 처리에 대해 조치를 취해야합니다. 처리 할 데이터가 포함 된 사용자 지정 주석으로 주석이 추가됩니다. 이 데이터가 주어지면 예외를 발생 시키거나 메서드에 주석이 추가되지 않은 것처럼 프로세스가 계속됩니다.

쉽게 정의하기위한 Java 코드 :

package com.example;

public class AccessDeniedForCustomAnnotatedMethodsAspect {

public Object checkAuthorizedAccess(ProceedingJoinPoint proceedingJointPoint)
throws Throwable {

    final MethodSignature methodSignature = (MethodSignature) proceedingJointPoint
                                            .getSignature();

    // how to get the method name
    final String methodName = methodSignature
                                            .getMethod()
                                            .getName();

    // how to get the parameter types
    final Class<?>[] parameterTypes = methodSignature
                                            .getMethod()
                                            .getParameterTypes();

    // how to get the annotations setted on the method
    Annotation[] declaredAnnotations = proceedingJointPoint
                                            .getTarget()
                                            .getClass()
                                            .getMethod(methodName, parameterTypes)
                                            .getDeclaredAnnotations();

    if (declaredAnnotations.length > 0) {

        for (Annotation declaredAnnotation : Arrays.asList(declaredAnnotations)) {

            // I just want to deal with the one that interests me
            if(declaredAnnotation instanceof CustomAnnotation) {

                // how to get the value contained in this annotation 
                (CustomAnnotation) declaredAnnotation).value()

                if(test not OK) {
                    throw new YourException("your exception message");
                }

                // triggers the rest of the method process
                return proceedingJointPoint.proceed();
           }
        }
    }
}

XML 구성 :

<aop:config>
    <aop:aspect id="accessDeniedForCustomAnnotatedMethods"
               ref="accessDeniedForCustomAnnotatedMethodsAspect">
        <aop:around pointcut="execution(@xxx.zzz.CustomAnnotation * *(..))"
               method="checkAuthorizedAccess" />
    </aop:aspect>
</aop:config>

<bean id="accessDeniedForCustomAnnotatedMethodsAspect"
   class="xxx.yyy.AccessDeniedForCustomAnnotatedMethodsAspect" />

도움이 되길 바랍니다!

참고 URL : https://stackoverflow.com/questions/4829088/java-aspect-oriented-programming-with-annotations

반응형