diff --git a/framework-docs/src/docs/asciidoc/core/core-aop.adoc b/framework-docs/src/docs/asciidoc/core/core-aop.adoc index 94d14ce67f..e3289f5808 100644 --- a/framework-docs/src/docs/asciidoc/core/core-aop.adoc +++ b/framework-docs/src/docs/asciidoc/core/core-aop.adoc @@ -233,7 +233,7 @@ classpath of your application (version 1.9 or later). This library is available To enable @AspectJ support with Java `@Configuration`, add the `@EnableAspectJAutoProxy` annotation, as the following example shows: -[source,java,indent=0,subs="verbatim,quotes",role="primary"] +[source,java,indent=0,subs="verbatim",role="primary"] .Java ---- @Configuration @@ -241,7 +241,7 @@ annotation, as the following example shows: public class AppConfig { } ---- -[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] +[source,kotlin,indent=0,subs="verbatim",role="secondary"] .Kotlin ---- @Configuration @@ -255,7 +255,7 @@ annotation, as the following example shows: To enable @AspectJ support with XML-based configuration, use the `aop:aspectj-autoproxy` element, as the following example shows: -[source,xml,indent=0,subs="verbatim,quotes"] +[source,xml,indent=0,subs="verbatim"] ---- ---- @@ -278,9 +278,9 @@ minimal steps required for a not-very-useful aspect. The first of the two examples shows a regular bean definition in the application context that points to a bean class that is annotated with `@Aspect`: -[source,xml,indent=0,subs="verbatim,quotes"] +[source,xml,indent=0,subs="verbatim"] ---- - + ---- @@ -288,10 +288,10 @@ that points to a bean class that is annotated with `@Aspect`: The second of the two examples shows the `NotVeryUsefulAspect` class definition, which is annotated with `@Aspect`: -[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages",fold="none"] +[source,java,indent=0,subs="verbatim",role="primary",chomp="-packages",fold="none"] .Java ---- - package org.xyz; + package com.xyz; import org.aspectj.lang.annotation.Aspect; @@ -299,10 +299,10 @@ annotated with `@Aspect`: public class NotVeryUsefulAspect { } ---- -[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages",fold="none"] +[source,kotlin,indent=0,subs="verbatim",role="secondary",chomp="-packages",fold="none"] .Kotlin ---- - package org.xyz + package com.xyz import org.aspectj.lang.annotation.Aspect @@ -346,13 +346,13 @@ An example may help make this distinction between a pointcut signature and a poi expression clear. The following example defines a pointcut named `anyOldTransfer` that matches the execution of any method named `transfer`: -[source,java,indent=0,subs="verbatim,quotes",role="primary"] +[source,java,indent=0,subs="verbatim",role="primary"] .Java ---- @Pointcut("execution(* transfer(..))") // the pointcut expression private void anyOldTransfer() {} // the pointcut signature ---- -[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] +[source,kotlin,indent=0,subs="verbatim",role="secondary"] .Kotlin ---- @Pointcut("execution(* transfer(..))") // the pointcut expression @@ -440,7 +440,7 @@ Spring AOP also supports an additional PCD named `bean`. This PCD lets you limit the matching of join points to a particular named Spring bean or to a set of named Spring beans (when using wildcards). The `bean` PCD has the following form: -[source,indent=0,subs="verbatim,quotes"] +[source,indent=0,subs="verbatim"] ---- bean(idOrNameOfBean) ---- @@ -471,37 +471,49 @@ it is natural and straightforward to identify specific beans by name. You can combine pointcut expressions by using `&&,` `||` and `!`. You can also refer to pointcut expressions by name. The following example shows three pointcut expressions: -[source,java,indent=0,subs="verbatim,quotes",role="primary"] +[source,java,indent=0,subs="verbatim",role="primary",chomp="-packages"] .Java ---- - @Pointcut("execution(public * \*(..))") - private void anyPublicOperation() {} // <1> + package com.xyz; - @Pointcut("within(com.xyz.myapp.trading..*)") - private void inTrading() {} // <2> + @Aspect + public class Pointcuts { - @Pointcut("anyPublicOperation() && inTrading()") - private void tradingOperation() {} // <3> + @Pointcut("execution(public * *(..))") + public void publicMethod() {} // <1> + + @Pointcut("within(com.xyz.trading..*)") + public void inTrading() {} // <2> + + @Pointcut("publicMethod() && inTrading()") + public void tradingOperation() {} // <3> + } ---- -<1> `anyPublicOperation` matches if a method execution join point represents the execution +<1> `publicMethod` matches if a method execution join point represents the execution of any public method. <2> `inTrading` matches if a method execution is in the trading module. <3> `tradingOperation` matches if a method execution represents any public method in the trading module. -[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] +[source,kotlin,indent=0,subs="verbatim",role="secondary",chomp="-packages"] .Kotlin ---- - @Pointcut("execution(public * \*(..))") - private fun anyPublicOperation() {} // <1> + package com.xyz - @Pointcut("within(com.xyz.myapp.trading..*)") - private fun inTrading() {} // <2> + @Aspect + class Pointcuts { - @Pointcut("anyPublicOperation() && inTrading()") - private fun tradingOperation() {} // <3> + @Pointcut("execution(public * *(..))") + fun publicMethod() {} // <1> + + @Pointcut("within(com.xyz.trading..*)") + fun inTrading() {} // <2> + + @Pointcut("publicMethod() && inTrading()") + fun tradingOperation() {} // <3> + } ---- -<1> `anyPublicOperation` matches if a method execution join point represents the execution +<1> `publicMethod` matches if a method execution join point represents the execution of any public method. <2> `inTrading` matches if a method execution is in the trading module. <3> `tradingOperation` matches if a method execution represents any public method in the @@ -523,10 +535,10 @@ We recommend defining a dedicated aspect that captures commonly used _named poin expressions for this purpose. Such an aspect typically resembles the following `CommonPointcuts` example (though what you name the aspect is up to you): -[source,java,indent=0,subs="verbatim",role="primary",chomp="-packages"] +[source,java,indent=0,subs="verbatim",role="primary",chomp="-packages",fold="none"] .Java ---- - package com.xyz.myapp; + package com.xyz; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; @@ -536,26 +548,26 @@ expressions for this purpose. Such an aspect typically resembles the following /** * A join point is in the web layer if the method is defined - * in a type in the com.xyz.myapp.web package or any sub-package + * in a type in the com.xyz.web package or any sub-package * under that. */ - @Pointcut("within(com.xyz.myapp.web..*)") + @Pointcut("within(com.xyz.web..*)") public void inWebLayer() {} /** * A join point is in the service layer if the method is defined - * in a type in the com.xyz.myapp.service package or any sub-package + * in a type in the com.xyz.service package or any sub-package * under that. */ - @Pointcut("within(com.xyz.myapp.service..*)") + @Pointcut("within(com.xyz.service..*)") public void inServiceLayer() {} /** * A join point is in the data access layer if the method is defined - * in a type in the com.xyz.myapp.dao package or any sub-package + * in a type in the com.xyz.dao package or any sub-package * under that. */ - @Pointcut("within(com.xyz.myapp.dao..*)") + @Pointcut("within(com.xyz.dao..*)") public void inDataAccessLayer() {} /** @@ -564,31 +576,31 @@ expressions for this purpose. Such an aspect typically resembles the following * "service" package, and that implementation types are in sub-packages. * * If you group service interfaces by functional area (for example, - * in packages com.xyz.myapp.abc.service and com.xyz.myapp.def.service) then - * the pointcut expression "execution(* com.xyz.myapp..service.*.*(..))" + * in packages com.xyz.abc.service and com.xyz.def.service) then + * the pointcut expression "execution(* com.xyz..service.*.*(..))" * could be used instead. * * Alternatively, you can write the expression using the 'bean' * PCD, like so "bean(*Service)". (This assumes that you have * named your Spring service beans in a consistent fashion.) */ - @Pointcut("execution(* com.xyz.myapp..service.*.*(..))") + @Pointcut("execution(* com.xyz..service.*.*(..))") public void businessService() {} /** * A data access operation is the execution of any method defined on a - * dao interface. This definition assumes that interfaces are placed in the + * DAO interface. This definition assumes that interfaces are placed in the * "dao" package, and that implementation types are in sub-packages. */ - @Pointcut("execution(* com.xyz.myapp.dao.*.*(..))") + @Pointcut("execution(* com.xyz.dao.*.*(..))") public void dataAccessOperation() {} } ---- -[source,kotlin,indent=0,subs="verbatim",role="secondary",chomp="-packages"] +[source,kotlin,indent=0,subs="verbatim",role="secondary",chomp="-packages",fold="none"] .Kotlin ---- - package com.xyz.myapp + package com.xyz import org.aspectj.lang.annotation.Aspect import org.aspectj.lang.annotation.Pointcut @@ -597,73 +609,68 @@ expressions for this purpose. Such an aspect typically resembles the following class CommonPointcuts { /** - * A join point is in the web layer if the method is defined - * in a type in the com.xyz.myapp.web package or any sub-package - * under that. - */ - @Pointcut("within(com.xyz.myapp.web..*)") - fun inWebLayer() { - } + * A join point is in the web layer if the method is defined + * in a type in the com.xyz.web package or any sub-package + * under that. + */ + @Pointcut("within(com.xyz.web..*)") + fun inWebLayer() {} /** - * A join point is in the service layer if the method is defined - * in a type in the com.xyz.myapp.service package or any sub-package - * under that. - */ - @Pointcut("within(com.xyz.myapp.service..*)") - fun inServiceLayer() { - } + * A join point is in the service layer if the method is defined + * in a type in the com.xyz.service package or any sub-package + * under that. + */ + @Pointcut("within(com.xyz.service..*)") + fun inServiceLayer() {} /** - * A join point is in the data access layer if the method is defined - * in a type in the com.xyz.myapp.dao package or any sub-package - * under that. - */ - @Pointcut("within(com.xyz.myapp.dao..*)") - fun inDataAccessLayer() { - } + * A join point is in the data access layer if the method is defined + * in a type in the com.xyz.dao package or any sub-package + * under that. + */ + @Pointcut("within(com.xyz.dao..*)") + fun inDataAccessLayer() {} /** - * A business service is the execution of any method defined on a service - * interface. This definition assumes that interfaces are placed in the - * "service" package, and that implementation types are in sub-packages. - * - * If you group service interfaces by functional area (for example, - * in packages com.xyz.myapp.abc.service and com.xyz.myapp.def.service) then - * the pointcut expression "execution(* com.xyz.myapp..service.*.*(..))" - * could be used instead. - * - * Alternatively, you can write the expression using the 'bean' - * PCD, like so "bean(*Service)". (This assumes that you have - * named your Spring service beans in a consistent fashion.) - */ - @Pointcut("execution(* com.xyz.myapp..service.*.*(..))") - fun businessService() { - } + * A business service is the execution of any method defined on a service + * interface. This definition assumes that interfaces are placed in the + * "service" package, and that implementation types are in sub-packages. + * + * If you group service interfaces by functional area (for example, + * in packages com.xyz.abc.service and com.xyz.def.service) then + * the pointcut expression "execution(* com.xyz..service.*.*(..))" + * could be used instead. + * + * Alternatively, you can write the expression using the 'bean' + * PCD, like so "bean(*Service)". (This assumes that you have + * named your Spring service beans in a consistent fashion.) + */ + @Pointcut("execution(* com.xyz..service.*.*(..))") + fun businessService() {} /** - * A data access operation is the execution of any method defined on a - * dao interface. This definition assumes that interfaces are placed in the - * "dao" package, and that implementation types are in sub-packages. - */ - @Pointcut("execution(* com.xyz.myapp.dao.*.*(..))") - fun dataAccessOperation() { - } + * A data access operation is the execution of any method defined on a + * DAO interface. This definition assumes that interfaces are placed in the + * "dao" package, and that implementation types are in sub-packages. + */ + @Pointcut("execution(* com.xyz.dao.*.*(..))") + fun dataAccessOperation() {} } ---- You can refer to the pointcuts defined in such an aspect anywhere you need a pointcut -expression by referencing the fully-qualified class name of the aspect combined with the -pointcut name. For example, to make the service layer transactional, you could write the -following which references the shared `com.xyz.myapp.CommonPointcuts.businessService()` -pointcut: +expression by referencing the fully-qualified name of the `@Aspect` class combined with +the `@Pointcut` method's name. For example, to make the service layer transactional, you +could write the following which references the +`com.xyz.CommonPointcuts.businessService()` _named pointcut_: -[source,xml,indent=0,subs="verbatim,quotes"] +[source,xml,indent=0,subs="verbatim"] ---- @@ -684,7 +691,7 @@ transaction elements are discussed in <>. [[aop-advice-before]] ==== Before Advice -You can declare before advice in an aspect by using the `@Before` annotation: +You can declare before advice in an aspect by using the `@Before` annotation. -[source,java,indent=0,subs="verbatim,quotes",role="primary"] -.Java ----- - import org.aspectj.lang.annotation.Aspect; - import org.aspectj.lang.annotation.Before; - - @Aspect - public class BeforeExample { - - @Before("com.xyz.myapp.CommonPointcuts.dataAccessOperation()") - public void doAccessCheck() { - // ... - } - } ----- -[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] -.Kotlin ----- - import org.aspectj.lang.annotation.Aspect - import org.aspectj.lang.annotation.Before - - @Aspect - class BeforeExample { - - @Before("com.xyz.myapp.CommonPointcuts.dataAccessOperation()") - fun doAccessCheck() { - // ... - } - } ----- - -If we use an in-place pointcut expression, we can rewrite the preceding example as follows: +The following example uses an inline pointcut expression. [source,java,indent=0,subs="verbatim",role="primary"] .Java @@ -952,7 +928,7 @@ If we use an in-place pointcut expression, we can rewrite the preceding example @Aspect public class BeforeExample { - @Before("execution(* com.xyz.myapp.dao.*.*(..))") + @Before("execution(* com.xyz.dao.*.*(..))") public void doAccessCheck() { // ... } @@ -967,7 +943,41 @@ If we use an in-place pointcut expression, we can rewrite the preceding example @Aspect class BeforeExample { - @Before("execution(* com.xyz.myapp.dao.*.*(..))") + @Before("execution(* com.xyz.dao.*.*(..))") + fun doAccessCheck() { + // ... + } + } +---- + +If we use a <>, we can rewrite the preceding example +as follows: + +[source,java,indent=0,subs="verbatim",role="primary"] +.Java +---- + import org.aspectj.lang.annotation.Aspect; + import org.aspectj.lang.annotation.Before; + + @Aspect + public class BeforeExample { + + @Before("com.xyz.CommonPointcuts.dataAccessOperation()") + public void doAccessCheck() { + // ... + } + } +---- +[source,kotlin,indent=0,subs="verbatim",role="secondary"] +.Kotlin +---- + import org.aspectj.lang.annotation.Aspect + import org.aspectj.lang.annotation.Before + + @Aspect + class BeforeExample { + + @Before("com.xyz.CommonPointcuts.dataAccessOperation()") fun doAccessCheck() { // ... } @@ -979,9 +989,9 @@ If we use an in-place pointcut expression, we can rewrite the preceding example ==== After Returning Advice After returning advice runs when a matched method execution returns normally. -You can declare it by using the `@AfterReturning` annotation: +You can declare it by using the `@AfterReturning` annotation. -[source,java,indent=0,subs="verbatim,quotes",role="primary"] +[source,java,indent=0,subs="verbatim",role="primary"] .Java ---- import org.aspectj.lang.annotation.Aspect; @@ -990,13 +1000,13 @@ You can declare it by using the `@AfterReturning` annotation: @Aspect public class AfterReturningExample { - @AfterReturning("com.xyz.myapp.CommonPointcuts.dataAccessOperation()") + @AfterReturning("execution(* com.xyz.dao.*.*(..))") public void doAccessCheck() { // ... } } ---- -[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] +[source,kotlin,indent=0,subs="verbatim",role="secondary"] .Kotlin ---- import org.aspectj.lang.annotation.Aspect @@ -1005,7 +1015,7 @@ You can declare it by using the `@AfterReturning` annotation: @Aspect class AfterReturningExample { - @AfterReturning("com.xyz.myapp.CommonPointcuts.dataAccessOperation()") + @AfterReturning("execution(* com.xyz.dao.*.*(..))") fun doAccessCheck() { // ... } @@ -1020,7 +1030,7 @@ Sometimes, you need access in the advice body to the actual value that was retur You can use the form of `@AfterReturning` that binds the return value to get that access, as the following example shows: -[source,java,indent=0,subs="verbatim,quotes",role="primary"] +[source,java,indent=0,subs="verbatim",role="primary"] .Java ---- import org.aspectj.lang.annotation.Aspect; @@ -1030,14 +1040,14 @@ access, as the following example shows: public class AfterReturningExample { @AfterReturning( - pointcut="com.xyz.myapp.CommonPointcuts.dataAccessOperation()", + pointcut="execution(* com.xyz.dao.*.*(..))", returning="retVal") public void doAccessCheck(Object retVal) { // ... } } ---- -[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] +[source,kotlin,indent=0,subs="verbatim",role="secondary"] .Kotlin ---- import org.aspectj.lang.annotation.Aspect @@ -1047,7 +1057,7 @@ access, as the following example shows: class AfterReturningExample { @AfterReturning( - pointcut = "com.xyz.myapp.CommonPointcuts.dataAccessOperation()", + pointcut = "execution(* com.xyz.dao.*.*(..))", returning = "retVal") fun doAccessCheck(retVal: Any) { // ... @@ -1072,7 +1082,7 @@ After throwing advice runs when a matched method execution exits by throwing an exception. You can declare it by using the `@AfterThrowing` annotation, as the following example shows: -[source,java,indent=0,subs="verbatim,quotes",role="primary"] +[source,java,indent=0,subs="verbatim",role="primary"] .Java ---- import org.aspectj.lang.annotation.Aspect; @@ -1081,13 +1091,13 @@ following example shows: @Aspect public class AfterThrowingExample { - @AfterThrowing("com.xyz.myapp.CommonPointcuts.dataAccessOperation()") + @AfterThrowing("execution(* com.xyz.dao.*.*(..))") public void doRecoveryActions() { // ... } } ---- -[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] +[source,kotlin,indent=0,subs="verbatim",role="secondary"] .Kotlin ---- import org.aspectj.lang.annotation.Aspect @@ -1096,7 +1106,7 @@ following example shows: @Aspect class AfterThrowingExample { - @AfterThrowing("com.xyz.myapp.CommonPointcuts.dataAccessOperation()") + @AfterThrowing("execution(* com.xyz.dao.*.*(..))") fun doRecoveryActions() { // ... } @@ -1109,7 +1119,7 @@ use the `throwing` attribute to both restrict matching (if desired -- use `Throw as the exception type otherwise) and bind the thrown exception to an advice parameter. The following example shows how to do so: -[source,java,indent=0,subs="verbatim,quotes",role="primary"] +[source,java,indent=0,subs="verbatim",role="primary"] .Java ---- import org.aspectj.lang.annotation.Aspect; @@ -1119,14 +1129,14 @@ The following example shows how to do so: public class AfterThrowingExample { @AfterThrowing( - pointcut="com.xyz.myapp.CommonPointcuts.dataAccessOperation()", + pointcut="execution(* com.xyz.dao.*.*(..))", throwing="ex") public void doRecoveryActions(DataAccessException ex) { // ... } } ---- -[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] +[source,kotlin,indent=0,subs="verbatim",role="secondary"] .Kotlin ---- import org.aspectj.lang.annotation.Aspect @@ -1136,7 +1146,7 @@ The following example shows how to do so: class AfterThrowingExample { @AfterThrowing( - pointcut = "com.xyz.myapp.CommonPointcuts.dataAccessOperation()", + pointcut = "execution(* com.xyz.dao.*.*(..))", throwing = "ex") fun doRecoveryActions(ex: DataAccessException) { // ... @@ -1167,7 +1177,7 @@ using the `@After` annotation. After advice must be prepared to handle both norm exception return conditions. It is typically used for releasing resources and similar purposes. The following example shows how to use after finally advice: -[source,java,indent=0,subs="verbatim,quotes",role="primary"] +[source,java,indent=0,subs="verbatim",role="primary"] .Java ---- import org.aspectj.lang.annotation.Aspect; @@ -1176,13 +1186,13 @@ purposes. The following example shows how to use after finally advice: @Aspect public class AfterFinallyExample { - @After("com.xyz.myapp.CommonPointcuts.dataAccessOperation()") + @After("execution(* com.xyz.dao.*.*(..))") public void doReleaseLock() { // ... } } ---- -[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] +[source,kotlin,indent=0,subs="verbatim",role="secondary"] .Kotlin ---- import org.aspectj.lang.annotation.Aspect @@ -1191,7 +1201,7 @@ purposes. The following example shows how to use after finally advice: @Aspect class AfterFinallyExample { - @After("com.xyz.myapp.CommonPointcuts.dataAccessOperation()") + @After("execution(* com.xyz.dao.*.*(..))") fun doReleaseLock() { // ... } @@ -1267,7 +1277,7 @@ value depending on the use case. The following example shows how to use around advice: -[source,java,indent=0,subs="verbatim,quotes",role="primary"] +[source,java,indent=0,subs="verbatim",role="primary"] .Java ---- import org.aspectj.lang.annotation.Aspect; @@ -1277,7 +1287,7 @@ The following example shows how to use around advice: @Aspect public class AroundExample { - @Around("com.xyz.myapp.CommonPointcuts.businessService()") + @Around("execution(* com.xyz..service.*.*(..))") public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable { // start stopwatch Object retVal = pjp.proceed(); @@ -1286,7 +1296,7 @@ The following example shows how to use around advice: } } ---- -[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] +[source,kotlin,indent=0,subs="verbatim",role="secondary"] .Kotlin ---- import org.aspectj.lang.annotation.Aspect @@ -1296,7 +1306,7 @@ The following example shows how to use around advice: @Aspect class AroundExample { - @Around("com.xyz.myapp.CommonPointcuts.businessService()") + @Around("execution(* com.xyz..service.*.*(..))") fun doBasicProfiling(pjp: ProceedingJoinPoint): Any { // start stopwatch val retVal = pjp.proceed() @@ -1344,18 +1354,18 @@ Suppose you want to advise the execution of DAO operations that take an `Account object as the first parameter, and you need access to the account in the advice body. You could write the following: -[source,java,indent=0,subs="verbatim,quotes",role="primary"] +[source,java,indent=0,subs="verbatim",role="primary"] .Java ---- - @Before("com.xyz.myapp.CommonPointcuts.dataAccessOperation() && args(account,..)") + @Before("execution(* com.xyz.dao.*.*(..)) && args(account,..)") public void validateAccount(Account account) { // ... } ---- -[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] +[source,kotlin,indent=0,subs="verbatim",role="secondary"] .Kotlin ---- - @Before("com.xyz.myapp.CommonPointcuts.dataAccessOperation() && args(account,..)") + @Before("execution(* com.xyz.dao.*.*(..)) && args(account,..)") fun validateAccount(account: Account) { // ... } @@ -1371,10 +1381,10 @@ Another way of writing this is to declare a pointcut that "provides" the `Accoun object value when it matches a join point, and then refer to the named pointcut from the advice. This would look as follows: -[source,java,indent=0,subs="verbatim,quotes",role="primary"] +[source,java,indent=0,subs="verbatim",role="primary"] .Java ---- - @Pointcut("com.xyz.myapp.CommonPointcuts.dataAccessOperation() && args(account,..)") + @Pointcut("execution(* com.xyz.dao.*.*(..)) && args(account,..)") private void accountDataAccessOperation(Account account) {} @Before("accountDataAccessOperation(account)") @@ -1382,10 +1392,10 @@ from the advice. This would look as follows: // ... } ---- -[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] +[source,kotlin,indent=0,subs="verbatim",role="secondary"] .Kotlin ---- - @Pointcut("com.xyz.myapp.CommonPointcuts.dataAccessOperation() && args(account,..)") + @Pointcut("execution(* com.xyz.dao.*.*(..)) && args(account,..)") private fun accountDataAccessOperation(account: Account) { } @@ -1404,7 +1414,7 @@ set of examples shows how to match the execution of methods annotated with an The following shows the definition of the `@Auditable` annotation: -[source,java,indent=0,subs="verbatim,quotes",role="primary"] +[source,java,indent=0,subs="verbatim",role="primary"] .Java ---- @Retention(RetentionPolicy.RUNTIME) @@ -1413,7 +1423,7 @@ The following shows the definition of the `@Auditable` annotation: AuditCode value(); } ---- -[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] +[source,kotlin,indent=0,subs="verbatim",role="secondary"] .Kotlin ---- @Retention(AnnotationRetention.RUNTIME) @@ -1423,24 +1433,27 @@ The following shows the definition of the `@Auditable` annotation: The following shows the advice that matches the execution of `@Auditable` methods: -[source,java,indent=0,subs="verbatim,quotes",role="primary"] +[source,java,indent=0,subs="verbatim",role="primary"] .Java ---- - @Before("com.xyz.lib.Pointcuts.anyPublicMethod() && @annotation(auditable)") + @Before("com.xyz.Pointcuts.publicMethod() && @annotation(auditable)") // <1> public void audit(Auditable auditable) { AuditCode code = auditable.value(); // ... } ---- -[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] +<1> References the `publicMethod` named pointcut defined in <>. + +[source,kotlin,indent=0,subs="verbatim",role="secondary"] .Kotlin ---- - @Before("com.xyz.lib.Pointcuts.anyPublicMethod() && @annotation(auditable)") + @Before("com.xyz.Pointcuts.publicMethod() && @annotation(auditable)") // <1> fun audit(auditable: Auditable) { val code = auditable.value() // ... } ---- +<1> References the `publicMethod` named pointcut defined in <>. [[aop-ataspectj-advice-params-generics]] ===== Advice Parameters and Generics @@ -1448,7 +1461,7 @@ The following shows the advice that matches the execution of `@Auditable` method Spring AOP can handle generics used in class declarations and method parameters. Suppose you have a generic type like the following: -[source,java,indent=0,subs="verbatim,quotes",role="primary"] +[source,java,indent=0,subs="verbatim",role="primary"] .Java ---- public interface Sample { @@ -1456,7 +1469,7 @@ you have a generic type like the following: void sampleGenericCollectionMethod(Collection param); } ---- -[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] +[source,kotlin,indent=0,subs="verbatim",role="secondary"] .Kotlin ---- interface Sample { @@ -1468,7 +1481,7 @@ you have a generic type like the following: You can restrict interception of method types to certain parameter types by tying the advice parameter to the parameter type for which you want to intercept the method: -[source,java,indent=0,subs="verbatim,quotes",role="primary"] +[source,java,indent=0,subs="verbatim",role="primary"] .Java ---- @Before("execution(* ..Sample+.sampleGenericMethod(*)) && args(param)") @@ -1476,7 +1489,7 @@ tying the advice parameter to the parameter type for which you want to intercept // Advice implementation } ---- -[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] +[source,kotlin,indent=0,subs="verbatim",role="secondary"] .Kotlin ---- @Before("execution(* ..Sample+.sampleGenericMethod(*)) && args(param)") @@ -1488,7 +1501,7 @@ tying the advice parameter to the parameter type for which you want to intercept This approach does not work for generic collections. So you cannot define a pointcut as follows: -[source,java,indent=0,subs="verbatim,quotes",role="primary"] +[source,java,indent=0,subs="verbatim",role="primary"] .Java ---- @Before("execution(* ..Sample+.sampleGenericCollectionMethod(*)) && args(param)") @@ -1496,7 +1509,7 @@ pointcut as follows: // Advice implementation } ---- -[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] +[source,kotlin,indent=0,subs="verbatim",role="secondary"] .Kotlin ---- @Before("execution(* ..Sample+.sampleGenericCollectionMethod(*)) && args(param)") @@ -1524,51 +1537,62 @@ following strategy to determine parameter names: the annotated method. These argument names are available at runtime. The following example shows how to use the `argNames` attribute: -[source,java,indent=0,subs="verbatim,quotes",role="primary"] +[source,java,indent=0,subs="verbatim",role="primary"] .Java ---- - @Before(value="com.xyz.lib.Pointcuts.anyPublicMethod() && target(bean) && @annotation(auditable)", - argNames="bean,auditable") + @Before( + value = "com.xyz.Pointcuts.publicMethod() && target(bean) && @annotation(auditable)", // <1> + argNames = "bean,auditable") public void audit(Object bean, Auditable auditable) { AuditCode code = auditable.value(); // ... use code and bean } ---- -[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] +<1> References the `publicMethod` named pointcut defined in <>. + +[source,kotlin,indent=0,subs="verbatim",role="secondary"] .Kotlin ---- - @Before(value = "com.xyz.lib.Pointcuts.anyPublicMethod() && target(bean) && @annotation(auditable)", argNames = "bean,auditable") + @Before( + value = "com.xyz.Pointcuts.publicMethod() && target(bean) && @annotation(auditable)", // <1> + argNames = "bean,auditable") fun audit(bean: Any, auditable: Auditable) { val code = auditable.value() // ... use code and bean } ---- - +<1> References the `publicMethod` named pointcut defined in <>. If the first parameter is of the `JoinPoint`, `ProceedingJoinPoint`, or `JoinPoint.StaticPart` type, you can leave out the name of the parameter from the value of the `argNames` attribute. For example, if you modify the preceding advice to receive the join point object, the `argNames` attribute need not include it: -[source,java,indent=0,subs="verbatim,quotes",role="primary"] +[source,java,indent=0,subs="verbatim",role="primary"] .Java ---- - @Before(value="com.xyz.lib.Pointcuts.anyPublicMethod() && target(bean) && @annotation(auditable)", - argNames="bean,auditable") + @Before( + value = "com.xyz.Pointcuts.publicMethod() && target(bean) && @annotation(auditable)", // <1> + argNames = "bean,auditable") public void audit(JoinPoint jp, Object bean, Auditable auditable) { AuditCode code = auditable.value(); // ... use code, bean, and jp } ---- -[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] +<1> References the `publicMethod` named pointcut defined in <>. + +[source,kotlin,indent=0,subs="verbatim",role="secondary"] .Kotlin ---- - @Before(value = "com.xyz.lib.Pointcuts.anyPublicMethod() && target(bean) && @annotation(auditable)", argNames = "bean,auditable") + @Before( + value = "com.xyz.Pointcuts.publicMethod() && target(bean) && @annotation(auditable)", // <1> + argNames = "bean,auditable") fun audit(jp: JoinPoint, bean: Any, auditable: Auditable) { val code = auditable.value() // ... use code, bean, and jp } ---- +<1> References the `publicMethod` named pointcut defined in <>. The special treatment given to the first parameter of the `JoinPoint`, `ProceedingJoinPoint`, and `JoinPoint.StaticPart` types is particularly convenient for @@ -1576,22 +1600,25 @@ advice instances that do not collect any other join point context. In such situa omit the `argNames` attribute. For example, the following advice need not declare the `argNames` attribute: -[source,java,indent=0,subs="verbatim,quotes",role="primary"] +[source,java,indent=0,subs="verbatim",role="primary"] .Java ---- - @Before("com.xyz.lib.Pointcuts.anyPublicMethod()") + @Before("com.xyz.Pointcuts.publicMethod()") // <1> public void audit(JoinPoint jp) { // ... use jp } ---- -[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] +<1> References the `publicMethod` named pointcut defined in <>. + +[source,kotlin,indent=0,subs="verbatim",role="secondary"] .Kotlin ---- - @Before("com.xyz.lib.Pointcuts.anyPublicMethod()") + @Before("com.xyz.Pointcuts.publicMethod()") // <1> fun audit(jp: JoinPoint) { // ... use jp } ---- +<1> References the `publicMethod` named pointcut defined in <>. * Using the `argNames` attribute is a little clumsy, so if the `argNames` attribute has not been specified, Spring AOP looks at the debug information for the @@ -1623,30 +1650,33 @@ arguments that works consistently across Spring AOP and AspectJ. The solution is to ensure that the advice signature binds each of the method parameters in order. The following example shows how to do so: -[source,java,indent=0,subs="verbatim,quotes",role="primary"] +[source,java,indent=0,subs="verbatim",role="primary"] .Java ---- @Around("execution(List find*(..)) && " + - "com.xyz.myapp.CommonPointcuts.inDataAccessLayer() && " + - "args(accountHolderNamePattern)") + "com.xyz.CommonPointcuts.inDataAccessLayer() && " + + "args(accountHolderNamePattern)") // <1> public Object preProcessQueryPattern(ProceedingJoinPoint pjp, String accountHolderNamePattern) throws Throwable { String newPattern = preProcess(accountHolderNamePattern); return pjp.proceed(new Object[] {newPattern}); } ---- -[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] +<1> References the `inDataAccessLayer` named pointcut defined in <>. + +[source,kotlin,indent=0,subs="verbatim",role="secondary"] .Kotlin ---- @Around("execution(List find*(..)) && " + - "com.xyz.myapp.CommonPointcuts.inDataAccessLayer() && " + - "args(accountHolderNamePattern)") + "com.xyz.CommonPointcuts.inDataAccessLayer() && " + + "args(accountHolderNamePattern)") // <1> fun preProcessQueryPattern(pjp: ProceedingJoinPoint, accountHolderNamePattern: String): Any { val newPattern = preProcess(accountHolderNamePattern) return pjp.proceed(arrayOf(newPattern)) } ---- +<1> References the `inDataAccessLayer` named pointcut defined in <>. In many cases, you do this binding anyway (as in the preceding example). @@ -1704,34 +1734,35 @@ given an interface named `UsageTracked` and an implementation of that interface `DefaultUsageTracked`, the following aspect declares that all implementors of service interfaces also implement the `UsageTracked` interface (e.g. for statistics via JMX): -[source,java,indent=0,subs="verbatim,quotes",role="primary"] +[source,java,indent=0,subs="verbatim",role="primary"] .Java ---- @Aspect public class UsageTracking { - @DeclareParents(value="com.xzy.myapp.service.*+", defaultImpl=DefaultUsageTracked.class) + @DeclareParents(value="com.xyz.service.*+", defaultImpl=DefaultUsageTracked.class) public static UsageTracked mixin; - @Before("com.xyz.myapp.CommonPointcuts.businessService() && this(usageTracked)") + @Before("execution(* com.xyz..service.*.*(..)) && this(usageTracked)") public void recordUsage(UsageTracked usageTracked) { usageTracked.incrementUseCount(); } } ---- -[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] +[source,kotlin,indent=0,subs="verbatim",role="secondary"] .Kotlin ---- @Aspect class UsageTracking { companion object { - @DeclareParents(value = "com.xzy.myapp.service.*+", defaultImpl = DefaultUsageTracked::class) + @DeclareParents(value = "com.xyz.service.*+", + defaultImpl = DefaultUsageTracked::class) lateinit var mixin: UsageTracked } - @Before("com.xyz.myapp.CommonPointcuts.businessService() && this(usageTracked)") + @Before("execution(* com.xyz..service.*.*(..)) && this(usageTracked)") fun recordUsage(usageTracked: UsageTracked) { usageTracked.incrementUseCount() } @@ -1745,12 +1776,12 @@ before advice of the preceding example, service beans can be directly used as implementations of the `UsageTracked` interface. If accessing a bean programmatically, you would write the following: -[source,java,indent=0,subs="verbatim,quotes",role="primary"] +[source,java,indent=0,subs="verbatim",role="primary"] .Java ---- UsageTracked usageTracked = context.getBean("myService", UsageTracked.class); ---- -[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] +[source,kotlin,indent=0,subs="verbatim",role="secondary"] .Kotlin ---- val usageTracked = context.getBean("myService", UsageTracked.class) @@ -1772,29 +1803,29 @@ supported. You can declare a `perthis` aspect by specifying a `perthis` clause in the `@Aspect` annotation. Consider the following example: -[source,java,indent=0,subs="verbatim,quotes",role="primary"] +[source,java,indent=0,subs="verbatim",role="primary"] .Java ---- - @Aspect("perthis(com.xyz.myapp.CommonPointcuts.businessService())") + @Aspect("perthis(execution(* com.xyz..service.*.*(..)))") public class MyAspect { private int someState; - @Before("com.xyz.myapp.CommonPointcuts.businessService()") + @Before("execution(* com.xyz..service.*.*(..))") public void recordServiceUsage() { // ... } } ---- -[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] +[source,kotlin,indent=0,subs="verbatim",role="secondary"] .Kotlin ---- - @Aspect("perthis(com.xyz.myapp.CommonPointcuts.businessService())") + @Aspect("perthis(execution(* com.xyz..service.*.*(..)))") class MyAspect { private val someState: Int = 0 - @Before("com.xyz.myapp.CommonPointcuts.businessService()") + @Before("execution(* com.xyz..service.*.*(..))") fun recordServiceUsage() { // ... } @@ -1834,7 +1865,7 @@ aspect. Because we want to retry the operation, we need to use around advice so that we can call `proceed` multiple times. The following listing shows the basic aspect implementation: -[source,java,indent=0,subs="verbatim,quotes",role="primary"] +[source,java,indent=0,subs="verbatim",role="primary"] .Java ---- @Aspect @@ -1857,7 +1888,7 @@ call `proceed` multiple times. The following listing shows the basic aspect impl this.order = order; } - @Around("com.xyz.myapp.CommonPointcuts.businessService()") + @Around("com.xyz.CommonPointcuts.businessService()") // <1> public Object doConcurrentOperation(ProceedingJoinPoint pjp) throws Throwable { int numAttempts = 0; PessimisticLockingFailureException lockFailureException; @@ -1874,7 +1905,9 @@ call `proceed` multiple times. The following listing shows the basic aspect impl } } ---- -[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] +<1> References the `businessService` named pointcut defined in <>. + +[source,kotlin,indent=0,subs="verbatim",role="secondary"] .Kotlin ---- @Aspect @@ -1896,7 +1929,7 @@ call `proceed` multiple times. The following listing shows the basic aspect impl this.order = order } - @Around("com.xyz.myapp.CommonPointcuts.businessService()") + @Around("com.xyz.CommonPointcuts.businessService()") // <1> fun doConcurrentOperation(pjp: ProceedingJoinPoint): Any { var numAttempts = 0 var lockFailureException: PessimisticLockingFailureException @@ -1913,22 +1946,24 @@ call `proceed` multiple times. The following listing shows the basic aspect impl } } ---- +<1> References the `businessService` named pointcut defined in <>. Note that the aspect implements the `Ordered` interface so that we can set the precedence of the aspect higher than the transaction advice (we want a fresh transaction each time we retry). The `maxRetries` and `order` properties are both configured by Spring. The main action happens in the `doConcurrentOperation` around advice. Notice that, for the -moment, we apply the retry logic to each `businessService()`. We try to proceed, +moment, we apply the retry logic to each `businessService`. We try to proceed, and if we fail with a `PessimisticLockingFailureException`, we try again, unless we have exhausted all of our retry attempts. The corresponding Spring configuration follows: -[source,xml,indent=0,subs="verbatim,quotes"] +[source,xml,indent=0,subs="verbatim"] ---- - + @@ -1937,7 +1972,7 @@ The corresponding Spring configuration follows: To refine the aspect so that it retries only idempotent operations, we might define the following `Idempotent` annotation: -[source,java,indent=0,subs="verbatim,quotes",role="primary"] +[source,java,indent=0,subs="verbatim",role="primary"] .Java ---- @Retention(RetentionPolicy.RUNTIME) @@ -1945,7 +1980,7 @@ To refine the aspect so that it retries only idempotent operations, we might def public @interface Idempotent { } ---- -[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] +[source,kotlin,indent=0,subs="verbatim",role="secondary"] .Kotlin ---- @Retention(AnnotationRetention.RUNTIME) @@ -1957,20 +1992,20 @@ We can then use the annotation to annotate the implementation of service operati to the aspect to retry only idempotent operations involves refining the pointcut expression so that only `@Idempotent` operations match, as follows: -[source,java,indent=0,subs="verbatim,quotes",role="primary"] +[source,java,indent=0,subs="verbatim",role="primary"] .Java ---- - @Around("com.xyz.myapp.CommonPointcuts.businessService() && " + - "@annotation(com.xyz.myapp.service.Idempotent)") + @Around("execution(* com.xyz..service.*.*(..)) && " + + "@annotation(com.xyz.service.Idempotent)") public Object doConcurrentOperation(ProceedingJoinPoint pjp) throws Throwable { // ... } ---- -[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] +[source,kotlin,indent=0,subs="verbatim",role="secondary"] .Kotlin ---- - @Around("com.xyz.myapp.CommonPointcuts.businessService() && " + - "@annotation(com.xyz.myapp.service.Idempotent)") + @Around("execution(* com.xyz..service.*.*(..)) && " + + "@annotation(com.xyz.service.Idempotent)") fun doConcurrentOperation(pjp: ProceedingJoinPoint): Any { // ... } @@ -2017,7 +2052,7 @@ methods of the object, and the pointcut and advice information are captured in t You can declare an aspect by using the `` element, and reference the backing bean by using the `ref` attribute, as the following example shows: -[source,xml,indent=0,subs="verbatim,quotes"] +[source,xml,indent=0,subs="verbatim"] ---- @@ -2049,7 +2084,7 @@ be defined as follows: + expression="execution(* com.xyz.service.*.*(..))" /> ---- @@ -2059,15 +2094,16 @@ language as described in <>. If you use the schema based declarat style, you can also refer to _named pointcuts_ defined in `@Aspect` types within the pointcut expression. Thus, another way of defining the above pointcut would be as follows: -[source,xml,indent=0,subs="verbatim,quotes"] +[source,xml,indent=0,subs="verbatim"] ---- + expression="com.xyz.CommonPointcuts.businessService()" /> <1> ---- +<1> References the `businessService` named pointcut defined in <>. Declaring a pointcut _inside_ an aspect is very similar to declaring a top-level pointcut, as the following example shows: @@ -2079,7 +2115,7 @@ as the following example shows: + expression="execution(* com.xyz.service.*.*(..))"/> ... @@ -2098,7 +2134,7 @@ collects the `this` object as the join point context and passes it to the advice + expression="execution(* com.xyz.service.*.*(..)) && this(service)"/> @@ -2111,14 +2147,14 @@ collects the `this` object as the join point context and passes it to the advice The advice must be declared to receive the collected join point context by including parameters of the matching names, as follows: -[source,java,indent=0,subs="verbatim,quotes",role="primary"] +[source,java,indent=0,subs="verbatim",role="primary"] .Java ---- public void monitor(Object service) { // ... } ---- -[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] +[source,kotlin,indent=0,subs="verbatim",role="secondary"] .Kotlin ---- fun monitor(service: Any) { @@ -2138,7 +2174,7 @@ follows: + expression="execution(* com.xyz.service.*.*(..)) and this(service)"/> @@ -2168,7 +2204,7 @@ exactly the same semantics. Before advice runs before a matched method execution. It is declared inside an `` by using the `` element, as the following example shows: -[source,xml,indent=0,subs="verbatim,quotes"] +[source,xml,indent=0,subs="verbatim"] ---- @@ -2196,7 +2232,7 @@ To define the pointcut inline instead, replace the `pointcut-ref` attribute with ... @@ -2218,12 +2254,12 @@ After returning advice runs when a matched method execution completes normally. declared inside an `` in the same way as before advice. The following example shows how to declare it: -[source,xml,indent=0,subs="verbatim,quotes"] +[source,xml,indent=0,subs="verbatim"] ---- ... @@ -2234,12 +2270,12 @@ As in the @AspectJ style, you can get the return value within the advice body. To do so, use the `returning` attribute to specify the name of the parameter to which the return value should be passed, as the following example shows: -[source,xml,indent=0,subs="verbatim,quotes"] +[source,xml,indent=0,subs="verbatim"] ---- @@ -2251,12 +2287,12 @@ The `doAccessCheck` method must declare a parameter named `retVal`. The type of parameter constrains matching in the same way as described for `@AfterReturning`. For example, you can declare the method signature as follows: -[source,java,indent=0,subs="verbatim,quotes",role="primary"] +[source,java,indent=0,subs="verbatim",role="primary"] .Java ---- public void doAccessCheck(Object retVal) {... ---- -[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] +[source,kotlin,indent=0,subs="verbatim",role="secondary"] .Kotlin ---- fun doAccessCheck(retVal: Any) {... @@ -2270,12 +2306,12 @@ After throwing advice runs when a matched method execution exits by throwing an exception. It is declared inside an `` by using the `after-throwing` element, as the following example shows: -[source,xml,indent=0,subs="verbatim,quotes"] +[source,xml,indent=0,subs="verbatim"] ---- ... @@ -2286,12 +2322,12 @@ As in the @AspectJ style, you can get the thrown exception within the advice bod To do so, use the `throwing` attribute to specify the name of the parameter to which the exception should be passed as the following example shows: -[source,xml,indent=0,subs="verbatim,quotes"] +[source,xml,indent=0,subs="verbatim"] ---- @@ -2303,12 +2339,12 @@ The `doRecoveryActions` method must declare a parameter named `dataAccessEx`. The type of this parameter constrains matching in the same way as described for `@AfterThrowing`. For example, the method signature may be declared as follows: -[source,java,indent=0,subs="verbatim,quotes",role="primary"] +[source,java,indent=0,subs="verbatim",role="primary"] .Java ---- public void doRecoveryActions(DataAccessException dataAccessEx) {... ---- -[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] +[source,kotlin,indent=0,subs="verbatim",role="secondary"] .Kotlin ---- fun doRecoveryActions(dataAccessEx: DataAccessException) {... @@ -2321,12 +2357,12 @@ The type of this parameter constrains matching in the same way as described for After (finally) advice runs no matter how a matched method execution exits. You can declare it by using the `after` element, as the following example shows: -[source,xml,indent=0,subs="verbatim,quotes"] +[source,xml,indent=0,subs="verbatim"] ---- ... @@ -2363,12 +2399,12 @@ method when it is invoked. See <> for notes on call The following example shows how to declare around advice in XML: -[source,xml,indent=0,subs="verbatim,quotes"] +[source,xml,indent=0,subs="verbatim"] ---- ... @@ -2378,7 +2414,7 @@ The following example shows how to declare around advice in XML: The implementation of the `doBasicProfiling` advice can be exactly the same as in the @AspectJ example (minus the annotation, of course), as the following example shows: -[source,java,indent=0,subs="verbatim,quotes",role="primary"] +[source,java,indent=0,subs="verbatim",role="primary"] .Java ---- public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable { @@ -2388,7 +2424,7 @@ The implementation of the `doBasicProfiling` advice can be exactly the same as i return retVal; } ---- -[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] +[source,kotlin,indent=0,subs="verbatim",role="secondary"] .Kotlin ---- fun doBasicProfiling(pjp: ProceedingJoinPoint): Any { @@ -2412,23 +2448,24 @@ attribute of the advice element, which is treated in the same manner as the `arg attribute in an advice annotation (as described in <>). The following example shows how to specify an argument name in XML: -[source,xml,indent=0,subs="verbatim,quotes"] +[source,xml,indent=0,subs="verbatim"] ---- method="audit" arg-names="auditable" /> ---- +<1> References the `publicMethod` named pointcut defined in <>. The `arg-names` attribute accepts a comma-delimited list of parameter names. The following slightly more involved example of the XSD-based approach shows some around advice used in conjunction with a number of strongly typed parameters: -[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"] +[source,java,indent=0,subs="verbatim",role="primary",chomp="-packages"] .Java ---- - package x.y.service; + package com.xyz.service; public interface PersonService { @@ -2442,10 +2479,10 @@ some around advice used in conjunction with a number of strongly typed parameter } } ---- -[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"] +[source,kotlin,indent=0,subs="verbatim",role="secondary",chomp="-packages"] .Kotlin ---- - package x.y.service + package com.xyz.service interface PersonService { @@ -2465,10 +2502,10 @@ strongly-typed parameters, the first of which happens to be the join point used proceed with the method call. The presence of this parameter is an indication that the `profile(..)` is to be used as `around` advice, as the following example shows: -[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"] +[source,java,indent=0,subs="verbatim",role="primary",chomp="-packages"] .Java ---- - package x.y; + package com.xyz; import org.aspectj.lang.ProceedingJoinPoint; import org.springframework.util.StopWatch; @@ -2487,10 +2524,10 @@ proceed with the method call. The presence of this parameter is an indication th } } ---- -[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"] +[source,kotlin,indent=0,subs="verbatim",role="secondary",chomp="-packages"] .Kotlin ---- - package x.y + package com.xyz import org.aspectj.lang.ProceedingJoinPoint import org.springframework.util.StopWatch @@ -2513,7 +2550,7 @@ proceed with the method call. The presence of this parameter is an indication th Finally, the following example XML configuration effects the execution of the preceding advice for a particular join point: -[source,xml,indent=0,subs="verbatim,quotes"] +[source,xml,indent=0,subs="verbatim"] ---- - + - + + types-matching="com.xyz.service.*+" + implement-interface="com.xyz.service.tracking.UsageTracked" + default-impl="com.xyz.service.tracking.DefaultUsageTracked"/> @@ -2646,14 +2683,14 @@ through JMX for example.) The class that backs the `usageTracking` bean would then contain the following method: -[source,java,indent=0,subs="verbatim,quotes",role="primary"] +[source,java,indent=0,subs="verbatim",role="primary"] .Java ---- public void recordUsage(UsageTracked usageTracked) { usageTracked.incrementUseCount(); } ---- -[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] +[source,kotlin,indent=0,subs="verbatim",role="secondary"] .Kotlin ---- fun recordUsage(usageTracked: UsageTracked) { @@ -2668,12 +2705,12 @@ advice of the preceding example, service beans can be directly used as implement the `UsageTracked` interface. To access a bean programmatically, you could write the following: -[source,java,indent=0,subs="verbatim,quotes",role="primary"] +[source,java,indent=0,subs="verbatim",role="primary"] .Java ---- UsageTracked usageTracked = context.getBean("myService", UsageTracked.class); ---- -[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] +[source,kotlin,indent=0,subs="verbatim",role="secondary"] .Kotlin ---- val usageTracked = context.getBean("myService", UsageTracked.class) @@ -2707,7 +2744,7 @@ namespace support in Spring. The following example shows an advisor: + expression="execution(* com.xyz.service.*.*(..))"/> + expression="execution(* com.xyz.service.*.*(..))"/> + class="com.xyz.service.impl.ConcurrentOperationExecutor"> @@ -2867,7 +2904,7 @@ this is not the case, we can refine the aspect so that it retries only genuinely idempotent operations, by introducing an `Idempotent` annotation and using the annotation to annotate the implementation of service operations, as the following example shows: -[source,java,indent=0,subs="verbatim,quotes",role="primary"] +[source,java,indent=0,subs="verbatim",role="primary"] .Java ---- @Retention(RetentionPolicy.RUNTIME) @@ -2875,7 +2912,7 @@ to annotate the implementation of service operations, as the following example s public @interface Idempotent { } ---- -[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] +[source,kotlin,indent=0,subs="verbatim",role="secondary"] .Kotlin ---- @Retention(AnnotationRetention.RUNTIME) @@ -2890,8 +2927,8 @@ pointcut expression so that only `@Idempotent` operations match, as follows: [source,xml,indent=0,subs="verbatim"] ---- + expression="execution(* com.xyz.service.*.*(..)) and + @annotation(com.xyz.service.Idempotent)"/> ---- @@ -2954,25 +2991,25 @@ it can express than the @AspectJ style: Only the "singleton" aspect instantiatio is supported, and it is not possible to combine named pointcuts declared in XML. For example, in the @AspectJ style you can write something like the following: -[source,java,indent=0,subs="verbatim,quotes",role="primary"] +[source,java,indent=0,subs="verbatim",role="primary"] .Java ---- @Pointcut("execution(* get*())") public void propertyAccess() {} - @Pointcut("execution(org.xyz.Account+ *(..))") + @Pointcut("execution(com.xyz.Account+ *(..))") public void operationReturningAnAccount() {} @Pointcut("propertyAccess() && operationReturningAnAccount()") public void accountPropertyAccess() {} ---- -[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] +[source,kotlin,indent=0,subs="verbatim",role="secondary"] .Kotlin ---- @Pointcut("execution(* get*())") fun propertyAccess() {} - @Pointcut("execution(org.xyz.Account+ *(..))") + @Pointcut("execution(com.xyz.Account+ *(..))") fun operationReturningAnAccount() {} @Pointcut("propertyAccess() && operationReturningAnAccount()") @@ -2987,7 +3024,7 @@ In the XML style you can declare the first two pointcuts: expression="execution(* get*())"/> + expression="execution(com.xyz.Account+ *(..))"/> ---- The downside of the XML approach is that you cannot define the @@ -3040,7 +3077,7 @@ you can do so. However, you should consider the following issues: To force the use of CGLIB proxies, set the value of the `proxy-target-class` attribute of the `` element to true, as follows: -[source,xml,indent=0,subs="verbatim,quotes"] +[source,xml,indent=0,subs="verbatim"] ---- @@ -3051,7 +3088,7 @@ To force CGLIB proxying when you use the @AspectJ auto-proxy support, set the `proxy-target-class` attribute of the `` element to `true`, as follows: -[source,xml,indent=0,subs="verbatim,quotes"] +[source,xml,indent=0,subs="verbatim"] ---- ---- @@ -3082,7 +3119,7 @@ Consider first the scenario where you have a plain-vanilla, un-proxied, nothing-special-about-it, straight object reference, as the following code snippet shows: -[source,java,indent=0,subs="verbatim,quotes",role="primary"] +[source,java,indent=0,subs="verbatim",role="primary"] .Java ---- public class SimplePojo implements Pojo { @@ -3097,7 +3134,7 @@ code snippet shows: } } ---- -[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] +[source,kotlin,indent=0,subs="verbatim",role="secondary"] .Kotlin ---- class SimplePojo : Pojo { @@ -3118,7 +3155,7 @@ that object reference, as the following image and listing show: image::images/aop-proxy-plain-pojo-call.png[] -[source,java,indent=0,subs="verbatim,quotes",role="primary"] +[source,java,indent=0,subs="verbatim",role="primary"] .Java ---- public class Main { @@ -3130,7 +3167,7 @@ image::images/aop-proxy-plain-pojo-call.png[] } } ---- -[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] +[source,kotlin,indent=0,subs="verbatim",role="secondary"] .Kotlin ---- fun main() { @@ -3145,7 +3182,7 @@ following diagram and code snippet: image::images/aop-proxy-call.png[] -[source,java,indent=0,subs="verbatim,quotes",role="primary"] +[source,java,indent=0,subs="verbatim",role="primary"] .Java ---- public class Main { @@ -3161,7 +3198,7 @@ image::images/aop-proxy-call.png[] } } ---- -[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] +[source,kotlin,indent=0,subs="verbatim",role="secondary"] .Kotlin ---- fun main() { @@ -3192,7 +3229,7 @@ The next approach is absolutely horrendous, and we hesitate to point it out, pre because it is so horrendous. You can (painful as it is to us) totally tie the logic within your class to Spring AOP, as the following example shows: -[source,java,indent=0,subs="verbatim,quotes",role="primary"] +[source,java,indent=0,subs="verbatim",role="primary"] .Java ---- public class SimplePojo implements Pojo { @@ -3207,7 +3244,7 @@ within your class to Spring AOP, as the following example shows: } } ---- -[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] +[source,kotlin,indent=0,subs="verbatim",role="secondary"] .Kotlin ---- class SimplePojo : Pojo { @@ -3228,7 +3265,7 @@ the fact that it is being used in an AOP context, which flies in the face of AOP also requires some additional configuration when the proxy is being created, as the following example shows: -[source,java,indent=0,subs="verbatim,quotes",role="primary"] +[source,java,indent=0,subs="verbatim",role="primary"] .Java ---- public class Main { @@ -3245,7 +3282,7 @@ following example shows: } } ---- -[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] +[source,kotlin,indent=0,subs="verbatim",role="secondary"] .Kotlin ---- fun main() { @@ -3279,7 +3316,7 @@ You can use the `org.springframework.aop.aspectj.annotation.AspectJProxyFactory` to create a proxy for a target object that is advised by one or more @AspectJ aspects. The basic usage for this class is very simple, as the following example shows: -[source,java,indent=0,subs="verbatim,quotes",role="primary"] +[source,java,indent=0,subs="verbatim",role="primary"] .Java ---- // create a factory that can generate a proxy for the given target object @@ -3296,7 +3333,7 @@ The basic usage for this class is very simple, as the following example shows: // now get the proxy object... MyInterfaceType proxy = factory.getProxy(); ---- -[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] +[source,kotlin,indent=0,subs="verbatim",role="secondary"] .Kotlin ---- // create a factory that can generate a proxy for the given target object @@ -3353,10 +3390,10 @@ The `@Configurable` annotation marks a class as being eligible for Spring-driven configuration. In the simplest case, you can use purely it as a marker annotation, as the following example shows: -[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"] +[source,java,indent=0,subs="verbatim",role="primary",chomp="-packages"] .Java ---- - package com.xyz.myapp.domain; + package com.xyz.domain; import org.springframework.beans.factory.annotation.Configurable; @@ -3365,10 +3402,10 @@ following example shows: // ... } ---- -[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"] +[source,kotlin,indent=0,subs="verbatim",role="secondary",chomp="-packages"] .Kotlin ---- - package com.xyz.myapp.domain + package com.xyz.domain import org.springframework.beans.factory.annotation.Configurable @@ -3381,13 +3418,13 @@ following example shows: When used as a marker interface in this way, Spring configures new instances of the annotated type (`Account`, in this case) by using a bean definition (typically prototype-scoped) with the same name as the fully-qualified type name -(`com.xyz.myapp.domain.Account`). Since the default name for a bean is the +(`com.xyz.domain.Account`). Since the default name for a bean is the fully-qualified name of its type, a convenient way to declare the prototype definition is to omit the `id` attribute, as the following example shows: -[source,xml,indent=0,subs="verbatim,quotes"] +[source,xml,indent=0,subs="verbatim"] ---- - + ---- @@ -3395,10 +3432,10 @@ is to omit the `id` attribute, as the following example shows: If you want to explicitly specify the name of the prototype bean definition to use, you can do so directly in the annotation, as the following example shows: -[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"] +[source,java,indent=0,subs="verbatim",role="primary",chomp="-packages"] .Java ---- - package com.xyz.myapp.domain; + package com.xyz.domain; import org.springframework.beans.factory.annotation.Configurable; @@ -3407,10 +3444,10 @@ can do so directly in the annotation, as the following example shows: // ... } ---- -[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"] +[source,kotlin,indent=0,subs="verbatim",role="secondary",chomp="-packages"] .Kotlin ---- - package com.xyz.myapp.domain + package com.xyz.domain import org.springframework.beans.factory.annotation.Configurable @@ -3458,12 +3495,12 @@ dependencies to be injected before the constructor bodies run and thus be available for use in the body of the constructors, you need to define this on the `@Configurable` declaration, as follows: -[source,java,indent=0,subs="verbatim,quotes",role="primary"] +[source,java,indent=0,subs="verbatim",role="primary"] .Java ---- @Configurable(preConstruction = true) ---- -[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] +[source,kotlin,indent=0,subs="verbatim",role="secondary"] .Kotlin ---- @Configurable(preConstruction = true) @@ -3485,7 +3522,7 @@ a reference to the bean factory that is to be used to configure new objects). If use Java-based configuration, you can add `@EnableSpringConfigured` to any `@Configuration` class, as follows: -[source,java,indent=0,subs="verbatim,quotes",role="primary"] +[source,java,indent=0,subs="verbatim",role="primary"] .Java ---- @Configuration @@ -3493,7 +3530,7 @@ use Java-based configuration, you can add `@EnableSpringConfigured` to any public class AppConfig { } ---- -[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] +[source,kotlin,indent=0,subs="verbatim",role="secondary"] .Kotlin ---- @Configuration @@ -3506,7 +3543,7 @@ If you prefer XML based configuration, the Spring <> defines a convenient `context:spring-configured` element, which you can use as follows: -[source,xml,indent=0,subs="verbatim,quotes"] +[source,xml,indent=0,subs="verbatim"] ---- ---- @@ -3518,10 +3555,10 @@ domain objects when it is initialized by Spring. In this case, you can use the `depends-on` bean attribute to manually specify that the bean depends on the configuration aspect. The following example shows how to use the `depends-on` attribute: -[source,xml,indent=0,subs="verbatim,quotes"] +[source,xml,indent=0,subs="verbatim"] ---- @@ -3614,7 +3651,7 @@ excerpt shows how you could write an aspect to configure all instances of object defined in the domain model by using prototype bean definitions that match the fully qualified class names: -[source,java,indent=0,subs="verbatim,quotes"] +[source,java,indent=0,subs="verbatim"] ---- public aspect DomainObjectConfiguration extends AbstractBeanConfigurerAspect { @@ -3647,7 +3684,7 @@ normal and include the `factory-method="aspectOf"` bean attribute. This ensures Spring obtains the aspect instance by asking AspectJ for it rather than trying to create an instance itself. The following example shows how to use the `factory-method="aspectOf"` attribute: -[source,xml,indent=0,subs="verbatim,quotes"] +[source,xml,indent=0,subs="verbatim"] ---- <1> @@ -3673,7 +3710,7 @@ declaration. Each `` element specifies a name pattern, and only beans names matched by at least one of the patterns are used for Spring AOP auto-proxy configuration. The following example shows how to use `` elements: -[source,xml,indent=0,subs="verbatim,quotes"] +[source,xml,indent=0,subs="verbatim"] ---- @@ -3741,7 +3778,7 @@ It is a time-based profiler that uses the @AspectJ-style of aspect declaration: [source,java,indent=0,subs="verbatim",role="primary",chomp="-packages"] .Java ---- - package foo; + package com.xyz; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Aspect; @@ -3765,14 +3802,14 @@ It is a time-based profiler that uses the @AspectJ-style of aspect declaration: } } - @Pointcut("execution(public * foo..*.*(..))") + @Pointcut("execution(public * com.xyz..*.*(..))") public void methodsToBeProfiled(){} } ---- [source,kotlin,indent=0,subs="verbatim",role="secondary",chomp="-packages"] .Kotlin ---- - package foo + package com.xyz import org.aspectj.lang.ProceedingJoinPoint import org.aspectj.lang.annotation.Aspect @@ -3796,7 +3833,7 @@ It is a time-based profiler that uses the @AspectJ-style of aspect declaration: } } - @Pointcut("execution(public * foo..*.*(..))") + @Pointcut("execution(public * com.xyz..*.*(..))") fun methodsToBeProfiled() { } } @@ -3807,19 +3844,19 @@ we want to weave our `ProfilingAspect` into our classes. This file convention, n the presence of a file (or files) on the Java classpath called `META-INF/aop.xml` is standard AspectJ. The following example shows the `aop.xml` file: -[source,xml,indent=0,subs="verbatim,quotes"] +[source,xml,indent=0,subs="verbatim"] ---- - + - + @@ -3833,7 +3870,7 @@ thing is that it does not require a lot of configuration (there are some more options that you can specify, but these are detailed later), as can be seen in the following example: -[source,xml,indent=0,subs="verbatim,quotes"] +[source,xml,indent=0,subs="verbatim"] ---- + class="com.xyz.StubEntitlementCalculationService"/> @@ -3858,10 +3895,10 @@ Now that all the required artifacts (the aspect, the `META-INF/aop.xml` file, and the Spring configuration) are in place, we can create the following driver class with a `main(..)` method to demonstrate the LTW in action: -[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"] +[source,java,indent=0,subs="verbatim",role="primary",chomp="-packages"] .Java ---- - package foo; + package com.xyz; // imports @@ -3878,10 +3915,10 @@ driver class with a `main(..)` method to demonstrate the LTW in action: } } ---- -[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"] +[source,kotlin,indent=0,subs="verbatim",role="secondary",chomp="-packages"] .Kotlin ---- - package foo + package com.xyz // imports @@ -3900,9 +3937,9 @@ switch on LTW selectively on a per-`ClassLoader` basis with Spring, and this is However, for this example, we use a Java agent (supplied with Spring) to switch on LTW. We use the following command to run the `Main` class shown earlier: -[literal,subs="verbatim,quotes"] +[literal,subs="verbatim"] ---- -java -javaagent:C:/projects/foo/lib/global/spring-instrument.jar foo.Main +java -javaagent:C:/projects/xyz/lib/spring-instrument.jar com.xyz.Main ---- The `-javaagent` is a flag for specifying and enabling @@ -3918,7 +3955,7 @@ implementation so that the profiler actually captures something other than 0 milliseconds (the `01234` milliseconds is not an overhead introduced by the AOP). The following listing shows the output we got when we ran our profiler: -[literal,subs="verbatim,quotes"] +[literal,subs="verbatim"] ---- Calculating entitlement @@ -3933,10 +3970,10 @@ Since this LTW is effected by using full-blown AspectJ, we are not limited only Spring beans. The following slight variation on the `Main` program yields the same result: -[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"] +[source,java,indent=0,subs="verbatim",role="primary",chomp="-packages"] .Java ---- - package foo; + package com.xyz; // imports @@ -3953,10 +3990,10 @@ result: } } ---- -[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"] +[source,kotlin,indent=0,subs="verbatim",role="secondary",chomp="-packages"] .Kotlin ---- - package foo + package com.xyz // imports @@ -4042,7 +4079,7 @@ enough because the LTW support uses `BeanFactoryPostProcessors`.) To enable the Spring Framework's LTW support, you need to configure a `LoadTimeWeaver`, which typically is done by using the `@EnableLoadTimeWeaving` annotation, as follows: -[source,java,indent=0,subs="verbatim,quotes",role="primary"] +[source,java,indent=0,subs="verbatim",role="primary"] .Java ---- @Configuration @@ -4050,7 +4087,7 @@ which typically is done by using the `@EnableLoadTimeWeaving` annotation, as fol public class AppConfig { } ---- -[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] +[source,kotlin,indent=0,subs="verbatim",role="secondary"] .Kotlin ---- @Configuration @@ -4063,7 +4100,7 @@ Alternatively, if you prefer XML-based configuration, use the `` element. Note that the element is defined in the `context` namespace. The following example shows how to use ``: -[source,xml,indent=0,subs="verbatim,quotes"] +[source,xml,indent=0,subs="verbatim"] ---- ` element. Again, the following example specifies a `ReflectiveLoadTimeWeaver`: -[source,xml,indent=0,subs="verbatim,quotes"] +[source,xml,indent=0,subs="verbatim"] ---- ---- @@ -4247,7 +4284,7 @@ To use it, you must start the virtual machine with the Spring agent by supplying the following JVM options: [literal] -[subs="verbatim,quotes"] +[subs="verbatim"] ---- -javaagent:/path/to/spring-instrument.jar ----