Initialising Spring AOP hangs the entire application after few successful requests - java

I have Spring 5.0.4 application with a Dispatcher servlet config file as spring-web-servlet.xml (spring-web being Dispatcher servlet name).
To enable AOP in the application, I made the entry <aop:aspectj-autoproxy /> in spring-web-servlet.xml after including the namespace for aop.
The pom.xml has below entries:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.0.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.6.11</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.6.11</version>
</dependency>
To use AOP, I created below Aspect class:
#Aspect
#Component
public class MyAspect {
#Before("getApiPointcut()")
public void logRequest(JoinPoint joinPoint) {
//some logic here
}
#AfterReturning(value = "getApiPointcut()", returning = "returnValue")
public void logResponse(Object returnValue) {
//some logic here
}
#Pointcut("within(com.test.service.controller.*) " +
" || within(com.test.service.api.GenericService)" +
" || within(com.test.service.api.UserService)")
public void getApiPointcut() {
}
}
This class has two methods: logRequest() and logResponse().
Every API call will first go through logRequest() and before returning the response, logResponse() is called.
For the initial few requests (5-6), AOP works fine and I get the flow in MyAspect class for both the methods.
But after that, if I hit any API, flow goes through logRequest(), then the API class, and then it hangs. The API class calls the service class. But the flow never reaches the service class and hence never goes in logResponse() and the server does not return anything to the client. I checked the logs and there are no exceptions. I checked the heap memory usage too and it is not consumed fully. Even the threads are not fully occupied. (Checked these stats using jconsole).
If I disable AOP by removing <aop:aspectj-autoproxy /> from spring-web-servlet.xml file, the server returns response for all the calls without any issue.
So, the conclusion that I made is enabling the AOP is causing the server to hang but I am not able to understand why.
Any help is appreciated.
UPDATE
The APIs (controller) on which I am trying to invoke AOP are annotated with #PreAuthorize. If I comment out the #PreAuthorize annotation, the application does not hang. Uncommenting the #PreAuthorize annotation again results in 5-6 successful requests and then the application hangs.
As #PreAuthorize also uses AOP, is there any case that I need to take care of when using my own AOP with #PreAuthorize?
UPDATE 2
The #PreAuthorize method on the API is as below:
#PreAuthorize("hasAuthority('SOME_AUTH') and #myUtil.canRead(#userId) ")
If I remove the hasAuthority('SOME_AUTH') and keep the second check, the aplication works fine, but if I keep both or keep only hasAuthority() check, the application does not responds after a few successful responses.
UPDATE 3
The issue gets resolved if I annotate the API with #Transactional.
However, the code used to work without #Transactional when aop was disabled. So why does enabling AOP makes it necessary to have #Transactional on the API?

Related

Spring AOP this() PCD context binder doesn't work with aspect instantiation model perthis()

I'm trying to log which aspect instance is responsible for which proxied object. However, when I'm collecting proxy object context through this() PCD and using perthis() instantiation model I'm getting an error related to the variable name of proxy object that I use in the pointcut expression:
warning no match for this type name: bean [Xlint:invalidAbsoluteTypeName]
Maven dependencies that I use:
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>6.0.3</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>6.0.3</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.19</version>
</dependency>
</dependencies>
This is an aspect that I use to implement that I needed:
#Aspect("perthis(com.sj.aspects.AssociationsAspect.exampleBeans())")
#Component
#Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class AssociationsAspect {
public AssociationsAspect(){
System.out.println("Creating aspect instance!");
}
#Pointcut("execution(* com.sj.utilities.Example.*(..))")
public void exampleBeans(){};
#Pointcut("execution(* com.sj.utilities.Example.*(..)) && this(bean)")
public void exampleOperations(Object bean){};
#Before(value = "exampleOperations(bean)", argNames = "jp,bean")
public void beforeExampleMethodsExecution(JoinPoint jp, Object bean){
System.out.println(
"JoinPoint: " + jp.getStaticPart() +
"\n\taspect: " + this +
"\n\tobject: " + bean
);
}
}
I tried to change bean as variable name to concrete type, but from documentation it will give different from binding result:
Any join point (method execution only in Spring AOP) where the proxy implements the AccountService interface:
this(com.xyz.service.AccountService)
As well as it will be changing exiting error to another:
error at ::0 formal unbound in pointcut
Funny enough, if you put away ("perthis(com.sj.aspects.AssociationsAspect.exampleBeans())") then everything will work fine and Spring container will create a separate aspect instance for every proxy object in it. However that is not desirable and most likely a bug, because through #Scope() annotation I only say that there can be multiple instances of same aspect and that Spring container will need to create new instance when I told it to do, but not that it need to create them when it wants to.
The final solution to which I came was to use JoinPoint reflection API instead of collecting context through this() PCD. And it works fine, however I have preconceptions related to how #Scope() works without perthis() instantiation model and with it.
In the end I want to know, 'Is there a solution for collecting proxy object context with this() PCD and using perthis() instantiation model at the same time?'. As well as what are mistakes in the aspect that I described earlier, that give such an error.
I am assuming that you got the syntax example for perthis() from this part of the Spring manual. Unfortunately, the syntax is wrong. Inside perthis(), you need to specify a valid pointcut such as, not just a method name without even a return type. Examples for valid clauses would be:
perthis(myPointcut()), if myPointcut is specified as a separate, named pointcut
perthis(this(org.acme.MyClass))
perthis(execution(* doCommand(..))
perthis(execution(* doCommand(..)) && this(org.acme.MyClass))
See also the AspectJ documentation here and there. Unfortunately, documentation is sparse.
In your particular case, you might want:
perthis(execution(* com.sj.utilities.Example.*(..)))
Update: I created Spring pull request # 29998 in order to improve the documentation.

Intercept nested methods using native AspectJ in Spring Boot

I am trying to intercept any method in my application which is annotated with my custom developed annotation.
Initially I used the Spring AOP which works fine. But, it is not intercepting if the method call is in the same target class.
Going through the official docs, I got to know that the Spring AOP uses proxy beans for the same.
One workaround I found was to self inject the target class. But, this seems like too much fuss. Like every time I am adding my custom annotation to a method, I need to make sure that I add the #Scope annotation, set the proxyMode & self inject target class as shown here
Later I moved on to configuring and using native AspectJ.
This is my Custom annotation:
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
public #interface TrackTime {
String description() default "";
}
Here is the Aspect for TrackTime annotation:
#Configuration
#Slf4j
#Aspect
public class TrackTimeServiceImpl {
#Pointcut("execution(public * *(..))")
public void methodsToBeProfiled(){
}
#Around("methodsToBeProfiled() && #annotation(x.y.z.TrackTime)")
public Object audit(ProceedingJoinPoint joinPoint) throws Exception {
//Business logic
}
}
I would like to mention here that my application is running on Jetty server.
The configuration file:
#Configuration
#EnableLoadTimeWeaving(aspectjWeaving = EnableLoadTimeWeaving.AspectJWeaving.ENABLED)
#EnableSpringConfigured
#EnableAspectJAutoProxy(proxyTargetClass = true)
public class TrackTimeConfig implements LoadTimeWeavingConfigurer {
#Override
public LoadTimeWeaver getLoadTimeWeaver() {
return new InstrumentationLoadTimeWeaver();
}
}
The aop.xml file:
Path to file: /resources/META-INF/aop.xml
<!DOCTYPE aspectj PUBLIC "-//AspectJ//DTD//EN" "https://www.eclipse.org/aspectj/dtd/aspectj.dtd">
<aspectj>
<weaver>
<!-- only weave classes in our application-specific packages -->
<include within="in.xxx.*"/>
</weaver>
<aspects>
<!-- weave in just this aspect -->
<aspect name="in.xxx.yyy.zzz.TrackTimeServiceImpl"/>
</aspects>
</aspectj>
Relative dependencies added in parent pom.xml have been mentioned here:
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.13</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.3.21</version>
</dependency>
My service class:
#Component
public class SomeService {
public void a(){
b();
}
#TrackTime
public void b(){
//business logic
}
}
Now when the method a() is called from the controller, even though the b() has the #TrackTime annotation, it is not intercepted.
Also, I would like to mention that I have set the following program arguments while running the application
-javaagent:/Users/xxx/.m2/repository/org/springframework/spring-instrument/5.3.6/spring-instrument-5.3.6.jar
-javaagent:/Users/xxx/.m2/repository/org/aspectj/aspectjweaver/1.9.6/aspectjweaver-1.9.6.jar
I have gone through docs, articles, followed solutions on stackoverflow. But, for the above mentioned configuration/code, it is not working as I want.
Requesting help from the community.
Thanks in advance.
I did not try to run your example locally yet, but noticed two details at first glance in your code:
You are configuring both #EnableLoadTimeWeaving (for native AspectJ) and #EnableAspectJAutoProxy (for Spring AOP), which might be conflicting with each other. Try to remove the latter and see if it fixes the problem.
In aop.xml, you are using <include within="in.xxx.*"/>. Please note that this will only include classes directly in the in.xxx package, but not classes in sub-packages. In order to include them as well, please use the double-dot notation in.xxx..*.
Feel free to report back if it is still not working with the suggested changes. I can take a closer look then.
First of all, I would like to thank #hfontanez, #void void & #kriegaex for responding and helping me out in moving forward in solving the problem statement.
So if anyone is looking out on how to intercept nested & private methods, let's have this as a one stop in configuring native AspectJ.
Please check my POC here on github for a working example.
In my case, I added the aspectjweaver JAR in my project structure and passed the arguments through VM Options in IDE.
That all !!
Nested/Private methods will now be intercepted.
Thank you,
Karthik

Resilience4J in Springboot is not working as expecting

I'm trying to add resilience4j into my app for exponential backoff, etc.
Service
#Component
public class ResilienceService {
private static final String BACKEND_A = "backendA";
public ResilienceService() throws IOException {
testRetry();
}
#Retry(name = BACKEND_A)
public void testRetry() throws IOException {
System.out.println("Hey it's working!");
throw new IOException();
}
}
Config
resilience4j.retry.instances.backendA.maxAttempts=3
resilience4j.retry.instances.backendA.waitDuration=10s
resilience4j.retry.instances.backendA.enableExponentialBackoff=true
resilience4j.retry.instances.backendA.exponentialBackoffMultiplier=2
resilience4j.retry.instances.backendA.retryExceptions[0]=java.io.IOException
I'm trying to basically see if resilience lib will call this function 3 times. How should I think about both configuring this correctly and also testing that the retries are actually happening? I thought I could put a breakpoint on the method and see it call 3 times, but maybe I'm misunderstanding.
Aside from the comment by #M.Deinum above, you may also have caught out by resilience4j-springboot2 not depending on spring aop by default.
E.g. you might need:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
</dependencies>
To be fair, the documentation does state:
Add the Spring Boot 2 Starter of Resilience4j to your compile dependency.
The module expects that org.springframework.boot:spring-boot-starter-actuator and org.springframework.boot:spring-boot-starter-aopare already provided at runtime

How to run a method before some special methods?

In my business, I have to execute a method (imagine an access controll-like method) before some special methods(e.g. save, update,etc) to check some prerequisites and then execute the intended method. It is obvious that the most simple way is to call that controlling method at the very beginning lines of those methods, but I'm looking for something like #Before. something clean.
Any answer/hints will be appreciated.
You can use Spring AOP + AspectJ
In simple, Spring AOP + AspectJ allow you to intercept method easily.
Common AspectJ annotations :
#Before – Run before the method execution #After – Run after the
method returned a result #AfterReturning – Run after the method
returned a result, intercept the returned result as well.
#AfterThrowing – Run after the method throws an exception #Around –
Run around the method execution, combine all three advices above.
Steps
1. First you should enable AspectJ
To enable AspectJ, you need aspectjrt.jar, aspectjweaver.jar and spring-aop.jar. See following Maven pom.xml file.
<!-- Spring AOP + AspectJ -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.6.11</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.6.11</version>
</dependency>
2. Enable AspectJ
In your context config file add
<aop:aspectj-autoproxy />
3. After that use AspectJ #Before
In below example, the method1() method will be executed before the execution of method2() method.
#Aspect
public class MyAspect {
#Before("execution(* your.package.method2(..))")
public void method1(JoinPoint joinPoint) {
System.out.println("method1() is running!");
System.out.println(" ---- " + joinPoint.getSignature().getName());
System.out.println("******");
}
}

JUnit weaving wrong Spring AOP Bean

I've run into a strange problem that I am having difficulty tracking down. I have an class (ServiceErrorInterceptor) defined as an #Aspect which is instantiated via XML configuration as a singleton bean. The XML configuration allows me to inject its dependent beans.
In my normal workflow, everything works fine. The aspect class is properly instantiated, and whenever the advice is called, the injected beans are as I would expect.
However, when I run my JUnit test, all my injected beans are null. This leads me to the conclusion that the advice is called from a different bean - not the same singleton bean that was instantiated by Spring. To further validate my hypothesis, I put a breakpoint on a setter which is called during the instantiation, and see that the bean id is not the same as the bean id if I put a breakpoint in my advice.
Is there some special configuration I must enable in my JUnit class to rectify this? My test class is already annotate with:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {
"classpath:spring/applicationContext-base.xml",
"classpath:spring/applicationContext-calculateServices.xml",
"classpath:spring/applicationContext-dom.xml"})
public class LendingSimulationServiceImplTest {
...
...
}
I've looked through the logs (I enabled spring trace logs), but don't see anything that stands out. And posting the entire log here would likely be overkill. If there is value in a specific part of the log please let me know and I will post it.
I'm able to post my code for the aspect, my junit and my config if that is helpful.
application-context.xml snippet:
<!-- SPRING ASPECT BEAN. POINTCUT DEFINED IN BEAN WITH ANNOTATION -->
<bean id="serviceErrorInterceptor" class="com.cws.cs.lendingsimulationservice.error.ServiceErrorInterceptor" scope="singleton">
<property name="errorMessageProvider" ref="resourceBundleProviderImpl"/>
<property name="defaultLocale">
<util:constant static-field="java.util.Locale.ENGLISH" />
</property>
</bean>
Any suggestions would be appreciated.
EDIT
My bean is implemented as:
#Aspect
public class ServiceErrorInterceptor {
/**
* Logger
*/
private static final Logger logger = LoggerFactory.getLogger(ServiceErrorInterceptor.class);
/**
* SOAP Header data
*/
#Autowired
private SOAPHeaderData soapHeaderData;
public ServiceErrorInterceptor(){
int x = 0;
x=x+1;
}
/**
* Exception Interceptor.
* #param ex
*/
#AfterThrowing(pointcut = "execution(* com.cws.cs.lendingsimulationservice.process.CalculatorProcess.calculate (..))", throwing = "ex")
public void errorInterceptor(Exception ex) {
if (logger.isDebugEnabled()) {
logger.debug("Error Message Interceptor started");
}
}
The relevant portions of my pom:
<!-- Aspect Oriented Programming (AOP) Framework (depends on spring-core,
spring-beans) Define this if you use Spring AOP APIs (org.springframework.aop.*) -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<!-- Support for AspectJ Annotations -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>${org.aspectj}</version>
</dependency>
I've done further debugging and putting a breakpoint in the dummy constructor, I get the following results:
with #Aspect and XML configuration, the constructor is called twice (different bean ids)
if I remove the #Aspect annotation then it is only called once.
If leave the #Aspect but remove the XML configuration, then the constructor isn't even called.
If I use an #Component annotation in combination with #Aspect (but without any XML configuration), then the bean is constructed twice.
Oddly enough, however, with both the #Component and #Aspect annotations AND the XML configuration, the constructor is still only called twice.
So then why would having both the XML configuration and the #Aspect annotation cause the constructor to be called twice with two different bean ids?
I have further validated that if I move the entire AOP definition into the XML configuration (removing the #Aspect and #Pointcut annotations) then the bean is only constructed once.
END EDIT
Thanks,
Eric
Does your aspect by any chance have any of the autodetect annotations (#Component, #Service) etc, apart from #Aspect - if it does, that could be one reason why a different bean seems to be present along with the one defined in your configuration.
Also, just scan through all your configuration to make sure that you are not declaring this bean elsewhere.
There is nothing special that needs to be done at the Junit level that I am aware of.
After a lot of discussion with the folks over at the SpringSource STS forum (see this thread), it turns out that the issue is related to the AJDT configuration. At the moment, AJ is weaving in the aspect, and Spring is locating the aspect on the Classpath, so they are both being executed.
Unfortunately, the AJ maven plugin is missing a configuration parameter to allow for exclusion of weaving; the current configuration excludes both LTW and CTW.
So, the workaround at the moment is to add -xmlConfigured to the AJ compiler flags and then specify an aop.xml file in aop.xml management which only lists the AJ aspects that you want to include in the project.
To get this to work, add '-xmlConfigured' to the Project Properties
'Non-standard compiler options' and then in AspectJBuild>'aop.xml
management' point it at a simple aop.xml file:
<aspectj>
<aspects>
<aspect name="com.fooMyNewNoneSpringAspect"/>
</aspects>
</aspectj>
Thanks to Andy Clement at the STS forum for this discovery and workaround. He will be raising JIRA issues to further address this shortcoming in the maven plugin.
A possible way you might find yourself in the same situation: you used the new operator rather than letting Spring inject your service.
Remember, we're not in AspectJ compile time weaving here. Nope, we're using Spring AOP proxies, so Spring must instantiate the object and dress it with proxies. If you were silly, like myself, and created a new service inside your tests, you won't get any AOP.
All the more reason to do compile time weaving with AspectJ and skip over all of the drawbacks of Spring AOP such as runtime weaving startup delay, inability to weave non-public and non-final classes.

Categories

Resources