I have a scenario where I need to access spring managed beans in my domain object(i.e. object created with new operator). I searched a lot and found that it can be done using Load Time Weaving provided by aspectJ. I've done all configurations for the above to the best of my knowledge. I'm new to aspectJ. Following are my code and the configuration files.
Domain class,
package test.components;
import hibSERVICES.NounHeader.NounHeaderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Configurable;
#Configurable
public class TestLoadTimeWeaving {
#Autowired
private NounHeaderService nounHeaderService;
public void hello(){
nounHeaderService.findByPrimaryKey(0L);
}
}
Controller,
package test.controllers;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
#Controller
#RequestMapping(value = "/testController.do")
public class TestController{
#RequestMapping(params = "todo=onLoad", method = {RequestMethod.POST, RequestMethod.GET})
public void onLoad(HttpServletRequest request, HttpServletResponse response){
TestLoadTimeWeaving testLoadTimeWeaving = new TestLoadTimeWeaving();
testLoadTimeWeaving.hello();
}
}
applicationContext.xml
<?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:dwr="http://www.directwebremoting.org/schema/spring-dwr"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:ehcache="http://ehcache-spring-annotations.googlecode.com/svn/schema/ehcache-spring"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.directwebremoting.org/schema/spring-dwr
http://www.directwebremoting.org/schema/spring-dwr-2.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
http://ehcache-spring-annotations.googlecode.com/svn/schema/ehcache-spring
http://ehcache-spring-annotations.googlecode.com/svn/schema/ehcache-spring/ehcache-spring-1.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<context:spring-configured />
<context:annotation-config />
<context:component-scan base-package="test" />
<context:load-time-weaver aspectj-weaving="on"/>
<bean lass="org.springframework.beans.factory.aspectj.AnnotationBeanConfigurerAspect" factory-method="aspectOf"/>
aop.xml,
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE aspectj PUBLIC
"-//AspectJ//DTD//EN"
"http://www.aspectj.org/dtd/aspectj_1_5_0.dtd">
<aspectj>
<weaver>
<exclude within="*..*CGLIB*" />
</weaver>
</aspectj>
I've written -javaagent:c:\spring-agent-2.5.6.jar as the VM argument
Using following jars to support LTW and aspectJ,
aspectjrt-1.5.4.jar
spring-agent-2.5.6.jar
spring-aspect.jar
aspectjWeaver-1.5.4.jar
spring-2.5.6.jar
All other spring dependencies are working fine, only the dependencies which are injected in the domain objects( i.e. object created with new operator) are not working i.e. I'm getting null for those depedencies.
Kindly help. Thanks in advance.
Related
i want to use the #before ,#after and #AfterThrowing in my function.
If other function use the annotation like #MyAspectTest, it should run beforeAction(), afterAction() and afterExcept() at related time.
But, it seems doesn't work.
i have already input the dependency and modified the beans.
package com.service.metrics;
import com.mgr.CMPMgr;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.AfterThrowing;
import java.lang.reflect.Method;
#Aspect
public class CMPAspect {
#Before(value="#annotation(com.mgr.CMPMgr)")
public void beforeAction(JoinPoint joinPoint) throws ClassNotFoundException {
testcode
}
#After(value="#annotation(com.mgr.CMPMgr)")
public void afterAction(){
testcode
}
#AfterThrowing(value="#annotation(com.mgr.CMPMgr)")
public void afterExcept(){
testcode
}
}
package com.mgr;
public #interface CMPMgr {
String name() default "";
long startTime = System.currentTimeMillis();
}
#CMPMgr(name = "vipGet")
#GET
#Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
#Path("/{lbId}")
public Response get(#PathParam("lbId")String lbId,
#HeaderParam("Authorization") String basicAuthData,
#HeaderParam("UserID") String behalf) {
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.8.0</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.0</version>
</dependency>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:jpa="http://www.springframework.org/schema/data/jpa" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:task="http://www.springframework.org/schema/task"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.2.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<aop:aspectj-autoproxy />
<!-- enabling annotation driven configuration / -->
<context:annotation-config />
<context:component-scan />
<!-- responsible for registering the necessary Spring components that power
annotation-driven transaction management; such as when #Transactional methods
are invoked -->
<tx:annotation-driven />
it should get into the Aspect functions. But i don't find it work in debug mode. Why?
Some things come to mind:
Your annotation needs runtime retention, but I do not see #Retention(RetentionPolicy.RUNTIME) in your code.
Your aspect should be a #Component, but I do not see the corresponding annotation either.
The target class containing method public Response get(..) also has to be a Spring bean/component. Because you only show incoherent snippets instead of full class definitions, I have no idea which package that class resides in, if it is a Spring component and whether or not it is picked up by component scan.
I have a web application which is supposed to run a scheduled code:
package com.myproject.daemon.jobs;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
#Component
public class MyDaemonJob {
private static final Logger log = LoggerFactory.getLogger(MyDaemonJob.class);
#PostConstruct
public void init() {
log.info("MyDaemonJob is intialized " );
}
#Scheduled(fixedDelay = 1000)
public void startDaemon() {
try {
log.info("MyDaemonJob is running ...");
} catch (Exception e) {
log.error("Encountered error running scheduled job: " + e.getMessage());
}
}
}
It surely is recognized as a Spring bean and initialized, as I can see from the PostConstruct log. However the method with the #Scheduled annotation never runs although it is supposed to run every 1 second.
Here is app context xml
<?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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<context:component-scan base-package="
com.myproject.daemon.jobs,
com.myproject.product" />
</beans>
Thank you ALL for quick help. This is really helpful.
The code started working, once I added config class with annotations as shown below --
package com.myproject;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
#Configuration
#EnableScheduling
public class AppConfig {
// various #Bean definitions
}
To use the #scheduled annotation it is necessary to include the spring task name space in spring bean configuration xml file. You can update the following namespac e in your xml configuration file.
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task-4.1.xsd">
Otherwise if you use the spring-boot application you can include the #EnableScheduling in your configuration file
I have a context as follows
<?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:int="http://www.springframework.org/schema/integration"
xmlns:int-amqp="http://www.springframework.org/schema/integration/amqp"
xmlns:rabbit="http://www.springframework.org/schema/rabbit"
xsi:schemaLocation="http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/integration/amqp
http://www.springframework.org/schema/integration/amqp/spring-integration-amqp.xsd
http://www.springframework.org/schema/rabbit
http://www.springframework.org/schema/rabbit/spring-rabbit.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<int:gateway id="fooGateway" service-interface="com.foo.FooGateway" />
</beans>
My gateway interface is as follows:
public interface FooGateway
{
public void foo(String foo);
}
This context is imported into another context but the fooGateway bean is never created by GatewayProxyFactoryBean.
I've set a breakpoint in GatewayProxyFactoryBean and I can see that it is not creating a proxy for this interface.
Turn on DEBUG logging for org.springframework; the bean creation process emits lots of information including when it reads particular configuration files.
I am using Spring AOP to create an Aspect. The Aspect that I defined is being executed twice. I can't seem to figure out why. I'd appreciate any inputs anyone has on this issue.
Thanks!
// Spring Configuration
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"
default-autowire="no"
default-lazy-init="true">
<bean id="loggingAdvice" class="com.xyz.aop.LoggingAdvice" />
<aop:config>
<aop:aspect id="loggingAspect" ref="loggingAdvice">
<aop:pointcut id="loggingPointcut"
expression="execution(* com.xyz.FooServiceImpl.foo(..))"/>
<aop:around pointcut-ref="loggingPointcut" method="log" />
</aop:aspect>
</aop:config>
<context:component-scan base-package="com.xyz.controllers" />
</beans>
// Advice
package com.xyz.aop;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.aspectj.lang.ProceedingJoinPoint;
public class LoggingAdvice {
public Object log(final ProceedingJoinPoint pjp) throws Throwable {
log.info("Started!");
try {
return pjp.proceed();
} finally {
log.info("Ended!");
}
}
}
// Advised Method
package com.xyz;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class FooServiceImpl implements FooService {
private static final Log log = LogFactory.getLog(FooServiceImpl.class);
#Override
public void foo() {
log.info("Foo!");
}
}
}
// Output
Started!
Started!
Foo!
Ended!
Ended!
// EDIT 1: Added more spring configuration info. Not using any Spring AOP annotations at all. I attached a debugger and saw that the aspect/log statements were being executed twice as well. So I doubt that it has anything to do with log statement printing the string twice.
Well, it seems like this is actually an issue with the logger. Same problem I encountered long time back and found that everything is being logged twice. When I replaced logger calls with regular sysout calls, everything worked fine.
Because the <aop:around...> is telling this to do work both before and after the method. You could use <aop:before...> or <aop:after...> instead for running only once.
I have a web application in which I'm using spring MVC. I have defined few constants in sample.properties file. spring-servlet is the servlet that gets initialized for all urls in my app. spring-servlet:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
<context:property-placeholder location="classpath:sample.properties"/>
</beans>
In one of my java classes I access the value of one of the properties like this:
package com.sample;
import com.google.gson.JsonArray;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
#Component
public class Validator {
#Value("${credit}")
String credits;
private static final Logger LOG = Logger.getLogger(Validator.class);
public void checkRating() {
LOG.debug(credits);
}
}
sample.properties:
credit=[{"duration":15,"credit":10},{"duration":30,"credit":20}]
When Validator is called from a controller, it just logs it as ${credit} in my log file. I dont get its value. Similarly, if I put an integer / floating point number in the properties file, I get an error saying it cannot be cast into integer / float. Am I missing any configuration?
The reason for this is because propertyplaceholder configurer is a BeanFactoryPostProcessor and it processess only the beans defined in the context in which the propertyplaceholder is configured. In a web application typically there is a heirarchy of context as explained here. Hence you need to declare this at appropriate place.