I want to log time spent to log file when invoke some service methods , now I implement it by AOP, e.g.
#Around("execution(* sample..TaskService.*(..))")
public Object aroundStat(ProceedingJoinPoint joinPoint) throws Throwable {
long start = System.currentTimeMillis();
Object proceed = joinPoint.proceed();
long end = System.currentTimeMillis();
String methodName = joinPoint.getSignature().getName();
log.info("{} taken time: {} ms",methodName,(end-start));
return proceed;
}
but I want to know how could implement it by using Annotation just like #Trasactional, e.g.
#Service
#TimeLogging
public class TaskService {
#TimeLogging
List<TaskStatDTO> taskStatusStat(String name){
//...
}
List<TaskStatDTO> finishedTaskStat(String name){
//...
}
//...
}
Could I implement some class and override some method?
don't use system time for measure time execution , use StopWatch from spring or apache. see good example - Measure execution time in Java – Spring StopWatch Example and spring api StopWatch
long start = System.currentTimeMillis();
long end = System.currentTimeMillis();
(end-start)
change to
StopWatch watch = new StopWatch();
watch.start();
..... execution
watch.stop();
watch.getTotalTimeMillis()
instead of
#Around("execution(* sample..TaskService.*(..))")
use
#Around("execution(* sample..TaskService.(..) && #annotation( sample...TimeLogging)")
see Advice parameters
better : see Combining pointcut expressions and Sharing common pointcut definitions
#Pointcut("execution(#annotation(* sample...TimeLogging)")
private void withTimeExecutionLayer() {}
#Pointcut("execution(public *sample..service.* *(..))")
privatr void inServiceLayer() {}
#Pointcut("inServiceLayer() && withTimeExecutionLayer()")
private void auditTimeExecutionServiceLayer() {}
Related
I am using Spring AOP for profiling method execution time. My methods uses Spring WebFlux and returns a Mono of various types viz. Map, List , custom objects of Java classes. But jointPoint.proceed() in #Around advice returns object. How can I return the same Mono from doAround method.
The method whose execution time I want to know is as follows :
public Mono<Map<Integer, Car>> getCarObject(List<Integer> cardIds) {
if (cardIds == null || cardIds.isEmpty()) {
return Mono.fromCallable(() -> new HashMap<>());
}
return Mono.fromCallable(() -> listingClient.getCarObject(carIds).getData());
}
My aspect class is as follows :
#Aspect
#Configuration
public class Demo {
private Logger logger = LoggerFactory.getLogger(this.getClass());
#Pointcut("execution(* com.Car.*.mediators.*.*(..))")
public void feignClientPointcut() {
}
#Around("feignClientPointcut()")
public void doAround(ProceedingJoinPoint joinPoint) throws Throwable {
long start = System.currentTimeMillis();
Object object = joinPoint.proceed();
long end = System.currentTimeMillis();
long time = end - start;
logger.error("Around Method Name = {}",joinPoint.getSignature().getName());
logger.error("Around time :{}",time);
}
}
How can I return the same Mono from doAround method. Because on returning Mono<object> the caller function of method throws an error as it expects a Map not a object ?
I'm trying to set up JunitTest using camel, activeMq and an Alfresco API
The route I want to test is :
from(Constantes.Direct.DIRECT_GET_AUTHENTIFICATION_TICKET)
.setBody().simple("{"
+ "\"userId\": \"userId\","
+"\"password\": \"password\""
+"}")
.setHeader(Exchange.HTTP_METHOD,constant(Constantes.Headers.HTTP_POST))
.setHeader(Exchange.HTTP_URI,simple(Constantes.Urls.OBTENIR_TICKET))
.to(Constantes.Urls.DUMMYHOST).convertBodyTo(String.class)
.unmarshal().json(JsonLibrary.Jackson, TicketAlfresco.class).process(new Dumper())
.process(new TokenBase64Proc())
.setHeader(Constantes.Headers.SENDER, constant(Constantes.Headers.ALFRESCO))
.setHeader(Constantes.Headers.API_ACTION, constant(SET_ALFRESCO_TOKEN))
.setHeader(Constantes.Headers.HEADER_AUTHORIZATION, simple("${body}"))
.inOut(Constantes.ActiveMq.ACTIVEMQ_IN)
.end();
The first "to" send a request to the Alfresco API and give back a new token.
The last inOut send the token to an activeMQ.
The problem is that when I want to test my route, when the test arrive to inOut inside the activeMq, the test fail because it didn't get any answer.
Do I need to install and embeded broker activeMQ or do I need to Mock the ActiveMQ ? And how can I do that?
For the moment to make it run I use :
mockEndpointsAndSkip("activemq:IN")
But I'm not sure that is the good solution.
Here is the test I have for the moment:
#RunWith(SpringRunner.class)
#EnableAutoConfiguration
#ComponentScan(basePackages = {"fr.gif.wsp.web.service.alfresco*"})
public class RouteGetAuthentificationTicketTest extends CamelTestSupport{
#Autowired private RouteGetAuthentificationTicket routeGetAuthentificationTicket;
//Route to test
private final static String FOURNISSEUR_GET_AUTHENTIFICATION_TICKET = Constantes.Direct.DIRECT_GET_AUTHENTIFICATION_TICKET;
private final static String MOCK_FOURNISSEUR_GET_AUTHENTIFICATION_TICKET = "mock:" + FOURNISSEUR_GET_AUTHENTIFICATION_TICKET;
// Mock result
private final static String MOCK_RESULT = "mock:result";
//Data
private final static String BODY = "Content of the body";
#Override
protected RoutesBuilder createRouteBuilder() {
return routeGetAuthentificationTicket;
}
#Before
public void setContextRoute() throws Exception {
context.getRouteDefinitions().get(0).adviceWith(context, new AdviceWithRouteBuilder() {
#Override
public void configure() throws Exception {
mockEndpointsAndSkip("activemq:IN");
weaveAddLast().to(MOCK_RESULT);
}
});
}
#Test
public void getAuthentificationTicket() throws InterruptedException {
final MockEndpoint resultEndpoint = context.getEndpoint(MOCK_FOURNISSEUR_GET_AUTHENTIFICATION_TICKET, MockEndpoint.class);
context.createProducerTemplate().sendBody(FOURNISSEUR_GET_AUTHENTIFICATION_TICKET, BODY);
resultEndpoint.assertIsSatisfied();
final Object result = context.createProducerTemplate().requestBody(FOURNISSEUR_GET_AUTHENTIFICATION_TICKET, BODY);
assertNotNull(result);
}}
Thanks for your time
Using apachebench with "ab -k -c 50 -n 1000000" options (50 concurrent threads) shows a 10x performance difference between the following 2 methods (manual and spring-managed serialization). Is it possible to achieve the same performance via configuration of Spring serialization?
I'm running the test on Windows 7, JDK8, i7-6700. Embedded Tomcat, similar results with Undertow or Jetty too. A similar WildFly 10 JAX-RS sample apps performance yields similar results as the manual spring one, so I see no reason why Spring automatic mode should be so slow.
Full source code:
#SpringBootApplication
#Controller
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
ObjectMapper mapper = new ObjectMapper(new JsonFactory());
#RequestMapping(value = "/auto", produces = "application/json; charset=utf-8")
#ResponseBody
public Lol automaticSerialization() {
Lol lol = new Lol();
lol.a = UUID.randomUUID().toString();
lol.b = System.currentTimeMillis();
return lol;
}
#RequestMapping(value = "/manual", produces = "application/json; charset=utf-8")
#ResponseBody
public String manualSerialization() throws JsonProcessingException {
Lol lol = new Lol();
lol.a = UUID.randomUUID().toString();
lol.b = System.currentTimeMillis();
return mapper.writeValueAsString(lol);
}
public static class Lol {
String a;
long b;
public void setA(String a) {
this.a = a;
}
public void setB(long b) {
this.b = b;
}
public String getA() {
return a;
}
public long getB() {
return b;
}
}
}
Edit:
Trace of automatic serialization:
Trace of manual serialization:
The only idea that I have is that Spring's default ObjectMapper is configured a bit differently than the one you use in your benchmark. Like the comments mention, you'd probably see a bit of overhead if you let Spring handle the mapping automatically but it shouldn't have more than a few percent's worth of impact.
To be sure that the comparison is fair, add this bean definition to your configuration:
#Bean
#Primary
ObjectMapper objectMapper() {
return new ObjectMapper(new JsonFactory());
}
and replace ObjectMapper mapper = new ObjectMapper(new JsonFactory()); with an autowired field:
#Autowired
ObjectMapper mapper;
and see if the benchmarks return the same value.
EDIT
I wanted to verify this for myselt so I wrote a JMeter plan and executed each endpoint exactly 5kk times, with a 1-minute warm-up period. The results were as expected, no major differences between the approaches:
Label,# Samples,Average,Min,Max,Std. Dev.,Error %,Throughput,KB/sec,Avg. Bytes
Auto Request,5000000,2,0,108,5.88,0.00%,15577.3,3088.08,203.0
Manual Request,5000000,2,0,149,5.99,0.00%,15660.2,2813.94,184.0
The important thing to note is the throughput difference - auto's 15577.3 vs. manual's 15660.2.
Here's my JMeter test plan, if you'd like to test it yourself, I was running on port 8081. If I find the time, I'll try another benchmarking framework, perhaps Gatling.
I want to limit concurrent method invocation in spring application.
There is interceptor for this and here the example of using this interceptor.
But the problem is that method(which need to be limited) is not in a bean, I am creating new object every time I need to call method.
Is there is possibility to achieve limitation in this case?
You can use Load-time weaving with AspectJ and write a custom aspect which does the throttling.
Example
#Aspect
public class ThrottlingAspect {
private static final int MAX_CONCURRENT_INVOCATIONS = 20;
private final Semaphore throttle = new Semaphore (MAX_CONCURRENT_INVOCATIONS, true);
#Around("methodsToBeThrottled()")
public Object profile(ProceedingJoinPoint pjp) throws Throwable {
throttle.acquire ();
try {
return pjp.proceed ();
}
finally {
throttle.release ();
}
}
#Pointcut("execution(public * foo..*.*(..))")
public void methodsToBeThrottled(){}
}
I realise that best practise may advise on loading test data on every #Test method, however this can be painfully slow for DBUnit so I have come up with the following solution to load it only once per class:
Only load a data set once per test class
Support multiple data sources and those not named "dataSource" from the ApplicationContext
Roll back of the inserted DBUnit data set not strictly required
While the code below works, what is bugging me is that my Test class has the static method beforeClassWithApplicationContext() but it cannot belong to an Interface because its static. Therefore my use of Reflection is being used in a non Type safe manner. Is there a more elegant solution?
/**
* My Test class
*/
#RunWith(SpringJUnit4ClassRunner.class)
#TestExecutionListeners({DependencyInjectionTestExecutionListener.class, DirtiesContextTestExecutionListener.class, DbunitLoadOnceTestExecutionListener.class})
#ContextConfiguration(locations={"classpath:resources/spring/applicationContext.xml"})
public class TestClass {
public static final String TEST_DATA_FILENAME = "Scenario-1.xml";
public static void beforeClassWithApplicationContext(ApplicationContext ctx) throws Exception {
DataSource ds = (DataSource)ctx.getBean("dataSourceXyz");
IDatabaseConnection conn = new DatabaseConnection(ds.getConnection());
IDataSet dataSet = DbUnitHelper.getDataSetFromFile(conn, TEST_DATA_FILENAME);
InsertIdentityOperation.CLEAN_INSERT.execute(conn, dataSet);
}
#Test
public void somethingToTest() {
// do stuff...
}
}
/**
* My new custom TestExecutioner
*/
public class DbunitLoadOnceTestExecutionListener extends AbstractTestExecutionListener {
final String methodName = "beforeClassWithApplicationContext";
#Override
public void beforeTestClass(TestContext testContext) throws Exception {
super.beforeTestClass(testContext);
Class<?> clazz = testContext.getTestClass();
Method m = null;
try {
m = clazz.getDeclaredMethod(methodName, ApplicationContext.class);
}
catch(Exception e) {
throw new Exception("Test class must implement " + methodName + "()", e);
}
m.invoke(null, testContext.getApplicationContext());
}
}
One other thought I had was possibly creating a static singleton class for holding a reference to the ApplicationContext and populating it from DbunitLoadOnceTestExecutionListener.beforeTestClass(). I could then retrieve that singleton reference from a standard #BeforeClass method defined on TestClass. My code above calling back into each TestClass just seems a little messy.
After the helpful feedback from Matt and JB this is a much simpler solution to achieve the desired result
/**
* My Test class
*/
#RunWith(SpringJUnit4ClassRunner.class)
#TestExecutionListeners({DependencyInjectionTestExecutionListener.class, DirtiesContextTestExecutionListener.class, DbunitLoadOnceTestExecutionListener.class})
#ContextConfiguration(locations={"classpath:resources/spring/applicationContext.xml"})
public class TestClass {
private static final String TEST_DATA_FILENAME = "Scenario-1.xml";
// must be static
private static volatile boolean isDataSetLoaded = false;
// use the Qualifier to select a specific dataSource
#Autowired
#Qualifier("dataSourceXyz")
private DataSource dataSource;
/**
* For performance reasons, we only want to load the DBUnit data set once per test class
* rather than before every test method.
*
* #throws Exception
*/
#Before
public void before() throws Exception {
if(!isDataSetLoaded) {
isDataSetLoaded = true;
IDatabaseConnection conn = new DatabaseConnection(dataSource.getConnection());
IDataSet dataSet = DbUnitHelper.getDataSetFromFile(conn, TEST_DATA_FILENAME);
InsertIdentityOperation.CLEAN_INSERT.execute(conn, dataSet);
}
}
#Test
public void somethingToTest() {
// do stuff...
}
}
The class DbunitLoadOnceTestExecutionListener is no longer requried and has been removed. It just goes to show that reading up on all the fancy techniques can sometimes cloud your own judgement :o)
Not a specialist, but couldn't you call an instance method of your test object in prepareTestInstance() after having verified it implements the appropriate interface, and call this method only if it's the first time prepareTestInstance is invoked with a test instance of this class. You would just have to keep a set of already seen classes:
#Override
public void prepareTestInstance(TestContext testContext) throws Exception {
MyDbUnitTest instance = (MyDbUnitTest) getTestInstance();
if (!this.alreadySeenClasses.contains(instance.getClass()) {
instance.beforeClassWithApplicationContext(testContext.getApplicationContext());
this.alreadySeenClasses.add(instance.getClass());
}
}