Spring AOP - pointcut/interceptor not called - java

I have defined the following interceptor:
#Aspect
public class OpenSessionInRequestInterceptor {
private Log log = LogFactory.getLog(getClass());
#Autowired
private SessionFactory sessionFactory;
public OpenSessionInRequestInterceptor() {
}
#Around("#annotation(com.sc2.master.aop.hibernate.OpenSession)")
public Object processAround(ProceedingJoinPoint pjp) throws Throwable {
log.info("Opening Hibernate Session in method "+pjp.getSignature());
Session session = SessionFactoryUtils.getSession(sessionFactory, true);
TransactionSynchronizationManager.bindResource(sessionFactory, new SessionHolder(session));
Object ret = pjp.proceed();
session.close();
TransactionSynchronizationManager.unbindResource(sessionFactory);
log.info("Closing Hibernate Session in method "+pjp.getSignature());
return ret;
}
}
When I execute the following piece of code in a spring test
#OpenSession
public void call() {
BusinessCustomer customer = (BusinessCustomer) this.customerDao.loadAll().get(0);
System.out.println(customer.getContacts().size());
}
the aspect method is called. To start the test my test case class looks as follows:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations={"file:WebContent/WEB-INF/applicationContext.xml"})
#Transactional
However, when I have a method annotated with #OpenSession and deploy the application on my Tomcat server, the interceptor method is not called.
The application context definition looks as follows:
<aop:aspectj-autoproxy proxy-target-class="true">
</aop:aspectj-autoproxy>
<bean id="openSessionInRequestInterceptor" class="OpenSessionInRequestInterceptor"></bean>
I can absolutely not figure out, why AOP does not work when deployed on the tomcat. I hope you have some ideas.
Solution I found the solution. I places my aop configuration in the applicationContext.xml, but this will not work. I placed the configuration in the application-servlet.xml and now everything is fine. Has someone an idea why?

I admit I didn't have to make it work using a marker annotation, but I needed the annotation as argument, so this worked:
#Around("#annotation(foo)")
public Object invoke(ProceedingJoinPoint invocation, Foo foo) throws Throwable
But.. note that #Transactional also starts a session if one isn't started, so perhaps you don't really need that.
Update: if your beans are defined in the child context, then the aop configuration of the parent context does not affect them. The parent context does not see the child context, and your x-servlet.xml is a child context.

To answer why you have to put configuration in the servlet XML to get to work:
I assume you are using <context:component-scan ...> tag and this is placed in the servlet XML. That is the reason why you need to have them both in servlet XML, otherwise they don't "see" each other. As a result, the connection is not properly established.

Related

#Cachable annotation does not work

We're using ehcache for caching purposes in our project.
import com.googlecode.ehcache.annotations.Cacheable;
// Other imports
#Component
public class Authenticator{
#Cacheable(cacheName = "rest_client_authorized")
public boolean isUserAuthorized(final String user, final String sessionId) {
// Method code
}
}
When entering the method there is no cache interceptor. The things we checked so far:
We don't call this method from inside the class, but from the outside. So the problem is not inner calls that causes to bypass the proxy.
We've added an interface for this class, and we changed the injections where this class is called to use the interface representation instead of the concrete class.
We have defined the cache manager in our application context this way:
<ehcache:annotation-driven cache-manager="ehCacheManager" />
<bean id="ehCacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
<!-- use a share singleton CacheManager -->
<property name="shared" value="true" />
</bean>
The cache is defined like this:
<cache name="rest_client_authorized"
eternal="false"
maxElementsInMemory="50"
overflowToDisk="false" diskPersistent="false"
timeToIdleSeconds="0" timeToLiveSeconds="600"
memoryStoreEvictionPolicy="LRU" />
When we test the cache manager using Jconsole we can see that the cache *rest_auth_disabled* exists and empty.
Any ideas as to why this does not work will be most appreciated. Thanks!
Updates (aggregation from comments below):
==========================================**
That's a legacy code that worked fine with the class and definitions I've provided. The method I talk about here is new, but the rest of the class did work in past. So we're struggling to understand what has changed. We also tried already to replace the annotation to spring Cacheable, but still nothing :/
Maybe that depends on the code that calls this new method, which is from a different spring bean than what we used for the other methods. But I still can't find the issue.
Also tried to return Boolean instead of boolean following an answer below and it didn't work.
We have a new lead which is probably related to the way we inject the bean (using #Autowire). Will update if that's indeed the case.
This problem might have to do with the order Springs loads the beans. Try removing the #Autowire annotation from the Authenticator declartion, and do the autowiring manually. Something like:
/**
* Class that uses Authenticator
*/
public class X {
// Don't use #autowire here
public Authenticator athenticator;
public void doSomething() {
manuallyAutowire();
}
public void manuallyAutowire() {
if(authenticator == null) {
authenticator = ApplicationContextUtils.getApplicationContext().
getBean(authenticator.class);
}
}
Where
#Component
public class ApplicationContextUtils implements ApplicationContextAware {
private static ApplicationContext ctx;
#Override
public void setApplicationContext(final ApplicationContext appContext)
throws BeansException {
ctx = appContext;
}
public static ApplicationContext getApplicationContext() {
return ctx;
}
}
The value of the parameter cacheName in #Cacheable should be the same with the value of the name attribute of <cache> declaration in your application-context
I think you are mixing up things here - You have used com.googlecode.ehcache.annotations.Cacheable, if you want Springs caching support it should actually be org.springframework.cache.annotation.Cacheable. Then the caching interceptors should work cleanly.
As far as I know the Spring Ehcache annotations recommends that both parameter as return object should have an equals() and hashCode() method which primitive types lack.
I'm not sure if this framework is converting primitives to their wrapper variant (for example Integer or Boolean). Try returning the wrapper variant Boolean in stead of a primitive type and see if it works.
Another thing I'm not sure about is how (and if) it handles final parameters. If my first idea doesn't work, try removing the final keyword if possible and see if it works.

Spring autowire a stubbed service - duplicate bean

Ok. We have the need to #Autowire a different webservice on-the-fly (preferably by toggling a JNDI setting on the webserver) and I'm at a loss on how to do this. This is the way I was approaching the problems..
Two packages:
com.mycomp.service.stub
com.mycomp.service.impl
One package contains MyServiceStub.java while implement MyService
The other package contains MyServiceImpl.java, which implements same
My controller, which requires MyService, has the bean defined as such
#Autowire
private MyService communicator;
My spring-context.xml has the following:
<context:component-scan base-package="com.mycomp" />
At this point I get a DuplicateBean exception during autowiring. Now, I can statically define which bean to autowire in spring-context.xml:
<bean id="communicator" class="com.mycomp.service.impl.MyServiceImpl" />
and everything works fine... But then, how to 'flip' the switch and change over to the Stub method on our QA server? It has no connection to that service, so we need to run with stubs enabled. A JNDI property would be best for this.. but I just can't get my head around how to toggle what bean spring autowires at runtime.
Any help??
Cheers,
Chris
#Profile solution
You definitely have to try Spring 3.1 #Profile:
#Autowire
private MyService communicator;
//...
#Service
#Profile("prd")
class MyServiceImpl //...
#Service
#Profile("qa")
class MyServiceStub //...
Now depending on which profile is enabled, either DefaultMyService will be initialized or MyServiceStub.
You can choose between profile in various ways:
How to set active spring 3.1 environment profile via a properites file and not via an env variable or system property
using system property
programmatically
...
Spring AOP (explicit around every method)
In this example the aspect wraps around every single MyService method separately and returns stubbed value:
#Aspect
#Service
public class StubAspect {
#Around("execution(public * com.blogspot.nurkiewicz.MyService.foo(..))")
public Object aroundFoo(ProceedingJoinPoint pjp) throws Throwable {
if (stubMode()) {
return //stub foo() result
}
return pjp.proceed();
}
#Around("execution(public * com.blogspot.nurkiewicz.MyService.bar(..))")
public Object aroundBar(ProceedingJoinPoint pjp) throws Throwable {
if (stubMode()) {
return //stub bar() result
}
return pjp.proceed();
}
private boolean stubMode() {
//whatever condition you want here
return true;
}
}
The code is pretty straightforward, unfortunately the return values are buried inside the aspect and you need a separate #Around for every target method. Finally, there is no place for MyServiceStub.
Spring AOP (automatically around all methods)
#Aspect
#Service
public class StubAspect {
private MyServiceStub stub = //obtain stub somehow
#Around("execution(public * com.blogspot.nurkiewicz.MyService.*(..))")
public Object aroundFoo(ProceedingJoinPoint pjp) throws Throwable {
if (stubMode()) {
MethodSignature signature = (MethodSignature)pjp.getSignature();
Method method = signature.getMethod();
return method.invoke(stub, pjp.getArgs());
}
return pjp.proceed();
}
private boolean stubMode() {
//whatever condition you want here
return true;
}
}
This approach is more implicit as it automatically wraps every target method, including new methods added in the future. The idea is simple: if stubMode() is off, run the standard method (pjp.proceed()). If it is on - run the exact same method with exact same parameters - but on a different object (stub in this case).
This solution is much better as it involves less manual work (at the price of using raw reflection).
Note that if both MyService implementations are Spring beans (even when one is annotated with #Primary), you might run into weird troubles. But it should be a good start.
See also:
Spring 3.1 M1: Introducing #Profile
Maybe you can replace the class with a property and deploy your application with different property files. The production version would contain the name of the real class while the QA version would contain the name of a stub.
Maybe this http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/beans.html#beans-factory-extension-factory-postprocessors can help you.

Spring 3 problems with TransactionManager and annotations

I'm trying to setup a TransactionManager in my Web Application (powered by Spring MVC 3), as I need to have one method of a component annotated as #Transactional.
This is my situation:
web.xml: load 2 xml files for the Spring ContextLoaderListener (applicationContext.xml and database.xml)
applicationContext.xml: contains some beans which I can't define via annotation, plus the tags for annotation, plus the usual context:annotation-config and context:component-scan (this component-scan includes the package that contains the #Transactional method)
database.xml: contains the datasource (I'm using BasicDataSource from commons-dbcp), the transaction manager definition and tx:annotation-driven.
I've got a #Component (DeleteComponent) which has an interface and an implementation (DeleteComponentImpl). The implementation class is annotated with #Component and has one public method annotated with #Transactional (I annotated the concrete class and not the interface, as Spring documentation states). For #Transactional I didn't put any arguments, as defaults are fine. This class has some DAOs (annotated with #Repository) being injected via #Autowired. I'm using only plain JDBC (no Hibernate or other ORM). This #Component is injected into a #Controller (which is defined in spring-servlet.xml).
If the method annotated as #Transactional throws an exception (unchecked, as RuntimeException), however, nothing is rolled back. The database retains the changes did before the exception. I'm using Jetty web server for testing locally my application. The thing I noticed is actually that seems like no transaction manager is being set up. Actually, my transaction manager is named transactionManager. The xml line to set up the annotation-driven transaction is
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
If I change it to use a non-existing bean name like
<tx:annotation-driven transaction-manager="fake"/>
The application still deploys correctly and doesn't complain.
Any tips on what should I check to make it working?
Thanks.
I solved by using #Transactional(rollbackFor = RuntimeException.class) and switching from a BasicDataSource to a ComboPooled that's present in c3p0 library. Thanks for the suggestions though.
To get rollback when an exception is thrown add this:
#Transactional(rollbackFor=Exception.class)
You will also need to set up the transactionManger bean (here is mine, using hibernate) :
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"
p:sessionFactory-ref="sessionFactory" />
I found this tutorial informative.
I believe that #Autowired and #Resource aren't scanned by Spring on a #Component.
Try to use a ContextHolder class to get the context and the DAO
#Component
public class ContextHolder implements ApplicationContextAware {
/**
* Spring context which will directly be injected by Spring itself
*/
private static ApplicationContext context = null;
/**
* Overridden method of ApplicationContextAware, which will automatically be called by the container
*/
public void setApplicationContext(ApplicationContext context) throws BeansException {
this.context = context;
}
/**
/**
* Static method used to get the context
*/
public static ApplicationContext getApplicationContext() {
return context;
}
}
and call your dao with :
ContextHolder.getApplicationContext().getBean("MyDAO");

Create ApplicationContext as Spring bean (by other application context)

How i can define one ApplicationContext as prototype spring bean in other application context. Also i need pass current context as parent to new application context.
Details:
I have Bean, that represent one user sessions in rich client application. This class manage lifetime of application context, and few other objects (like database connection). This session beans itself configured by special "start-up application context" .
Now i'm want unit test this session beans, but have trouble because session specific application context created inside session bean, and has many depend to "start-up context";
Example code:
public class UserDBAminSession implements ApplicationContextAware, UserSession {
ApplicationContext startupContext;
ApplicationContext sessionContext;
public void setApplicationContext(ApplicationContext startupContext) {...}
public void start() {
createSessionContext() ;
}
private void createSessionContext() {
sessionContext = new ClassPathXmlApplicationContext("admin-session.xml", startupContext);
}
}
For testing purpose i want relapse createSessionContext function code with something like this:
sessionContext = startupContext.getBean("adminContext", ApplicationContext.class);
Then i can create mock of startupContext, what return some stub. Or even DI "session context" to bean by spring, in some future. But, i don't know how pass parent context parameter to ClassPathXmlApplicationContext constructor. I'm try something like this, but it seems not work:
<bean id="adminContext" class="org.springframework.context.support.ClassPathXmlApplicationContext"
scope="prototype" autowire="constructor">
<constructor-arg type="java.lang.String">
<value>admin-session.xml</value>
</constructor-arg>
</bean>
Also I'm think about create application context on top level and pass it by setter, but:
This just move problem to above level, not solve. In fact it already done (UserSession - are this "top level").
This broke RAII pattern.
This need huge code refactoring.
Or make special "context factory" objects, but it harder already not best code.
What look stupid, I can't IoC objects from IoC framework itself. May be i'm misread some spring documentation?
Any other idea, how unit-test this class?
Use FactoryBean and ApplicationContextAware interfaces.
public class ChildApplicationContextFactoryBean implements FactoryBean, ApplicationContextAware {
protected String[] configLocations;
protected ApplicationContext applicationContext;
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
#Override
public Object getObject() throws Exception {
return new ClassPathXmlApplicationContext(configLocations, applicationContext);
}
#Override
public Class getObjectType() {
return ClassPathXmlApplicationContext.class;
}
#Override
public boolean isSingleton() {
return true;
}
public void setConfigLocations(String[] configLocations) {
this.configLocations = configLocations;
}
}
Usage:
<bean class="com.skg.ecg.portal.operation.transit.ChildApplicationContextFactoryBean">
<property name="configLocations">
<list>
<value>applicationContext.xml</value>
</list>
</property>
</bean>
If I understand you correctly, your requirement is for managing a collection of beans within a manually-controlled scope (your RIA session, in this case).
Spring has support for scoped beans. You have the basic singleton and prototype scopes, and webapps get the request and session scopes as well. If your RIA session is actually an HTTP session, then I suggest you use session-scoped beans instead of your manually-nested application context design.
If your sessions are not web-related, then you still have the option of definign your own custom scope. There's more work in this, but it is a defined extension point in the container, so you're on safe ground.
Your original idea of application contexts being themselves beans within a parent context would work, yes, but it's probably unnecessary in this case, and just adds complexity. If you want to investigate it further, however, have a look at the SingletonBeanFactoryLocator, which is a Spring infrastructure class for managing hierarchies of application contexts. It won't do the specific job you want, but it might give you ideas.

Spring- How to use Spring Dependency Injection to write a Standalone Java Application

I want to write a standalone application with IOC, how do I use springs dependency injection in there? I'm using JIdea. There is spring 2.5 support but I want to use spring 3.0 here is the way I tried!
I experience in using Spring MVC we can inject dependencies there in a WebApplicationContext but how do I inject dependencies in a standalone application
I tried this
ApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"com\\ttg\\xmlfile.xml"});
but I cannot see that the dependencies are injected by the beans defined there (in the XML file)
I put the above code in the main method and two bean definitions for two Objects,in one Java class's constructor I used the other class's object - which was injected to this object - and called a method on that which will print some thing but it didn't worked I thought that the above code creates all the dependencies and injects them but it doesn't seem like that
How do I properly use Springs IOC, dependency injection in my stand alone app which does not contain a WebApplicationContext?
Please mention steps.
suppose you have:
class Bean1 {
Bean2 bean2;
}
class Bean2 {
String data;
}
the context.xml file
<bean id="bean1" class="Bean1">
<property name="bean2" ref="bean2" />
</bean>
<bean id="bean2" class="Bean2" />
then this should be true
ApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"context.xml"});
Bean1 bean1 = (Bean1) context.getBean("bean1");
// bean1.bean2 should not be null here.
you can use autowiring support provided by spring, in order to inject dependencies (and possibly apply post processors) to an object that is not part of the application context.
In your case, this object is your standalone application.
Here is the way to achieve this. In this example, I use #Autowired (for b1), traditional DI (for b2) and initialization hook for b3. The autowiring support with annotations assumes you have defined the appropriate spring post-processor in your application context (e.g. by declaring <context:annotation-config/>).
public class StandaloneApp implements InitializingBean {
#Autowired private Bean1 b1;
private Bean2 b2;
private Bean3 b3;
public void afterPropertiesSet() throws Exception {
this.b3 = new Bean3(b1, b2);
}
public void setB2(Bean2 b2) {
this.b2 = b2;
}
public static void main(String... args) {
String[] locations = // your files relative to the classpath
ApplicationContext ac = new ClasspathXmlApplicationContext(locations);
// or use FileSystemXmlApplicationContext if the files are not in the classpath
StandaloneApp app = new StandaloneApp();
AutowireCapableBeanFactory acbf = ac.getAutowireCapableBeanFactory();
acbf.autowireBeanProperties(app, AUTOWIRE_BY_NAME, false);
acbf.initializeBean(app, "standaloneApp"); // any name will work
}
}
In this example, all b1, b2 and b3 should be non-null (assuming b1 and b2 beans exist in your application context).
I haven't tested it (might not even compile due to some typo), but the idea is in the last 3 lines. See the javadocs for AutowireCapableBeanFactory and mentionned methods to see exactly what happens.
If you prefer (mostly) pure java, you can use java config:
#Configuration
pubic class MyConfig {
#Bean
public Bean1 bean1() { return new Bean1(); }
#Bean
public Bean2 bean2() { return new Bean2(bean1()); }
}
And then to instantiate:
ApplicationContext ctx =
new AnnotationConfigApplicationContext(MyConfig.class);
Keep in mind there's some things that pure annotation driven configuration doesn't yet support (such as things like tx:annotation-driven), which you might need some xml glue code for.
<beans>
<tx:annotation-driven />
<context:annotation-config/>
<bean class="MyConfig"/>
</beans>
And then use a standard xml based way of creating the ApplicationContext (like ClasspathXmlApplicationContext, or the spring web context loader, etc...).
How did you confirm that your beans aren't being wired correctly? One common issue is the xml config file not being in the right place. Can you give us some more information like your project layout and the code you use to obtain the beans from the container?
If you add log4j logging to your app, you should see a cascade of messages coming out that will tell you a lot about what Spring is and is not doing. If you don't have that feedback, you're in the dark. You might be able to ferret out the answer just by getting more information out of Spring from log4j.
Are you calling context.getBean("beanName") to get a reference to the bean or are you doing a new SomeClass()? If you do it through getBean() then the injected properties should be set.
Also, be sure to use the same bean factory (ClassPathXmlApplicationContext instance) for retrieving all your beans. This should most likely be static final and used by the entire application.
you can use the command #Autowired

Categories