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.
Related
In a modular Spring configured application, we use factory beans to provide bean instances across module boundaries.
For example, one module A may expose a bean instance by the name name. Another module B can then consume that bean via a declaration of the style
<bean id="nameBean" class="com.zfabrik.springframework.ComponentFactoryBean">
<property name="componentName" value="A/name" />
<property name="className" value="a.AInterface" />
</bean>
Note that modules have separated class loader hierarchies and the actual implementation class of A/name may not be visible in B. As if in OSGI (although this is NOT OSGi).
My goal is to provide A/name in a programmatic application context in B. However when trying
#Configuration
public static class AppContext {
#Bean AInterface nameBean() {
return lookup("A/name",AInterface.class);
}
}
(lookup does the actual instance retrieval) I see that Spring is trying to configure the returned instance. For example, it will attempt to resolve #Autowired properties of A/names's implementation class - which does not make sense in the context of B (and the deal of the lookup is to provide something fully configured anyway). Even, if I try
#Configuration
public static class AppContext {
#Bean(autowire=Autowire.NO) AInterface nameBean() {
return lookup("A/name",AInterface.class);
}
}
it will go about configuring the returned instance.
How can I provide a bean to the application context without spring touching its implementation instance?
EDIT: As suggested by Sotirios Delimanolis, returning the FactoryBean does AFAICT avoids Spring configuration of the returned instance.
The alternative code would look like this:
#Configuration
public static class AppContext {
#Bean FactoryBean<AInterface> nameBean() {
return new ComponentFactoryBean("A/name",AInterface.class);
}
}
It's not as cool as an #UntouchedBean annotation because of the FactoryBean in the return type, but it solves the problem.
#Sotirios: Please suggest as answer so that I can tag your suggestion accordingly.
/EDIT
Ok, just so it can be closed. The suggested and accepted answer is to return the factory 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.
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.
I'm developing an aspect that checks string arguments of setter methods of my entity package for empty strings and replace them with null values. But unfortunately my aspect doesn't works well :(. I guess it is because of my pointcut definition, but I'm not sure.
My aspect looks like:
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
#Aspect
public class EmptyStringToNullSetter {
private static final Logger LOGGER = LoggerFactory
.getLogger(EmptyStringToNullSetter.class);
public void check(final JoinPoint jp) {
LOGGER.debug(jp.getSignature().toLongString());
}
}
My spring config looks like:
<bean id="emptyStringToNullSetter" class="de.foo.util.aop.parameter.EmptyStringToNullSetter" />
<aop:config>
<aop:pointcut id="entityStringSetter" expression="execution(* de.foo.entity.*.set*(..)) and args(java.lang.String)" />
<aop:aspect id="checkEmptyStringsAspect" ref="emptyStringToNullSetter">
<aop:before method="check" pointcut-ref="entityStringSetter" />
</aop:aspect>
</aop:config>
My test class looks like:
import de.foo.entity.Period;
#ContextConfiguration(locations = { "/spring/test-util-context.xml" })
public class EmptyStringToNullSetterTest extends
AbstractJUnit4SpringContextTests {
#Test
public void testCheck() {
Period period = new Period();
period.setName("");
Assert.assertNull(period.getName());
}
}
When I execute my test the aspect doesn't intercept my setter. Do anyone has any idea why?!
Cheers,
Kevin
Since you are using proxy-based AOP, the advice will apply only to Spring beans and the "period" object isn't a bean. You need to either have "period" as a bean or use AspectJ's weaving based AOP. In either case, you will also need to use an around advice instead of before.
This design is very tricky and error-prone with Spring JDK proxy based AOP.
I've mentionned this point here: http://doanduyhai.wordpress.com/2011/08/08/spring-aop-advices-on-setters-not-trigged/
Basically, an aspect define with Spring AOP is implemented at runtime as a proxy object wrapping around the original target.
In the bean lifecycle, Spring will create proxies only after the bean is fully initialized, e.g. after all properties injection by setter.
So the first time your setter is called, it will not be intercepted by the advice because the proxy does not exist yet.
However all subsequent calls to the setter will be intercepted.
Furthermore, be careful about self-invocation issues, e.g. calling the setter() inside another target method.
I've been using the #Required annotation up to now to ensure DI of my beans in a Spring configured application.
To enable the annotation, you need to declare a RequiredAnnotationBeanPostProcessor bean in your configuration.
In your test configuration you just don't declare it, so that if some beans are not needed you don't have to have them in your config.
I want to switch to less XML and use #Autowired annotation, but it is by default required=true, which is fine for the runtime configuration.
But I need #Autowired to be required=false for testing purpose only - while keeping it required for runtime.
Is that possible at all? I can't find a way to declaratively turn the required property to false.
cheers
You probably solved it already but this trick might be useful for others.
As far as I understood without context:annotation-driven being present #Autowired annotations should not be processed but this is clearly not the case so I might misunderstood something.
However, I needed a quick solution... This somewhat dirty trick negates required value for all classes making optional what was required before. Adding it to my test context solved my problem but it is useful only if all autowirings are required in your business classes.
<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor">
<property name="requiredParameterValue" value="false" />
</bean>
I worked out a solution that works for JavaConfig configurations
#ContextConfiguration(initializers={DisableAutowireRequireInitializer.class})
public class TestCase {
// Some tests
}
public class DisableAutowireRequireInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
#Override
public void initialize(ConfigurableApplicationContext applicationContext) {
// Register the AutowiredAnnotationBeanPostProcessor while initalizing
// the context so we get there before any #Autowire resolution happens
// We set the "requiredParameterValue" so that #Autowire fields are not
// required to be resolved. Very useful for a test context
GenericApplicationContext ctx = (GenericApplicationContext) applicationContext;
ctx.registerBeanDefinition(AnnotationConfigUtils.AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME,
BeanDefinitionBuilder
.rootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class)
.addPropertyValue("requiredParameterValue", false)
.getBeanDefinition());
}
}
You can use the same technique as you did with #Required - don't register the AutowiredAnnotationBeanPostProcessor in your test context, but leave it in your live context.
This is usually registered by adding <context:annotation-driven/>, rather than being declared manually.