Loading...
Spring Framework Reference Documentation 7.0.2의 Declaring a Pointcut의 한국어 번역본입니다.
아래의 경우에 피드백에서 신고해주신다면 반영하겠습니다.
감사합니다 :)
Pointcuts는 관심 있는 join point들을 결정하고, 이를 통해 advice가 언제 동작할지 제어할 수 있게 해줍니다. Spring AOP는 Spring beans에 대한 method execution join point만을 지원하므로, pointcut을 Spring beans에 대한 method execution을 매칭하는 것으로 생각할 수 있습니다. pointcut 선언은 두 부분으로 구성됩니다. 이름과 파라미터들로 구성된 signature와, 우리가 정확히 어떤 method execution들에 관심이 있는지를 결정하는 pointcut expression입니다.
@AspectJ annotation-style의 AOP에서, pointcut signature는 일반 method 정의로 제공되며, pointcut expression은 @Pointcut annotation을 사용하여 표시됩니다 (pointcut signature 역할을 하는 method는 void 반환 타입을 가져야 합니다).
예제는 pointcut signature와 pointcut expression 사이의 구분을 명확히 하는 데 도움이 될 수 있습니다. 다음 예제는 anyOldTransfer라는 이름의 pointcut을 정의하는데, 이는 이름이 transfer인 어떤 method의 execution과도 매칭됩니다:
1@Pointcut("execution(* transfer(..))") // the pointcut expression 2private void anyOldTransfer() {} // the pointcut signature
1@Pointcut("execution(* transfer(..))") // the pointcut expression 2private fun anyOldTransfer() {} // the pointcut signature
@Pointcut annotation의 값으로 구성되는 pointcut expression은 일반적인 AspectJ pointcut expression입니다. AspectJ의 pointcut 언어에 대한 전체 논의는 AspectJ Programming Guide (그리고 확장에 대해서는
AspectJ 5 Developer’s Notebook) 또는 Colyer 등 저자의 Eclipse AspectJ, Ramnivas Laddad의 _AspectJ in Action_과 같은 AspectJ 관련 서적을 참조하십시오.
Spring AOP는 pointcut expressions에서 사용할 수 있도록 다음과 같은 AspectJ pointcut designator(PCD)를 지원합니다:
execution: method execution join point를 매칭하기 위한 것입니다. Spring AOP를 사용할 때 기본적으로 사용하는 pointcut designator입니다.within: 특정 type들 내의 join point (Spring AOP를 사용할 때는 매칭되는 type 내에 선언된 method의 execution)를 대상으로 매칭을 제한합니다.this: bean reference (Spring AOP proxy)가 주어진 type의 인스턴스인 join point (Spring AOP를 사용할 때는 method execution)를 대상으로 매칭을 제한합니다.target: target object (proxy되는 application object)가 주어진 type의 인스턴스인 join point (Spring AOP를 사용할 때는 method execution)를 대상으로 매칭을 제한합니다.args: arguments가 주어진 type들의 인스턴스인 join point (Spring AOP를 사용할 때는 method execution)를 대상으로 매칭을 제한합니다.@target: 실행 중인 object의 class가 주어진 type의 annotation을 가진 join point (Spring AOP를 사용할 때는 method execution)를 대상으로 매칭을 제한합니다.@args: runtime 시점에 전달된 실제 arguments의 type들이 주어진 type들의 annotation을 가진 join point (Spring AOP를 사용할 때는 method execution)를 대상으로 매칭을 제한합니다.@within: 주어진 annotation을 가진 type들 내의 join point (Spring AOP를 사용할 때는 주어진 annotation을 가진 type들에 선언된 method의 execution)를 대상으로 매칭을 제한합니다.@annotation: join point의 대상 (Spring AOP에서 실행되는 method)이 주어진 annotation을 가진 join point만 매칭하도록 제한합니다.전체 AspectJ pointcut 언어는 Spring에서 지원되지 않는 추가 pointcut designator들을 지원합니다: call, get, set, preinitialization,
staticinitialization, initialization, handler, adviceexecution, withincode, cflow,
cflowbelow, if, @this, 그리고 @withincode. Spring AOP에 의해 해석되는 pointcut expressions에서 이러한 pointcut designator를 사용하면 IllegalArgumentException이 발생합니다.
Spring AOP에서 지원되는 pointcut designator 집합은 향후 릴리스에서 더 많은 AspectJ pointcut designator들을 지원하도록 확장될 수 있습니다.
Spring AOP는 method execution join point에만 매칭을 제한하기 때문에, 앞에서 설명한 pointcut designator에 대한 설명은 AspectJ programming guide에서 찾을 수 있는 정의보다 더 좁은 정의를 제공합니다. 추가로, AspectJ 자체는 type 기반 semantics를 가지며, execution join point에서 this와 target은 모두 동일한 object, 즉 method를 실행하는 object를 가리킵니다. Spring AOP는 proxy 기반 시스템이며, proxy object 자체 (this에 바인딩됨)와 proxy 뒤에 있는 target object (target에 바인딩됨)를 구분합니다.
Spring의 AOP framework가 proxy 기반이라는 특성 때문에, target object 내의 호출은 정의상 가로채지지 않습니다. JDK proxies의 경우, proxy에 대한 public interface method 호출만 가로챌 수 있습니다. CGLIB을 사용하면, proxy에 대한 public 및 protected method 호출(필요한 경우 package-visible method까지)도 가로챌 수 있습니다. 그러나, proxy를 통한 일반적인 상호작용은 항상 public signature를 통해 설계되어야 합니다. pointcut 정의는 일반적으로 가로채진 어떤 method에 대해서든 매칭된다는 점에 유의하십시오. pointcut이 CGLIB proxy 시나리오에서 proxy를 통한 잠재적인 non-public 상호작용이 있더라도 오직 public만을 대상으로 의도된 것이라면, 그에 맞게 정의되어야 합니다. interception 요구 사항에 target class 내의 method 호출이나 심지어 constructor까지 포함되는 경우, Spring의 proxy 기반 AOP framework 대신 Spring이 구동하는 native AspectJ weaving의 사용을 고려하십시오. 이는 서로 다른 특성을 가진 다른 모드의 AOP 사용 방식을 구성하므로, 결정을 내리기 전에 weaving에 대해 충분히 숙지해야 합니다.
Spring AOP는 bean이라는 추가 PCD도 지원합니다. 이 PCD를 사용하면 특정 이름의 Spring bean 또는 (wildcards를 사용할 때) 이름 집합에 대해 join point 매칭을 제한할 수 있습니다. bean PCD는 다음과 같은 형식을 가집니다:
1bean(idOrNameOfBean)
idOrNameOfBean 토큰은 어떤 Spring bean의 이름도 될 수 있습니다. * 문자를 사용하는 제한적인 wildcard 지원이 제공되므로, Spring beans에 대해 일부 naming convention을 설정해 두면, 이를 선택하기 위한 bean PCD expression을 작성할 수 있습니다. 다른 pointcut designator들과 마찬가지로, bean PCD는 && (and), || (or), ! (negation) 연산자와 함께 사용할 수도 있습니다.
beanPCD는 Spring AOP에서만 지원되며 native AspectJ weaving에서는 지원되지 않습니다. 이는 AspectJ가 정의하는 표준 PCD들에 대한 Spring 고유의 확장이며, 따라서@Aspectmodel로 선언된 aspect에서는 사용할 수 없습니다.beanPCD는 weaving 기반 AOP가 제한되는 type 수준만이 아니라 (Spring bean name 개념을 기반으로 하는) instance 수준에서 동작합니다. instance 기반 pointcut designator는 Spring의 proxy 기반 AOP framework와 Spring bean factory와의 긴밀한 통합이 제공하는 특별한 기능으로, 여기에서는 특정 bean들을 이름으로 식별하는 것이 자연스럽고 직관적입니다.
&&, ||, !을 사용하여 pointcut expressions를 결합할 수 있습니다. 또한 이름으로 pointcut expressions를 참조할 수도 있습니다. 다음 예제는 세 개의 pointcut expressions를 보여줍니다:
1package com.xyz; 2 3public class Pointcuts { 4 5 @Pointcut("execution(public * *(..))") 6 public void publicMethod() {} // (1) 7 8 @Pointcut("within(com.xyz.trading..*)") 9 public void inTrading() {} // (2) 10 11 @Pointcut("publicMethod() && inTrading()") 12 public void tradingOperation() {} // (3) 13}
| 1 | publicMethod는 method execution join point가 어떤 public method의 execution을 나타내는 경우 매칭됩니다. |
| 2 | inTrading은 method execution이 trading module에 있는 경우 매칭됩니다. |
| 3 | tradingOperation은 method execution이 trading module에 있는 어떤 public method를 나타내는 경우 매칭됩니다. |
1package com.xyz 2 3class Pointcuts { 4 5 @Pointcut("execution(public * *(..))") 6 fun publicMethod() {} // (1) 7 8 @Pointcut("within(com.xyz.trading..*)") 9 fun inTrading() {} // (2) 10 11 @Pointcut("publicMethod() && inTrading()") 12 fun tradingOperation() {} // (3) 13}
| 1 | publicMethod는 method execution join point가 어떤 public method의 execution을 나타내는 경우 매칭됩니다. |
| 2 | inTrading은 method execution이 trading module에 있는 경우 매칭됩니다. |
| 3 | tradingOperation은 method execution이 trading module에 있는 어떤 public method를 나타내는 경우 매칭됩니다. |
위에서 보인 것처럼, 더 복잡한 pointcut expressions를 더 작은 named pointcuts 로부터 구성하는 것이 모범 사례입니다. 이름으로 pointcuts를 참조할 때는 일반 Java visibility 규칙이 적용됩니다 (private pointcuts는 같은 type에서, protected pointcuts는 계층 구조에서, public pointcuts는 어디에서나 볼 수 있음 등). visibility는 pointcut 매칭에 영향을 미치지 않습니다.
enterprise applications에서 작업할 때, 개발자는 여러 aspects 내에서 application의 modules와 특정 operation 집합을 참조해야 할 필요가 자주 있습니다. 이러한 목적을 위해 일반적으로 사용되는 named pointcut expressions를 캡처하는 전용 class를 정의하는 것이 좋습니다. 이러한 class는 일반적으로 다음의 CommonPointcuts 예제와 유사합니다 (class 이름은 자유롭게 정할 수 있습니다):
1package com.xyz; 2 3import org.aspectj.lang.annotation.Pointcut; 4 5public class CommonPointcuts { 6 7 /** 8 * A join point is in the web layer if the method is defined 9 * in a type in the com.xyz.web package or any sub-package 10 * under that. 11 */ 12 @Pointcut("within(com.xyz.web..*)") 13 public void inWebLayer() {} 14 15 /** 16 * A join point is in the service layer if the method is defined 17 * in a type in the com.xyz.service package or any sub-package 18 * under that. 19 */ 20 @Pointcut("within(com.xyz.service..*)") 21 public void inServiceLayer() {} 22 23 /** 24 * A join point is in the data access layer if the method is defined 25 * in a type in the com.xyz.dao package or any sub-package 26 * under that. 27 */ 28 @Pointcut("within(com.xyz.dao..*)") 29 public void inDataAccessLayer() {} 30 31 /** 32 * A business service is the execution of any method defined on a service 33 * interface. This definition assumes that interfaces are placed in the 34 * "service" package, and that implementation types are in sub-packages. 35 * 36 * If you group service interfaces by functional area (for example, 37 * in packages com.xyz.abc.service and com.xyz.def.service) then 38 * the pointcut expression "execution(* com.xyz..service.*.*(..))" 39 * could be used instead. 40 * 41 * Alternatively, you can write the expression using the 'bean' 42 * PCD, like so "bean(*Service)". (This assumes that you have 43 * named your Spring service beans in a consistent fashion.) 44 */ 45 @Pointcut("execution(* com.xyz..service.*.*(..))") 46 public void businessService() {} 47 48 /** 49 * A data access operation is the execution of any method defined on a 50 * DAO interface. This definition assumes that interfaces are placed in the 51 * "dao" package, and that implementation types are in sub-packages. 52 */ 53 @Pointcut("execution(* com.xyz.dao.*.*(..))") 54 public void dataAccessOperation() {} 55 56}
1package com.xyz 2 3import org.aspectj.lang.annotation.Pointcut 4 5class CommonPointcuts { 6 7 /** 8 * A join point is in the web layer if the method is defined 9 * in a type in the com.xyz.web package or any sub-package 10 * under that. 11 */ 12 @Pointcut("within(com.xyz.web..*)") 13 fun inWebLayer() {} 14 15 /** 16 * A join point is in the service layer if the method is defined 17 * in a type in the com.xyz.service package or any sub-package 18 * under that. 19 */ 20 @Pointcut("within(com.xyz.service..*)") 21 fun inServiceLayer() {} 22 23 /** 24 * A join point is in the data access layer if the method is defined 25 * in a type in the com.xyz.dao package or any sub-package 26 * under that. 27 */ 28 @Pointcut("within(com.xyz.dao..*)") 29 fun inDataAccessLayer() {} 30 31 /** 32 * A business service is the execution of any method defined on a service 33 * interface. This definition assumes that interfaces are placed in the 34 * "service" package, and that implementation types are in sub-packages. 35 * 36 * If you group service interfaces by functional area (for example, 37 * in packages com.xyz.abc.service and com.xyz.def.service) then 38 * the pointcut expression "execution(* com.xyz..service.*.*(..))" 39 * could be used instead. 40 * 41 * Alternatively, you can write the expression using the 'bean' 42 * PCD, like so "bean(*Service)". (This assumes that you have 43 * named your Spring service beans in a consistent fashion.) 44 */ 45 @Pointcut("execution(* com.xyz..service.*.*(..))") 46 fun businessService() {} 47 48 /** 49 * A data access operation is the execution of any method defined on a 50 * DAO interface. This definition assumes that interfaces are placed in the 51 * "dao" package, and that implementation types are in sub-packages. 52 */ 53 @Pointcut("execution(* com.xyz.dao.*.*(..))") 54 fun dataAccessOperation() {} 55 56}
이러한 class에 정의된 pointcuts는 pointcut expression이 필요한 어디에서든, class의 fully-qualified name과 @Pointcut method 이름을 조합하여 참조할 수 있습니다. 예를 들어, service layer를 transactional하게 만들기 위해, 다음과 같이 작성할 수 있으며, 이는 com.xyz.CommonPointcuts.businessService() _named pointcut_을 참조합니다:
1<aop:config> 2 <aop:advisor 3 pointcut="com.xyz.CommonPointcuts.businessService()" 4 advice-ref="tx-advice"/> 5</aop:config> 6 7<tx:advice id="tx-advice"> 8 <tx:attributes> 9 <tx:method name="*" propagation="REQUIRED"/> 10 </tx:attributes> 11</tx:advice>
<aop:config> 및 <aop:advisor> element는 Schema-based AOP Support에서 설명합니다. transaction element는 Transaction Management에서 설명합니다.
Spring AOP 사용자는 execution pointcut designator를 가장 자주 사용하게 될 가능성이 높습니다. execution expression의 형식은 다음과 같습니다:
1execution(modifiers-pattern? 2 ret-type-pattern 3 declaring-type-pattern?name-pattern(param-pattern) 4 throws-pattern?)
반환 타입 패턴(ret-type-pattern in the preceding snippet), 이름 패턴, 파라미터 패턴을 제외한 모든 부분은 선택 사항입니다. 반환 타입 패턴은 join point가 매칭되기 위해 method의 반환 타입이 무엇이어야 하는지를 결정합니다. 반환 타입 패턴으로는 *가 가장 자주 사용됩니다. 이는 어떤 반환 타입이든 매칭합니다.
완전 수식된 type 이름은 method가 주어진 type을 반환할 때만 매칭됩니다. 이름 패턴은 method 이름을 매칭합니다. 이름 패턴 전체 또는 일부로 * wildcard를 사용할 수 있습니다. declaring type 패턴을 지정하는 경우, 이름 패턴 component와 결합하기 위해 끝에 .을 포함하십시오.
parameters 패턴은 약간 더 복잡합니다: ()는 파라미터가 없는 method를 매칭하는 반면, (..)는 파라미터 개수에 상관없이 (0개 이상) 매칭합니다. (*) 패턴은 어떤 type이든 하나의 파라미터를 받는 method를 매칭합니다. (*,String)은 두 개의 파라미터를 받는 method를 매칭합니다. 첫 번째는 어떤 type이든 될 수 있지만, 두 번째는 반드시 String이어야 합니다. 자세한 내용은 AspectJ Programming Guide의
Language Semantics 섹션을 참조하십시오.
다음 예제는 일반적인 pointcut expressions를 보여줍니다:
1execution(public * *(..))
set으로 시작하는 어떤 method의 execution:1execution(* set*(..))
AccountService interface에 의해 정의된 어떤 method의 execution:1execution(* com.xyz.service.AccountService.*(..))
service package에 정의된 어떤 method의 execution:1execution(* com.xyz.service.*.*(..))
1execution(* com.xyz.service..*.*(..))
1within(com.xyz.service.*)
1within(com.xyz.service..*)
AccountService interface를 구현하는 어떤 join point (Spring AOP에서는 method execution만 해당):1this(com.xyz.service.AccountService)
this는 binding form에서 더 일반적으로 사용됩니다. advice body에서 proxy object를 사용 가능하게 만드는 방법은 Declaring Advice 섹션을 참조하십시오.
AccountService interface를 구현하는 어떤 join point (Spring AOP에서는 method execution만 해당):1target(com.xyz.service.AccountService)
target은 binding form에서 더 일반적으로 사용됩니다. advice body에서 target object를 사용 가능하게 만드는 방법은 Declaring Advice 섹션을 참조하십시오.
Serializable인 어떤 join point (Spring AOP에서는 method execution만 해당):1args(java.io.Serializable)
args는 binding form에서 더 일반적으로 사용됩니다. advice body에서 method arguments를 사용 가능하게 만드는 방법은 Declaring Advice 섹션을 참조하십시오.
이 예제에서 제시된 pointcut은 execution(* *(java.io.Serializable))과 다르다는 점에 유의하십시오. args 버전은 runtime에 전달된 argument가 Serializable인 경우 매칭되고, execution 버전은 method signature가 type이 Serializable인 하나의 파라미터를 선언하는 경우 매칭됩니다.
@Transactional annotation이 있는 어떤 join point (Spring AOP에서는 method execution만 해당):1@target(org.springframework.transaction.annotation.Transactional)
@target도 binding form에서 사용할 수 있습니다. advice body에서 annotation object를 사용 가능하게 만드는 방법은 Declaring Advice 섹션을 참조하십시오.
@Transactional annotation이 있는 어떤 join point (Spring AOP에서는 method execution만 해당):1@within(org.springframework.transaction.annotation.Transactional)
@within도 binding form에서 사용할 수 있습니다. advice body에서 annotation object를 사용 가능하게 만드는 방법은 Declaring Advice 섹션을 참조하십시오.
@Transactional annotation이 있는 어떤 join point (Spring AOP에서는 method execution만 해당):1@annotation(org.springframework.transaction.annotation.Transactional)
@annotation도 binding form에서 사용할 수 있습니다. advice body에서 annotation object를 사용 가능하게 만드는 방법은 Declaring Advice 섹션을 참조하십시오.
@Classified annotation이 있는 어떤 join point (Spring AOP에서는 method execution만 해당):1@args(com.xyz.security.Classified)
@args도 binding form에서 사용할 수 있습니다. advice body에서 annotation object(s)를 사용 가능하게 만드는 방법은 Declaring Advice 섹션을 참조하십시오.
tradeService인 Spring bean에 대한 어떤 join point (Spring AOP에서는 method execution만 해당):1bean(tradeService)
*Service와 매칭되는 Spring beans에 대한 어떤 join point (Spring AOP에서는 method execution만 해당):1bean(*Service)
컴파일 중에 AspectJ는 매칭 성능을 최적화하기 위해 pointcuts를 처리합니다. 코드와 각 join point가 주어진 pointcut에 (정적 또는 동적) 매칭되는지 여부를 판단하는 것은 비용이 많이 드는 과정입니다. (동적 매칭은 정적 분석만으로는 매칭 여부를 완전히 결정할 수 없고, 코드 실행 시 실제 매칭 여부를 판단하기 위한 테스트가 코드에 삽입되는 경우를 의미합니다). pointcut 선언을 처음 접할 때, AspectJ는 매칭 프로세스를 위한 최적의 형태로 이를 다시 작성합니다.
이것은 무엇을 의미합니까? 기본적으로 pointcuts는 DNF(Disjunctive Normal Form)로 다시 작성되며, 평가 비용이 더 저렴한 component들이 먼저 확인되도록 pointcut의 component들이 정렬됩니다. 이는 다양한 pointcut designator의 성능을 이해하는 것에 대해 걱정할 필요가 없으며, pointcut 선언에서 어떤 순서로든 제공할 수 있음을 의미합니다.
그러나 AspectJ는 전달받은 정보로만 작업할 수 있습니다. 매칭 성능을 최적화하기 위해, 무엇을 달성하려는지 생각하고 정의에서 가능한 한 매칭을 위한 검색 범위를 좁혀야 합니다. 기존 designator들은 자연스럽게 세 가지 그룹 중 하나에 속합니다: kinded, scoping, contextual:
execution, get, set, call, 그리고 handler.within 및 withincodethis, target, 그리고 @annotation잘 작성된 pointcut은 최소한 처음 두 종류(kinded와 scoping)를 포함해야 합니다. join point context에 기반하여 매칭하거나 advice에서 사용할 수 있도록 그 context를 바인딩하기 위해 contextual designators를 포함할 수 있습니다. kinded designator만 또는 contextual designator만 제공해도 동작하지만, 추가 처리와 분석으로 인해 weaving 성능(소요 시간과 메모리 사용량)에 영향을 줄 수 있습니다. scoping designators는 매칭이 매우 빠르며, 이를 사용하면 AspectJ가 더 이상 처리하지 말아야 할 join point 집합을 매우 빠르게 제외할 수 있습니다. 가능한 경우 좋은 pointcut에는 항상 하나 이상의 scoping designator가 포함되어야 합니다.
Broadcom과 제3자 파트너는 사이트 사용 분석, 사용자 경험 개선, 광고 지원 등의 목적을 포함하여 기술(쿠키 포함)을 사용합니다. 당사 사이트를 사용함으로써, 귀하는 Cookie Notice에 설명된 대로 쿠키 사용에 동의하는 것입니다.
Allow All
Required Only
Cookies Settings

Privacy Policy에 설정된 대로 Broadcom과 상호작용하여 어떤 website를 방문할 때, 해당 website는 대부분 cookies의 형태로 browser에 정보를 저장하거나 검색할 수 있습니다. 이 정보는 귀하, 귀하의 환경설정 또는 귀하의 device에 관한 것일 수 있으며, 대부분 사이트가 예상대로 작동하도록 하기 위해 사용됩니다. 이 정보는 일반적으로 귀하를 직접 식별하지는 않지만, 보다 개인화된 web 경험을 제공할 수 있습니다.
Always Active
이러한 cookies는 website가 기능하기 위해 필요하며 Broadcom의 systems에서 꺼질 수 없습니다. 일반적으로 귀하가 privacy 환경설정 설정, 로그인, form 작성 등 서비스 요청에 해당하는 작업을 수행할 때에만 설정됩니다. browser를 설정하여 이러한 cookies를 차단하거나 이에 대해 경고를 표시할 수 있지만, 그러면 사이트의 일부가 작동하지 않습니다. 이러한 cookies는 개인을 식별할 수 있는 어떤 정보도 저장하지 않습니다.
Performance Cookies
이러한 cookies는 Broadcom이 방문 횟수와 트래픽 출처를 집계할 수 있도록 하여, Broadcom이 사이트의 성능을 측정하고 개선할 수 있게 해줍니다. 이 cookies는 Broadcom이 어떤 페이지가 가장 인기 있고 가장 인기가 없는지, 그리고 방문자가 사이트 주변을 어떻게 이동하는지 알 수 있도록 도와줍니다. 이 cookies가 수집하는 모든 정보는 집계되며 따라서 익명입니다. 이 cookies를 허용하지 않으면, Broadcom은 귀하가 사이트를 방문했을 때를 알 수 없으며, 사이트의 성능을 모니터링할 수 없습니다.
Targeting Cookies
이러한 cookies는 Broadcom의 사이트를 통해 Broadcom의 광고 파트너에 의해 설정될 수 있습니다. 이 cookies는 해당 회사들이 귀하의 관심사 profile을 구축하고 다른 사이트에서 관련 광고를 표시하는 데 사용할 수 있습니다. 이 cookies는 직접적으로 개인 정보를 저장하지 않지만, 귀하의 browser와 internet device를 고유하게 식별하는 데 기반합니다. 이러한 cookies를 허용하지 않으면, 보다 덜 타겟팅된 광고를 보게 됩니다.
Back Button
Filter Button
ConsentLeg.Interest
Clear
Apply Cancel
Confirm My Choices
Required Only Allow All
Declaring an Aspect
Declaring Advice