Spring AOP Configuration (XML) - java

I am experimenting with Spring AOP for the first time and get stuck in the XML configuration. I'm trying to get a mock version of AOP-based "logging" up and running, using a MethodInterceptor to wrap specific method calls and do some simple System.out.println statements before and after those method invocations. Simple stuff, right?
So my project has many classes, two of them are Fizz and Buzz. Fizz has a method named foo() and Buzz has a method named wapap(). Every time these methods are invoked at runtime, I want my LoggingInterceptor to execute its invoke() method around them:
public class LoggingInterceptor implements MethodInterceptor
{
public Object invoke(MethodInvocation methodInvocation)
{
try
{
System.out.println("About to call a special method.");
Object result = methodInvocation.proceed();
return result;
}
finally
{
System.out.println("Finished executing the special method.");
}
}
}
So I understand the concepts of advice (my interceptor impl), pointcuts (the methods that will have advice executed around them), and pointcut advisors (bindings between advice and pointcuts).
I'm just struggling tying it altogether in a simple XML config.
Here's what I have so far, but I know it's missing pointcut and pointcut advisor definitions, and possibly more.
<beans default-autowire="no" >
<bean name="loggingInterceptor" class="org.me.myproject.aop.LoggingInterceptor"/>
</beans>
What am I missing here to make this specific to Fizz::foo() and Buzz::wapap() calls?
Any nudges in the right direction are enormously appreciated!

Add this:
<aop:config>
<aop:advisor advice-ref="loggingInterceptor" pointcut="execution(public * Fizz.foo(..))"/>
<aop:advisor advice-ref="loggingInterceptor" pointcut="execution(public * Buzz.wapap(..))"/>
</aop:config>
You also need to add AOP namespace declaration in version appropriate to your framework:
<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/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
">
Also consider using #AspectJ aspects and see this question: Spring: Standard Logging aspect (interceptor).

If you are using Spring 2.5+ you can use annotation to and create your advice and Pointcuts.
Create class with #Aspect annotation.
Create #PointCut for specific class and specific method and then create #Around advice.
You can read short tutorial how to do it here:
http://veerasundar.com/blog/2010/01/spring-aop-example-profiling-method-execution-time-tutorial/
It' very easy to implement.

Related

Spring cache support requires ApplicationContext?

I'm running into an issue trying to use Spring caching with ehcache in my application. For reasons that I can't elaborate on, my application uses a graph of BeanFactories instead of ApplicationContexts. This approach has worked well as long as we manually register our BeanPostProcessors, as is called out in the Spring documentation.
We are now adding caching to the app. When we used the simplest annotation configuration, it works.
// This works
package com.x.y.z;
public class RoleManager {
private String user;
public RoleManager( String user ) {
this.user = user;
}
public String getName() {
return user;
}
#Cacheable("user")
public boolean isAllowed(String permissionId, Map<String,?> params)
{
... lengthy and expensive operation to determine if user is permitted to do something
}
}
We configure this to using spring xml for this bean factory:
<?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:util="http://www.springframework.org/schema/util"
xmlns:cache="http://www.springframework.org/schema/cache" xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation=
"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd
http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd">
<cache:annotation-driven/>
<bean id="roleManager" class="com.x.y.z.RoleManager" scope="prototype"/>
<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager">
<property name="cacheManager" ref="ehcacheManager"/>
</bean>
<bean id="ehcacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
<property name="configLocation" value="file:${conf.dir}/ehcache.xml"/>
<property name="shared" value="true"/>
</bean>
</beans>
... unrelated business beans elided ...
We are using Spring 4.1.9 and ehcache 2.10.2
The above code works quite well. Our ehcache instance for "user" begins to fill as we get cache misses, and returns cached values for hits.
Once this was running correctly, we found that it isn't possible to evict all the entries for a particular user because the cache key is a concatenation of the permissionid and the Map::toString result. We decided to create a cache per user so we would have more control over eviction. To use Spring, we need to use a CacheResolver to accomplish this.
package com.x.y.z;
import org.springframework.cache.CacheManager;
import org.springframework.cache.interceptor.AbstractCacheResolver;
import org.springframework.cache.interceptor.CacheOperationInvocationContext;
import java.util.Collection;
import java.util.Collections;
public class MyCacheResolver extends AbstractCacheResolver {
public MyCacheResolver() {
}
public MyCacheResolver(CacheManager cacheManager) {
super(cacheManager);
}
#Override
protected Collection<String> getCacheNames(CacheOperationInvocationContext<?> cacheOperationInvocationContext) {
if(cacheOperationInvocationContext.getTarget() instanceof RoleManager) {
return Collections.singleton(((RoleManager) cacheOperationInvocationContext.getTarget()).getName());
}
return Collections.singleton("user");
}
}
We wire this up by adding a new bean definition
<bean id="myCacheResolver" class="com.x.y.z.MyCacheResolver">
<constructor-arg index="0" ref="cacheManager"/>
</bean>
And change the annotation in RoleManager to
#Cacheable(cacheResolver="myCacheResolver")
Once we do this, however, we get the following exception when the isAllowed method is invoked:
java.lang.NullPointerException
at org.springframework.beans.factory.annotation.BeanFactoryAnnotationUtils.qualifiedBeanOfType(BeanFactoryAnnotationUtils.java:57)
at org.springframework.cache.interceptor.CacheAspectSupport.getBean(CacheAspectSupport.java:282)
at org.springframework.cache.interceptor.CacheAspectSupport.getCacheOperationMetadata(CacheAspectSupport.java:254)
at org.springframework.cache.interceptor.CacheAspectSupport.getOperationContext(CacheAspectSupport.java:226)
at org.springframework.cache.interceptor.CacheAspectSupport$CacheOperationContexts.<init>(CacheAspectSupport.java:500)
at org.springframework.cache.interceptor.CacheAspectSupport.execute(CacheAspectSupport.java:299)
at org.springframework.cache.interceptor.CacheInterceptor.invoke(CacheInterceptor.java:61)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)
at com.sun.proxy.$Proxy61.isAllowed(Unknown Source)
at com.x.y.z.RoleManager.isAllowed(CompositeRoleManager.java:61)
When I look at the CacheAspectSupport class from the stack trace, I see that it has a member, applicationContext, which is null.
protected <T> T getBean(String beanName, Class<T> expectedType) {
return BeanFactoryAnnotationUtils.qualifiedBeanOfType(this.applicationContext, expectedType, beanName);
}
This seems like a bug in Spring to me since we do not use ApplicationContexts, and yet caching works until we need to use a CacheResolver. I've looked over the documentation and I see no mention that one must use ApplicationContexts in order to use the Spring caching abstraction.
I guess my question is, has anyone experienced this problem, and if so, what did you do to resolve it? We absolutely cannot use ApplicationContexts in our application, and I'd rather not throw out a perfectly usable abstraction and code directly to the ehcache (or JSR-107) APIs.
Thanks in advance!
Spring 4.3 has fixed the problem by adding a setBeanFactory() method and using the BeanFactory thus set to call the CacheResolvers. Unfortunately I am unable to update our Spring library code to 4.3 at this time, but it will work when we are able to upgrade in the future.

Spring configuration for dependency injection

I'm learning spring dependency injection with Struts2, beased on a web project. In my example, I created a zoo having animals. Animal will talk if injection is succeed. E.g. in the console, we will see dog's talk :
Wowowo ฅ^•ﻌ•^ฅ
However, if injection failed, then we'll see :
zooService bean has not been injected.
Here's the architecture of my application :
com.zoo.controller.ZooController is the controller for receiving web actions.
com.zoo.service.ZooService is the interface for animal's talk
com.zoo.service.ZooServiceForDog is the implementation for dog's talk
Problem
Up to the step, everything is OK. And the dependency injection is handled by Spring using an XML file called applicationContext.xml. However, I've 2 types of configuration for this file, the first one Config 1 works but the second Config 2 doesn't.
Injection succeed using config 1.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
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.xsd">
<bean id="zooService" class="com.zoo.service.ZooServiceForDog" />
</beans>
Injection failed using config 2.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
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.xsd">
<bean id="zooController" class="com.zoo.controller.ZooController">
<property name="zooService" ref="zooServiceBean" />
</bean>
<bean id="zooServiceBean" class="com.zoo.service.ZooServiceForDog" />
</beans>
Can somebody explain why the Config 2 cannot work ?
Here're other codes that might be helpful to the issue :
Class com.zoo.controller.ZooController:
package com.zoo.controller;
import com.zoo.service.ZooService;
import com.opensymphony.xwork2.ActionSupport;
public class ZooController extends ActionSupport {
private static final long serialVersionUID = 1L;
private ZooService zooService;
public String live () {
if (zooService != null) {
zooService.talk();
} else {
System.out.println("zooService bean has not been injected.");
}
return SUCCESS;
}
public ZooService getZooService() {
return zooService;
}
public void setZooService(ZooService zooService) {
this.zooService = zooService;
}
}
It cannot work because the scope of the zooController is singleton. You should make the scope prototype.
<bean id="zooController" class="com.zoo.controller.ZooController" scope="prototype" >
<property name="zooService" ref="zooServiceBean" />
</bean>
The dependency management is defined by the container:
If your actions managed by Struts container, then Struts is creating them in the default scope. If your actions is managed by Spring container then you need to define the scope of the action beans, because Spring by default uses singleton scope and if you don't want to share your action beans between user's requests you should define the corresponding scope. You can use prototype scope, which means a new instance is returned by the Spring each time Struts is being built an action instance.
The Struts integrates to Spring via plugin. Make sure it has
<constant name="struts.objectFactory" value="spring" />
then you can delegate actions to Spring
References:
Struts2 and Spring
Spring plugin
EDIT:
In your first config you declared a bean zooService that will be injected by Struts using spring object factory.
In your second config you declared two beans zooController and zooServiceBean, but you changed the name of the second bean. Then you tried to build the action bean using spring object factory like in the first case. And because there's no bean with name zooService the autowiring has been failed. Because by default Struts is configured to autowire beans from the application context by name.
Then you changed struts.xml and used a bean reference in the action class attribute. It means that Struts will use app context to get a bean from Spring. And because it has an explicit dependency on the second bean, it would be wired before the bean is returned.

Why isn't my custom Spring aspect triggered?

I want to weave the following custom aspect using Spring 4.X.
(I use Scala, but is exactly the same as in Java).
I'm based on this existing code, acting as sample from the Vaughn Vernon's IDDD book:
#Aspect
#Component
class EventProcessor #Autowired()(private val eventRepository: EventRepository) {
#Before("execution(* com.mymainpackage.*.application.commands.*.*(..)")
def listen() {
DomainEventPublisher.instance().subscribe(new DomainEventSubscriber[Event] {
def handleEvent(domainEvent: Event) {
eventRepository.save(domainEvent)
}
def subscribedToEventType = {
classOf[Event]
}
})
}
}
My application-context.xml:
.........
<context:load-time-weaver/>
<context:annotation-config/>
<context:component-scan
base-package="........" />
The typical classes/services I want to weave with aspect contains this kind of method:
def handle(event:Event)
and its corresponding interfaces and implementation may be found in this explicit package for instance:
com.mymainpackage.myboundedcontext1.application.commands.anestedpackage
I well checked that the base-package contains the class's package of the custom aspect.
Is there a necessity to declare a #PointCut additionally to #Before?
The sample doesn't do it...
Of course, I executed my code with the following jar allowing "weaving" at Runtime so:
-javaagent:/cache/org.springframework/spring-instrument/jars/spring-instrument-4.0.0.RELEASE.jar
Did I miss something "obvious"?
Any idea how to fix this?
As #M.Deinum mentionned, I forgot a last ) regarding the matcher of my pointcut.
Furthermore I forgot to specify the aspectj-autoproxy, in order to take into account my aspect class.
With that, would no need to declare an aop.xml if I expect all aspects classes to have their created respective proxies.
So I specified it by adding spring-aop xsd to my application-context.xml like this ("------->" to make a legend, although not valid :) in this xml):
<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:neo4j="http://www.springframework.org/schema/data/neo4j"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop" ------->That is added
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/data/neo4j
http://www.springframework.org/schema/data/neo4j/spring-neo4j-2.1.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd" ---------> That is added >
.....
<aop:aspectj-autoproxy/>
.....
Now the whole works.

Property file in spring mvc

I have a property file with key value pairs:
key1=value1
key2=value2
Now, in my controller, I want to directly print the value of a property file (of course after loading the property file using web.xml / app-servlet.xml), like:
System.out.printl(${key1});
Is it possible to do that?
If not, I want to create an interface with all constant variable to read values from property file. How do I do it??
public interface MyConstants
{
#Value("${key1}")
public static final KEY_1="";
}
But as expected only empty string is assigned.
How do I solve this issue? Or, what is the best way to using property files to retrieve values? Thanks in advance...
There are two reasons why having an interface for 'MyConstants' instead of a class is incorrect :
1) Spring cannot inject values to an interface which has no implementation. Simply because you wont be able instantiate the interface. Remember, Spring is just a factory and it can play only with 'things' which can be instantiated.
2) Another reason is that having an interface for storing your constants is an anti-pattern in itself. That is not what interfaces are designed for. You might want to refer to the Constant interface anti-pattern.
http://en.wikipedia.org/wiki/Constant_interface
It's possible! You need to use the util namespace in your app-servlet.xml as below:
<?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:p="http://www.springframework.org/schema/p" xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.2.xsd">
<util:properties id="props" location="classpath:yourfile.properties" />
<!-- other -->
</beans>
And your controller is something like
#org.springframework.beans.factory.annotation.Value("#{props.key1}")
public void setFoo(String foo) {
System.out.println("props.key1: " + foo);
}
update for another way:
You also can use namespace context
<context:property-placeholder location="classpath:yourfile.properties" />
In controller, declare a property as below
#Value("${pros.key1}")
private String foo;
Creating a ''Constants'' class / interface is a widely used approach, but I think its a flawed approach. It creates a weird coupling where classes from different layers in your system suddenly start depending on one Constants class. It also becomes difficult to understand by looking at the constants class, as to which constant is being used by who? Not to mention the fact that it completely mocks abstraction. You suddenly have a constants class which contains information about the error message to show on the jsp, username and password of a third party api, thread pool size etc.. all in one "I know everything" class
So avoid a constant class / interface as far as possible. Look at your controllers / services, if a particular service class needs a particular configuration value that you want exposed in a property file, inject it into the class and store it as an instance level constant. This design is much cleaner from an abstraction point of view, it also helps to unit test this class easily.
In Spring, you can create a handle to a property file as follows:
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations" value="classpath:my-application.properties" />
</bean>
As the code suggests, you can mention multiple property files here. After you do this, you can reference a key from the mentioned property file, elsewhere in the context like so:
<bean id="xx" class="com.xx.SomeClass" p:imageUrl="${categories.images}"/>
The SomeClass instance here has a property called imageUrl which is now injected with the value mentioned against the categories.images key from the property file called my-application.properties
Hope this helps.

Mocks returning mocks: Mocking neo4j (database) objects for unit testing of domain logic

I am unit testing domain logic and domain objects backed by a neo4j database. Most of these tests need to mock the neo4j GraphDatabaseService, various Nodes, and various Relationships. Some of the mocked methods return these mocked objects. For example, a getReferenceNode() call returns a mocked Node or a getSingleRelationship() call returns a mocked Relationship whose getEndNode() in turn returns a mocked Node.
I'm concerned by the number of mocks returning mocks returning mocks. Usually, this isn't recommended. It certainly complicates the test setup and leads to quite brittle tests, because so many layers of neo4j functionality need to be mocked.
Is there a way to avoid this when unit testing neo4j-backed domain logic?
You could try using a temporary database--one that gets created/flushed every time. In case you need to sample data then you could:
either have a fixture that populates the new db with data;
have a test db setup that is used every time you run tests (in this case you must figure out a way to rollback your changes or always start from the known state)
I am using Maven, Spring data source and unit test my app using the ImpermanentGraphDatabase.
Since it was quite hard to set it up here is what i did:
in my applicationContext.xml I initialized the graphDatabaseService:
<?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:neo4j="http://www.springframework.org/schema/data/neo4j"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/data/neo4j http://www.springframework.org/schema/data/neo4j/spring-neo4j-2.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"
default-lazy-init="true">
<neo4j:config graphDatabaseService="graphDatabaseService"/>
<!-- use in memory graph database -->
<bean id="graphDatabaseService" class="org.neo4j.test.ImpermanentGraphDatabase"/>
</beans>
in my pom.xml i had to add the kernel-tests:
<dependency>
<groupId>org.neo4j</groupId>
<artifactId>neo4j-kernel</artifactId>
<version>1.6</version>
<classifier>tests</classifier>
<scope>test</scope>
</dependency>
otherwise the impermanentGraphDatabase won't be available.
finally I could use a clean graph db evrytime:
public class MyNeo4JTest extends TestCase {
protected ApplicationContext ctx;
protected GraphDatabaseService gds;
#Before
public void setUp() throws Exception {
// test-data
ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
gds = ctx.getBean(GraphDatabaseService.class);
}
#Test
public void testUser () {
...
}
}
I find that the setup is MUCH faster than using the normal way. keeping everything in memory seems to pay off

Categories