issues when using spring aop load-time weaving deal with methods call inside itself - spring

I have bussiness class as follow:
class A {
public void sayHello(String name){
System.out.println("hello "+name);
}
public void openDoorForJack(){
System.out.println("door opened");
this.sayHello("Jack");
}
}
and aspect class as follow:
#Aspect
class Aspect {
#Pointcut("execution (* com..*.sayHello(String)) && args(name)")
public void beforeSayHelloPointCut(String name) {}
#Before("beforeSayHelloPointCut(name)")
public void beforeSayHello(String name) throws Throwable {
System.out.println(name+" is knocking");
}
}
after I have all those beans configured in spring,I turn LTW on using
<aop:aspectj-autoproxy/>
<context:load-time-weaver aspectj-weaving="on" weaver-class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver"/>
of course aspectjrt,aspectj-weaver,spring-instrument are in position,-javaagent:path/spring-instrument.jar is passed to VM options and follow aop.xml is under META-INF
<!DOCTYPE aspectj PUBLIC
"-//AspectJ//DTD//EN" "http://www.eclipse.org/aspectj/dtd/aspectj.dtd">
<aspectj>
<weaver>
<!-- only weave classes in specific packages -->
<include within="*"/>
</weaver>
<aspects>
<!-- weave in just this aspect -->
<aspect name="com.Aspect"/>
</aspects>
</aspectj>
When I run test like:
applicationContext.getBean(A.class).sayHello("Jack");
result seems perfect
Jack is knocking
Hello Jack
But when I run test that call sayHello inside itself
applicationContext.getBean(A.class).openDoorForJack();
no interception happens at all
door opened
Hello Jack
The reason way I use LTW is that I want methods call using "this" or "super" can be intercepted as well,but seems I failed to do so.
Would someone help me point out the problem,is there something I missed?
----------------------------EDIT---------------------------------
After some debug I found where I got wrong
In real life,
I hava "class A" under package com.bussiness
and "class Aspect" under package com.aspect
I worte aop.xml like follow
<weaver>
<!-- only weave classes in specific packages -->
<include within="com.aspect.*"/>
</weaver>
which is not correct,it should be the package that contains classes need to be woven,after I changed it to
<weaver>
<!-- com package and its sub package all get woven-->
<include within="com..*"/>
</weaver>
It finally work

Try dynamic proxy, it should work. It's not easy but I think this is what you need.
More on this:
How to use AOP to intercept a method call in super on an argument?

Related

AOP Advice not getting executed

I am using AspectJ AOP with spring. I am NOT USING spring AOP but AspectJ AOP with spring.
I am using load time weaving. My advices are not getting executed. Any leads would greatly help.
#Aspect
public class ProfilingAspect {
#Around("methodsToBeProfiled()")
public Object profile(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("Hello #################");
return pjp.proceed();
}
#Pointcut("execution(public * com.core.search.domain.AIESearchDomainService.doSearch())")
public void methodsToBeProfiled() {
}
}
Following is the method on which I am trying to run the advice.
package com.core.search.domain;
public class AIESearchDomainService {
public SearchResponse doSearch() {
return null;
}
}
I have enabled load time weaving using the the below annotation.
#EnableLoadTimeWeaving
I have also specified the java agent for enabling the load time weaver as below.
-javaagent:"pathTo/spring-instrument-5.3.25.jar"
I have also created aop.xml and kept it in /resources/META-INF folder.
<aspectj>
<weaver>
<!-- only weave classes in our application-specific packages -->
<include within="com.core.search.domain.*"/>
</weaver>
<aspects>
<!-- weave in just this aspect -->
<aspect name="package.for.ProfilingAspect"/>
</aspects>
</aspectj>
There are no errors in the code but my advice is not getting executed. Please help. I believe weaving is happening because I am able to see the following log.
[AppClassLoader#18b4aac2] warning javax.* types are not being woven because the weaver option '-Xset:weaveJavaxPackages=true' has not been specified
I guess you forgot to enable aspectjWeaving param
#EnableLoadTimeWeaving(aspectjWeaving=ENABLED)

Context vs context - setting ignore-unresolvable="true" - PropertyPlaceholderConfigurer

Problem
I'm trying to set ignore-unresolvable="true".
I have found the answer https://stackoverflow.com/a/11773267/1688441 from the question how to define not mandatory property in spring? .
The example they show is:
<context:property-placeholder ignore-unresolvable="true" ... />
However, in the project I have inherited we have a project file called project.xml that contains Resource definitions with a Context tag.
<?xml version="1.0" encoding="UTF-8"?>
<Context>
<Resource />
<ResourceLink />
<Resource />
</Context>
Note: The resources have been removed
When I edit the Context tag to add ignore-resolvable everything breaks and not even my DataSource resource is read. Anyone have any ideas?
I tried the following:
<Context:property-placeholder ignore-unresolvable="true">
Possibly related:
spring PropertyPlaceholderConfigurer and context:property-placeholder
It turns out that in the specific project a class based configuration was being used instead of XML. I found the following class to which I added setIgnoreUnresolvablePlaceholders(false) in the method that returns PropertySourcesPlaceholderConfigurer:
#Configuration
#ComponentScan
#EnableWebMvc
#EnableAsync
#EnableScheduling
#PropertySource(value = {"classpath:appProp.properties"})
#Import({ExternalizeConfiguration.class, AppApplication.class,
AppPersistenceApplication.class, ConnectBoIntegrationApplication.class})
public class AppWebApplication extends WebMvcConfigurerAdapter {
...Other Code...
/**
* Bean required for Value annotation
*/
#Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
PropertySourcesPlaceholderConfigurer test = new PropertySourcesPlaceholderConfigurer();
test.setIgnoreUnresolvablePlaceholders(false);
return test;
}
}
So my understanding is that annotating this method as #Bean causes the method to execute whenever an object of type PropertySourcesPlaceholderConfigurer is auto-wired. In this way, we control which instance is used and what params are set on it.

Why is Mybatis mapper scanner picking up wrong class

I use Spring with Mybatis. I have it configured to scan for mappers in my whole project and I assumed it determined a mapper because it found an XML file which has reference to a java interface.
But this is proven incorrect today because I had to add a new interface which is not a mapper class and Mybatis thinks it is, so it is causing problems in my app due to this error:
Mapped Statements collection does not contain value for com.blah.MyInterface.someMethod
com.blah.MyInterface is just a simple interface which I needed to be included in Spring context so I gave it the #Component tag. Is that the wrong tag to use? Is that where the confusion comes from?
I just needed to create this interface so that I can have a proxy wrap my database calls in one place where I can put a #Transactional tag, since Spring ignores it when it is in my Controller method.
Sample code
package com.blah.something;
#Component public interface MyInterface {
public void someMethod( SomeObject obj) throws Exception;
}
package com.blah.something;
public class MyImplementation implements MyInterface {
#Transactional
public void someMethod( SomeObject obj) throws Exception {
... do a whole bunch of stuff
}
}
I dont want this included in the MyBatis mappers!
Edit: added the mybatis config xml as requested:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<setting name="lazyLoadingEnabled" value="false" />
<setting name="defaultStatementTimeout" value="60"/>
</settings>
<typeAliases>
<typeAlias alias="StripTrailingZerosBigDecimalTypeHandler" type="com.blah.typehandlers.StripTrailingZerosBigDecimalTypeHandler"/>
</typeAliases>
</configuration>
This is the part of my spring xml config which calls the mybatis mapper scanner:
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.blah" />
</bean>
So I set it to scan the whole project which includes my interface above but I can't imagine it just grabs every single interface and considers them all mappers!
In my debug log I see mybatis picking up my interface:
12/9/13 11:18:44 904 [org.mybatis.spring.mapper.MapperScannerConfigurer$Scanner.findCandidateComponents:4125] - Scanning file [D:\Weblogic\wls11\domains\ldapdomain\autodeploy\default\WEB-INF\classes\com\blah\MyInterface.class]
12/9/13 11:18:44 904 [org.mybatis.spring.mapper.MapperScannerConfigurer$Scanner.findCandidateComponents:4125] - Identified candidate component class: file [D:\Weblogic\wls11\domains\ldapdomain\autodeploy\default\WEB-INF\classes\com\blah\MyInterface.class]
12/9/13 11:18:44 904 [org.mybatis.spring.mapper.MapperScannerConfigurer$Scanner.findCandidateComponents:4125] - Scanning file [D:\Weblogic\wls11\domains\ldapdomain\autodeploy\default\WEB-INF\classes\com\blah\MyImplementation .class]
12/9/13 11:18:44 904 [org.mybatis.spring.mapper.MapperScannerConfigurer$Scanner.findCandidateComponents:4125] - Ignored because not a concrete top-level class: file [D:\Weblogic\wls11\domains\ldapdomain\autodeploy\default\WEB-INF\classes\com\blah\MyImplementation .class]
There is no XML for this interface, there is no mapper namespace for it, it's just a plain old regular interface and MyBatis should not be thinking it is a mapper service
Ok it looks like MyBAtis scanner does indeed take every interface, it does not have any "smarts" in it to identify mapper interfaces as I thought it would - based on finding matching XML or namespaces. I had to add a filter to the mapper configuration and then introduce a new annotation to annotate my mapper interfaces.

No matching factory method found: factory method 'aspectOf()'

I have the following aspect:
package trc.suivi.aspects;
import java.util.Date;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import trc.suivi.domain.EvenementPli;
import trc.suivi.domain.Pli;
import trc.suivi.domain.TypeEvenement;
import trc.suivi.repository.EvenementPliRepository;
public aspect PliEventManagerAspect {
private static final Logger log = Logger.getLogger(PliEventManagerAspect.class);
#Autowired
private EvenementPliRepository evenementPliRepository;
public PliEventManagerAspect() {
}
pointcut catchEMPersist(Pli pli) : (execution(* trc.suivi.repository.PliRepository+.save(*)) && args(pli));
pointcut catchEMPersist() : (execution(trc.suivi.domain.Pli.persist()));
after(Pli pli) returning: catchEMPersist(pli) {
log.debug("catchEMPersist(pli)");
EvenementPli ev = new EvenementPli();
ev.setDateCreation(new Date());
ev.setType(TypeEvenement.creation);
ev.setMessage("Création d'un pli");
evenementPliRepository.save(ev);
}
after() returning: catchEMPersist() {
log.debug("catchEMPersist()");
EvenementPli ev = new EvenementPli();
ev.setDateCreation(new Date());
ev.setType(TypeEvenement.creation);
ev.setMessage("Création d'un pli");
evenementPliRepository.save(ev);
}
}
And the following xml config:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">
<aop:aspectj-autoproxy />
<bean class="trc.suivi.aspects.PliEventManagerAspect" factory-method="aspectOf"/>
</beans>
When I start my app, I get this:
No matching factory method found: factory method 'aspectOf()'. Check that a method with the specified name exists and that it is static.
I am quite dumbfounded as I am pretty sure this config worked fine before. What is more this is a Spring Roo project so all the aspectJ config should be fine.
Can anyone please help?
This is probably because your aspect has not compiled for whatever reason, can you try and add more diagnostic to your aspectj weaver plugin and see what is being printed on the console, along these lines:
<configuration>
<outxml>true</outxml>
<showWeaveInfo>false</showWeaveInfo>
<Xlint>warning</Xlint>
<verbose>true</verbose>
...
</configuration>
Also since you are using raw aspectj you don't really need to use <aop:aspectj-autoproxy/> which is used to trigger Spring AOP.
I was having the same error message come up. I solved it by looking at rozky's answer here: http://forum.springsource.org/showthread.php?79928-NoSuchMethodError-Aspect-aspectOf%28%29
For the sake of recording the answer, I've copied it here:
rozky wrote:
Hi,
I had a same problem. I found out that the weaving need to be enabled also for aspect classes in aop.xml file. In your case it is (see highlighted part):
<!DOCTYPE aspectj PUBLIC
"-//AspectJ//DTD//EN" "http://www.eclipse.org/aspectj/dtd/aspectj.dtd">
<aspectj>
<weaver options="-verbose -showWeaveInfo -debug">
<!-- only weave classes in our application-specific packages -->
<include within="com.mypackage.*"/>
<include within="foo.*"/> <!-- this is the highlighted line -->
</weaver>
<aspects>
<!-- weave in just this aspect -->
<aspect name="foo.ProfilingAspect"/>
</aspects>
</aspectj>
Hope it helps.

perf4j #Profiled annotation not working

I have gone thru the below link from perf4J site and have done same to same: http://perf4j.codehaus.org/devguide.html#Using_Spring_AOP_to_Integrate_Timing_Aspects
Added the following in my spring.xml.
<aop:aspectj-autoproxy/>
<bean id="timingAspect" class="org.perf4j.log4j.aop.TimingAspect"/>
<bean id="wscClientBase" class="com.xyz.csa.core.common.WscClientBase"/>
In class WscClientBase I have the following method with #Profiled annotation.
#Profiled(tag = "SOAPCALLTEST")
public Object sendMessage(Object message) {
String msg = message.toString();
if (msg.indexOf(' ') > 1) {
msg = msg.substring(1, msg.indexOf(' '));
}
try {
Object ret = marshalSendAndReceive(message);
return ret;
} catch (RuntimeException ex) {
throw ex;
}
}
I dont see the perf4j TimingLogger statements in the application log. However if I use it obtrusively (without annotation) as below, I see the log statements successfully.
public Object sendMessage(Object message) {
String msg = message.toString();
if (msg.indexOf(' ') > 1) {
msg = msg.substring(1, msg.indexOf(' '));
}
StopWatch stopWatch = new Slf4JStopWatch();
try {
Object ret = marshalSendAndReceive(message);
stopWatch.stop("PERF_SUCCESS_TAG", msg);
return ret;
} catch (RuntimeException ex) {
stopWatch.stop("PERF_FAILURE_TAG", msg);
throw ex;
}
}
Am I missing something?
Perf4j
This is a performance analysis and checking plugin for application. It can be integrated with spring using spring AOP. It creates a log file that is give to a parser to analyse and produce relevant information. It can provide average,mean, std deviation by default.
For more general information please check http://perf4j.codehaus.org/index.html
How to setup Perf4j.
For normal setup you just need to add perf4j jar and create StopWatch instance for every code sniplet you want to monitor.
StopWatch stopWatch= new StopWatch(“snipletTagName”)
…
//{your code sniplet}
…
stopwatch.stop();
This will create perf4j monitor and you will get logg information on the console.
Main purpose of this documentation is to have a setup by setup understanding of integrating perf4j with spring.
1.Add all of the below Jar files.
1.perf4j-0.9.16-slf4jonly.jar
2.aspectjweaver-1.6.12.jar
3.aopalliance-1.0.jar
4.commons-logging-1.1.1.jar
5.logback-classic-1.0.7.jar
6.logback-core-1.0.7.jar
7.slf4j-api-1.7.1.jar
8.perf4j-0.9.16.jar
9.aspectjrt-1.6.1.jar
10.commons-jexl-1.1.jar
11.asm-1.5.3.jar
12.cglib-2.1_3.jar
Make sure you have all these jars in your classpath along with spring libraries.
2.create your own logback.xml that will be used by perf4j implicitly
the content of the logback.xml will be
<configuration>
<appender name="perf4jFileAppender"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<File>logs/perf4j.log</File>
<encoder>
<Pattern>%date %-5level [%thread] %logger{36} [%file:%line] %msg%n
</Pattern>
</encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<FileNamePattern>logs/perf4j.%d{yyyy-MM-dd}.log</FileNamePattern>
</rollingPolicy>
</appender>
<appender name="CoalescingStatistics"
class="org.perf4j.logback.AsyncCoalescingStatisticsAppender">
<param name="TimeSlice" value="1" />
<appender-ref ref="perf4jFileAppender" />
</appender>
<appender name="RootConsoleAppender" class="ch.qos.logback.core.ConsoleAppender">
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>debug</level>
</filter>
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern>%date %-5level [%thread] %logger{36} [%file:%line] %msg%n
</pattern>
</layout>
</appender>
<!-- Loggers -->
<!-- The Perf4J logger. Note that org.perf4j.TimingLogger is the value of
the org.perf4j.StopWatch.DEFAULT_LOGGER_NAME constant. Also, note that additivity
is set to false, which is usually what is desired - this means that timing
statements will only be sent to this logger and NOT to upstream loggers. -->
<logger name="org.perf4j.TimingLogger" additivity="false">
<level value="DEBUG" />
<appender-ref ref="CoalescingStatistics" />
<appender-ref ref="perf4jFileAppender" />
<appender-ref ref="RootConsoleAppender" />
</logger>
</configuration>
3.In your spring configuration file you need to add aspectj tag that will enable #Profiled annotation of perf4j.
(Note: What is #Profiled annotation?: you will add this tag to all the
methods in all the classes that are called from spring instance or use
dependency injection. The object basically should be spring context
registered and the method should be invoked by the object that are
registered in spring context. I wasted one day thinking why my method
was not logged then I realized that the object I tested was not part
of spring context.
OK, the code that you need to add to spring configuration xml is
<!-- this is my spring-context.xml -->
<beans>
<aop:aspectj-autoproxy>
<aop:include name="timingAspect" />
</aop:aspectj-autoproxy>
<bean id="timingAspect" class="org.perf4j.slf4j.aop.TimingAspect" />
<!-- this is the class that will be registered with the spring and now we can get this class and call the method that we need to monitor-->
<bean class="com.perf4jexample.Test" />
</beans>
4.Create the Test class that will implement #Profiled annotation.
public class Test {
private String testVal;
public Test() {
// TODO Auto-generated constructor stub
}
#Profiled
public void testing() {
System.out.println("testt" );
}
public String getTestVal() {
return testVal;
}
public void setTestVal(String testVal) {
this.testVal = testVal;
}
}
5.Ok now you have setup every thing just thing remains is test class that will start spring context and with it load perf4j.
public class Test(){
public static void main(){
AbstractApplicationContext context = new ClassPathXmlApplicationContext(
"spring-context.xml");
context.start();
Test bean = context.getBean(Test.class);
bean.testing();
}
I hope by following these setups you should be able to perf4j console appender to display one line on console.
Perf4j Monitoring command on the log:
For Generating Performance statistical information execute on you logger path
java -jar perf4j-0.9.16.jar myLogger.log
For Generating Graphs
java -jar perf4j-0.9.16.jar --graph perfGraphs.out myLogger.log
I hope this tutorial helps you to integrated Spring, perf4j, logback with Profiled annotation.
Try adding <aop:include name="timingAspect"/> inside the <aop:aspectj-autoproxy/>.
Can you also confirm that you are invoking sendMessage on an object that is retrieved from the spring application context (using getBean or injected as a dependency).
Here I have two ways to make perf4j #Profiled work on spring boot project.
Precondition is adding below dependencies
"org.aspectj:aspectjweaver",
"org.perf4j:perf4j:0.9.16",
"commons-jexl:commons-jexl:1.1",
"cglib:cglib:3.2.1",
For normal spring project, probably need to add little more dependencies like spring-aop, aopalliance... those looks included in spring-boot-starter-parent
1. Java Configuration
This is simplest way and mostly works, but I found that somehow not working on spring-data JpaRepository method. It just provides org.perf4j.log4j.aop.TimingAspect bean and do aspectj autoproxing. Same way like xml configuration provided by other people above
#Configuration
#EnableAspectJAutoProxy
public class PerformanceConfig {
#Bean
public TimingAspect timingAspect() {
return new TimingAspect();
}
}
2. Provide Your own Aspect
In this way, the #Profiled annotated spring-data repository interface methods also work fine. But the downside of this is ignoring the tag given in #Profiled(tag='some tag') and using the joinPoint method name as tag.
#Aspect
#Component
public class PerformanceTracker {
#Around(value="execution(#org.perf4j.aop.Profiled * com.mypackage..*(..))")
public Object checkPerformance(ProceedingJoinPoint pjp) throws Throwable {
StopWatch stopWatch = new Log4JStopWatch(pjp.getSignature().toShortString());
Object result = pjp.proceed();
stopWatch.stop();
return result;
}
}
The reason why it could not work is that the profiled method is in the parent class of the Spring-bean. I can tell it by looking at your bean name: WscClientBase. I assume that this is base class from which you have many children classes.
After some research time I found very important note in Spring documentation about #Transactional and #Cacheable.
http://docs.spring.io/spring-framework/docs/current/spring-framework-reference/html/transaction.html#transaction-declarative-annotations. Check “Method visibility and #Transactional” block.
http://docs.spring.io/spring/docs/current/spring-framework-reference/html/cache.html#cache-annotation-enable. Check “Method visibility and cache annotations”
In both cases they say things like this:
“When using proxies, you should apply the <> annotations only to
methods with public visibility. If you do annotate protected, private
or package-visible methods with these annotations, no error is raised,
but the annotated method does not exhibit the configured caching
settings. Consider the use of AspectJ (see below) if you need to
annotate non-public methods as it changes the bytecode itself.”
And below…
“Spring recommends that you only annotate concrete classes (and
methods of concrete classes) with the #Cache* annotation, as opposed
to annotating interfaces. You certainly can place the #Cache*
annotation on an interface (or an interface method), but this works
only as you would expect it to if you are using interface-based
proxies. The fact that Java annotations are not inherited from
interfaces means that if you are using class-based proxies
(proxy-target-class="true") or the weaving-based aspect (
mode="aspectj"), then the caching settings are not recognized by the
proxying and weaving infrastructure, and the object will not be
wrapped in a caching proxy, which would be decidedly bad.”
I assume that #Profiled use similar weaving mechanism therefore you can't put #Profiled on any method in parent classes.
As a matter of fact I had similar issue in my application: I had #Profiled and #Cacheable in parent class and none of those worked: I didn't see any records in my Perf4J log and cache wasn't updated. When I moved #Profiled into methods of children-classes I started seeing the records in the perf4j.log.
put config below in your "servlet-context-config.xml" .have fun!
<aop:aspectj-autoproxy/>
<bean id="timingAspect" class="org.perf4j.log4j.aop.TimingAspect"/>
<bean id="wscClientBase" class="com.xyz.csa.core.common.WscClientBase"/>
For people who have this type of problem they can check that there is not in spring logs (level info), messages like it " is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)".

Resources