주석을 지향하는 Java Aspect 지향 프로그래밍
"AOP Fundamentals" 라는 제목의 게시물에서 AOP가 무엇인지, 무엇을하는지 King의 영어 설명을 요청 합니다. 나는 모든 이론에 대해 나를 채우는 데 도움이 매우 유용한 도움말 링크를 충족합니다.
이제 AOP가 내 모든 관심을 끌리는 모든 기사와 장 발췌문은 환상적이지만 모든 경우 에는 고상한 이론, 모호한 UML 모델 및 내 취향에 비해 너무 높은 그러나 순서로 구성됩니다.
여기에 AOP 이론에 대한 이해가 있습니다. 명확하게하기 위해 뭔가 잘못 보이면 알려주세요! :
로깅, 인증, 동기화, 유효성 검사, 예외 처리 같은 교차 절단 문제는 코드베이스의 거의 모든 구성 요소 / 모듈에서 보편적으로 사용되는 비 AOP 시스템에서 고도로 결합됩니다.
AOP는 조인 포인트 , 어드바이스 및 포인트-cut을 사용하여 이러한 교차 문제를 추상화하는 측면 (클래스 / 메소드)을 정의합니다 .
ㅏ. 조언 -교차 절단 문제를 구현하는 실제 코드 (아마도 체계의 방법일까요?) (예 : 실제 로깅, 유효성 검사, 인증 등)
비. Join Point- 특정 보장의 어드바이스가 실행 가능한 비 AOP 코드에서 트리거되는 이벤트 (비 AOP 코드에 "직조"됨)
씨. Pointcut- 본질적으로 어드바이스 실행에 대한 조인 포인트 (트리거링 이벤트) 매핑
모든 구성 요소로 모듈화 (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
파일은 그대로 유지됩니다. 예를 들어이 프로그램을 디버그하고 중단 점을 제안면 operate
Spring이 어떻게 마법을 수행했는지 알 수 있습니다.
스프링 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
'ProgramingTip' 카테고리의 다른 글
혼자 개발자로서 Mercurial을 어떻게 사용합니까? (0) | 2020.11.28 |
---|---|
자바 프로그래머로서 무엇을 찾아야합니까? (0) | 2020.11.28 |
모바일 앱용 NoSQL? (0) | 2020.11.28 |
Git 저장소 손상 (모형 헤더 검사, 자극 개체 손상) (0) | 2020.11.28 |
C / C ++ 소스 코드? (0) | 2020.11.28 |