All 19 entries tagged Spring
View all 46 entries tagged Spring on Warwick Blogs | View entries tagged Spring at Technorati | There are no images tagged Spring on this blog
July 05, 2006
The practice of
So I have started to use Springs funky new schema support and AOP for applying transactions. Previously we were doing things the very long and hard way:<bean name="myControllerTarget" class="uk....MyController"> </bean> <bean name="/mycontroller/myurl.htm" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="proxyInterfaces"> <value>org.springframework.web.servlet.mvc.Controller</value> </property> <property name="interceptorNames"> <list> <value>transactionInterceptor</value> <value>myControllerTarget</value> </list> </property> </bean>
(Let’s not go into the whole “transactional controller” debate :))
Anyway, whilst being very verbose, this had the very valuable benefit of being extremely explicit. Which, as we will see, is extremely useful quality.
So I decided that I would use Spring’s new schema and ended up with:
<tx:advice id="readWriteTxAdvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="handleRequest"/> </tx:attributes> </tx:advice> <aop:config> <aop:pointcut id="serviceMethods" expression="execution(* org.springframework.web.servlet.mvc.Controller.*(..))"/> <aop:advisor advice-ref="readWriteTxAdvice" pointcut-ref="serviceMethods"/> </aop:config>
and everything stopped working :( More specifically, when I programatically rolled back a transaction I would end up with an UnexpectedRollbackException :( After asking the exceptionally helpful people at the Spring forum (http://forum.springframework.org/showthread.php?t=26574), it turned out that I had somehow managed to end up with a nested transaction….the nested transaction was marked as rollback whilst the outer transaction was trying to be committed.
So, off I go exercising my brain trying to determine how on earth I was getting a nested transaction and I thought “hmmm, the pointcut is Controller., maybe this is being applied to implementations of Controller”. Given that the AbstractController has a “handleRequest” and “handleRequestInternal” method, I assumed *yes, ass out of u and me ;) that one transaction was being started when handleRequest was invoked and another when handleRequestInternal. This is wrong wrong wrong for two reasons; Controller.* doesn’t match (although I need to confirm this) methods on subclasses and secondly the transaction advice explicity only handles the “handleRequest” method, but why should I let little things like that stop me :)
So I thought, “well, the pointcut is obviously too inclusive, lets restrict it” and ended up with
<tx:advice id="readWriteTxAdvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="handleRequest"/> </tx:attributes> </tx:advice> <aop:config> <aop:pointcut id="serviceMethods" expression="execution(* org.springframework.web.servlet.mvc.Controller.handle(..))"/> <aop:advisor advice-ref="readWriteTxAdvice" pointcut-ref="serviceMethods"/> </aop:config>
Thats better isn’t it. Deployed, and it worked.
Then it struck me…..the method on the Controller is called “handleRequest”, not “handle”.....as a result the pointcut would match absolutely nothing :)
So how the flipping heck is this thing working, because rollbacks were working, commits were working etc.?
The other point to this joyful account is that fact that the context in which the aop was defined was importing another context which had a controller defined (actually it was the Spring Web Flow controller). And after looking in their, it was immediately apparent that the flow controller was wrapped using the old style.
Great.
So actually what was happening was the controller was coming out of the included context already wrapped in a transactional proxy. The aop: stuff in the “parent” context was then wrapping it in another transaction.
By “fixing” the aop:pointcut I had ineffect disabled the aop:pointcut, hence there was only one transactional proxy..the one explicitly defined in the included flow.
The fix was easy when I understand the problem.
I managed to spend a good couple of hours identifying the problem and the “solution” not by understanding the problem, but understanding its behaviour. The “solution” was identified not because it fixed the problem, but because it appeared to work.
This is actually quite rare for me…I am usually so anal that I absolutely have to understand why it is breaking…it usually isn’t enough to simply know it works, I have to know why :)
Ah well…..
Moral of the story…make sure you really understand the cause of the problem, and not just its characteristics…..and don’t believe everything I say about aop :)
July 04, 2006
So my book is doing well :)
Writing about web page http://www.amazon.com/gp/product/customer-reviews/159059584X/103-6827141-9792643
So the book I contributed to (I did the last two chapters on Spring Web Flow) seems to be doing well.
No idea about the number of sales (although I did receive my first commission cheque ;)), but all the reviews seem to like it.
Anyways, if you understand the title (Expert Spring MVC + Web Flow) then go and buy the book :) If you are really lucky and bring it to me in elab before the end of the week I might even sign it for you ;) :)
April 15, 2006
Performance of Spring CGLIB and JDK proxies
So I noticed a couple of questions popping up on the Spring forums asking about the cost of using AOP in Spring. This is really a question of how expensive CGLIB or JDK proxies are.
Since I had no real idea (there are lots of "not than expensive" comments around) I decided to write a little test.
Essentially I construct X instances of a class, X instances of a CGLIB proxy of that class (cglib sub classes the target class) and X instances of a JDK proxy, and then called the same method on each instance and measured the time. Hardly conclusive, but enough to give an idea.
I assumed the impact was minimal; when X is 10000:
Unproxied: 926654(ns) 9(ms) cglib: 23986289(ns) 239(ms) Proxy: 70206129(ns) 702(ms)
I expected some over head, but notwhere near that much….. I was also suprised that CGLIB was almost 3 times quicker than JDK proxies (JDK1.5.0_06 on WinXP SP2).
It is still a long way away from being the bottleneck in any system I am likely to write, but good to know :)
I expect AspectJ style weaving is probably a lot more efficient because (IIUI) it modified the byte code directly. Of course, there is an overhead of the modification, but that is a one off…. But I may be so completely wrong :)
Code:
public class MyClassImpl implements MyClass {
public void doSomething() {
}
}
public interface MyClass {
void doSomething();
}
import junit.framework.TestCase;
import org.springframework.aop.framework.ProxyFactoryBean;
public final class ProxyTest extends TestCase {
public void testPerformance() {
int numberToExecute = 10000;
MyClass[] classes = new MyClass[numberToExecute];
for (int i = 0; i< numberToExecute; i++) {
classes[i] = new MyClassImpl();
}
MyClass[] cglibProxyClasses = new MyClassImpl[numberToExecute];
for (int i = 0; i< numberToExecute; i++) {
ProxyFactoryBean factoryBean = new ProxyFactoryBean();
factoryBean.setProxyTargetClass(true);
factoryBean.setTarget(classes[i]);
cglibProxyClasses[i] = (MyClass) factoryBean.getObject();
}
MyClass[] proxyClasses = new MyClass[numberToExecute];
for (int i = 0; i< numberToExecute; i++) {
ProxyFactoryBean factoryBean = new ProxyFactoryBean();
factoryBean.setProxyTargetClass(false);
factoryBean.setInterfaces(new Class[] {MyClass.class });
factoryBean.setTarget(classes[i]);
proxyClasses[i] = (MyClass) factoryBean.getObject();
}
long unproxyExecution = executeClasses(numberToExecute, classes);
displayResults("Unproxied", unproxyExecution);
long cglibExecution = executeClasses(numberToExecute, cglibProxyClasses);
displayResults("cglib", cglibExecution);
long proxyExecution = executeClasses(numberToExecute, proxyClasses);
displayResults("Proxy", proxyExecution);
}
private void displayResults(String label, long unproxyExecution) {
System.out.println(label + ": " + unproxyExecution + "(ns) " + (unproxyExecution / 100000) + "(ms)");
}
private long executeClasses(int numberToExecute, MyClass[] classes) {
long start = System.nanoTime();
for (int i = 0; i< numberToExecute; i++) {
classes[i].doSomething();
}
long end = System.nanoTime();
long execution = end – start;
return execution;
}
}
March 27, 2006
Threading in JBoss, hibernate + spring
The project I am currently working on has an OM which looks like:
page -> content -> contentFetcher
The page typically has 4 contents (links, toolbars, main and rhs) which are sequentially loaded. This seems like a good candidate for threading; there are no dependencies between them and they are each potentially expensive to created (coming from remote servers etc.).
As an experiment I wrapped added the call to retrieve them in it's own thread and deployed. Unfortunately it all went horribly wrong….and (I think) it is because we are using spring OSIV which creates a single session for the entire thread. The stack trace is:
java.util.ConcurrentModificationException
at java.util.HashMap$HashIterator.nextEntry(HashMap.java:787)
at java.util.HashMap$ValueIterator.next(HashMap.java:817)
at org.hibernate.pretty.Printer.toString(Printer.java:90)
at org.hibernate.event.def.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListen
er.java:97)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:26)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1009)
at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:356)
at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:106)
at org.springframework.orm.hibernate3.HibernateTransactionManager.doCommit(HibernateTransactionManager.java:584)
which is a shame.
(As an aside, it is OK to create threads within JBoss, or rather to retrieve threads from a custom threadpool; thus allowing JBoss to shut down without your threads holding anything up.)
I am sure I can work around this, and I have only spent 5 minutes on this so far, but I don't think we will be able to use SessionPerView…..
P.S link
March 21, 2006
Expert Spring MVC + Spring Web Flow errata
Writing about web page http://apress.com/book/bookDisplay.html?bID=10048
Below are the changes in Chapter 11 + Chapter 12 as a result of upgrading to Spring Web Flow 1.0 EA:
[global changes]
_flowExecutionId has been renamed to _flowExecutionKey
org.springframework.webflow.manager has been renamed to org.springframework.webflow.executor
FlowExecutionManager has been renamed to FlowExecutor
FlowExecutionManagerImpl has been renamed to FlowExecutorImpl
FlowExecutionContinuationKey has been renamed to FlowExecutionKey
FlowExecutionManagerParameterExtractor has been renamed to FlowExecutorArgumentExtractor
Chapter 11
– Figure 11–3 (page 7) has four boxes which all contain text starting "webflow.manager.". The word "manager" needs to be replaced with the word "executor", i.e the first box should read webflow.executor.struts.FlowAction etc.
– The first line of the last paragraph on page 7 refers to "FlowExecutionManager". This has been renamed to "FlowExecutor".
– Page 8 refers to "org.springframework.webflow.execution.FlowExecutionRepository". This has been renamed to "org.springframework.webflow.execution.repository.FlowExecutionRepository".
– Page 17 refers to "AbstractFlowexecutionTests" but the e after "Flow" should be capitalised: "AbstractFlowExecutionTests".
– The first two methods in Listing 11–8 are duplicates. Please remove the first method. The second method needs to change from:
protected Resource getFlowLocation() {
File flowDir = new File(.......);
return new FileSyste…..
}
to:
protected Resource getFlowLocation() {
File flowDir = new File(.......);
FileSystemResource resource = new FileSystemResource(new File(flowDir, "purchase-flow.xml"));
return new ExternalizedFlowDefinition("purchaseFlow", resource);
}
so essentially the first line stays the same, and the second line is replaced with two new lines.
– Listing 11–13 on page 22 refers to "org.springframework.webflow.manager.
mvc.FlowController" The word "manager" needs to be replaced with the word "executor".
– The next paragragh on page 22 contains a reference to "org.springframework.webflow.mvc.FlowController". This should be "org.springframework.webflow.executor.mvc.FlowController".
– Page 26 refers to " org.springframework.webflow.config.FlowBuilder". This should be "org.springframework.webflow.builder.FlowBuilder".
Chapter 12
[global and specific changes]
– Page 8, first sentence contains " org.springframework.binding.AttributeMapper". Should be "org.springframework.binding.mapping.AttributeMapper".
– Page 9, first paragraph contains "ParameterizableFlowAttributeMapper", should be DefaultFlowAttributeMapper.
– Page 9, Listing 12–9 first method signature is "public Map createSubflowInput(Request…..". Should be "public AttributeMap createSubflowInput(Request….".
First line in first method is "Map map = new HashMap()" should be "AttributeMap map = new AttributeMap()".
Second method signature is "public void mapSubflowOuput(Map subflowOutput…." should be "public void mapSubflowOutput(UnmodifiableAttributeMap…".
– Page 12, In "Integration With Web Frameworks" the term FlowExecutionManager needs to be replaced with FlowExecutor. There are 5 occurences (although any others you spot should also be changed).
The last but one sentence "Both methods accept org…... and return org…." should read "Both methods accept org.springframework.webflow.ExternalContext in their parameters and return org.springframework.webflow.executor.ResponseInstruction , from which the org.springframework.webflow.ViewSelection can be obtained."
Listing 12–11 has completely changed:
public interface ExternalContext {
public String getContextPath();
public String getDispatcherPath();
public String getRequestPathInfo();
public ParameterMap getRequestParameterMap();
public AttributeMap getRequestMap();
public SharedAttributeMap getSessionMap();
public SharedAttributeMap getApplicationMap();
public interface SharedMap extends Map {
public Object getMutex();
}
public static class SharedAttributeMap extends AttributeMap {
public SharedAttributeMap(SharedMap sharedMap) {
super(sharedMap);
}
public SharedMap getSharedMap() {
return (SharedMap)getMapInternal();
}
public Object getMutex() {
return getSharedMap().getMutex();
}
}
}
– Page 13 Last entry in Table 12–2 contains the word "manager." should be "executor."
"The FlowExecutionManager" should be renamed "FlowExecutor".
Listing 12–12 heading should be changed to "org.springframework.webflow.executor.FlowExecutor".
Both methods return "ViewSelection". They should return "ResponseInstruction".
Within the Note, "FlowExecutionManager" should be renamed to "FlowExecutor".
The next two paragraphs require all instances of "FlowExecutionManager" to be changed to "FlowExecutor". I count 2 instances
The next two paragraphs require all instances of "_flowExecutionId" to be changed to "_flowExecutionKey". I count 2 instances
The "org.springframework.webflow.executor.support.FlowExecutionManagerParameterExtractor" needs to be "org.springframework.webflow.executor.FlowExecutorArgumentExtractor".
-Page 15, Listing 12–13 Please remove the last method "rehydrate".
Listing 12–14 FlowExecutionContext has changed. It essentially needs to be:
public interface FlowExecutionContext extends FlowExecutionStatistics {
public Flow getFlow();
public AttributeMap getScope();
FlowSession getActiveSession();
}
The next paragraph contains the phrase "the active flow definition, the current state, and" which needs to be replaced with "conversation scope and".
The next paragraph contains the phrase "The root flow" which needs to be replaced with "The flow". The last sentence contains "getActiveFlow()" which needs to be "getFlow()".
Page 17, Listing 12–15 has changed. It should now be:
public interface RequestContext {
public Flow getActiveFlow() throws IllegalStateException;
public State getCurrentState() throws IllegalStateException;
public AttributeMap getRequestScope();
public AttributeMap getFlowScope();
public AttributeMap getConversationScope();
public ParameterMap getRequestParameters();
public ExternalContext getExternalContext();
public FlowExecutionContext getFlowExecutionContext();
public Event getLastEvent();
public Transition getLastTransition();
public UnmodifiableAttributeMap getAttributes();
public void setAttributes(AttributeCollection attributes);
public UnmodifiableAttributeMap getModel();
}
Page 18 contains two references to "org.springframework.webflow.manager.ConditionalFlowExecutionListenerLoader". They should be "org.springframework.webflow.executor.ConditionalFlowExecutionListenerLoader ".
Listing 12–17 on Page 18 contains a reference to "org.springframework.webflow.manager.FlowExecutionManagerImpl". It should be "org.springframework.webflow.executor.FlowExecutorImpl".
Page 19, Listing 12–18 has completely changed:
public interface FlowExecutionRepository {
public FlowExecution createFlowExecution(String flowId);
public FlowExecutionKey generateKey(FlowExecution flowExecution) throws FlowExecutionRepositoryException;
public FlowExecutionKey generateKey(FlowExecution flowExecution, Serializable conversationId) throws FlowExecutionRepositoryException;
public ConversationLock getLock(Serializable conversationId);
public FlowExecution getFlowExecution(FlowExecutionKey key) throws FlowExecutionRepositoryException;
public void putFlowExecution(FlowExecutionKey key, FlowExecution flowExecution) throws FlowExecutionRepositoryException;
public FlowExecutionKey getCurrentFlowExecutionKey(Serializable conversationId) throws FlowExecutionRepositoryException;
public ViewSelection getCurrentViewSelection(Serializable conversationId) throws FlowExecutionRepositoryException;
public void setCurrentViewSelection(Serializable conversationId, ViewSelection viewSelection) throws FlowExecutionRepositoryException;
public void invalidateConversation(Serializable conversationId) throws FlowExecutionRepositoryException;
}
– Page 22 contains a number of references to FlowExecutionContinuationKey. This has been renamed to FlowExecutionKey.
– Page 22 contains a number of references to _flowExecutionId. This has been renamed to _flowExecutionKey.
– Page 22 at the bottom contains a reference to "org.springframework.webflow.execution.repository.SimpleFlowExecutionRepository ". It should be "org.springframework.webflow.execution.repository.support.SimpleFlowExecutionRepository".
Page 23. The note should read "This is the default implementation."
Page 23 contains a reference to "_flowExecutionId", it should be "_flowExecutionKey".
Page 24 contains two references to "_flowExecutionId", they should be "_flowExecutionKey".
Page 30, Table 12–10 contains a reference to "RedirectViewSelector". Should be "ExternalRedirectSelector".
Table 12–11 is wrong, should be:
ApplicationViewSelector If viewName is specified.
ApplicationViewSelector If redirect:viewName is specified.
ExternalRedirectSelector If externalRedirect:/url?par1=x is specified
FlowRedirectSelector If flowRedrect:/url is specified
YourViewSelector If bean=yourBean is specified.
– Page 31 contains three references to "FlowExecutionManagerParameterExtractor". They should all be "FlowExecutorArgumentExtractor".
– Page 31 contains three references to "FEMPE". They should all be "FEAE".
– Page 34 contains a reference to "InvalidConversionationContinuationException". Should be "CannotContinueConversationException".
March 05, 2006
So the reviews are trickling in
Follow-up to Spring Web Flow book is now released! from Colin's blog
So I have been keeping an eye on any reviews that have been posted, and spotted a few:
and
Any more, please let me know as this is a first time experience for me and it is always good to get feedback ;)
February 22, 2006
Spring Web Flow book is now released!
Writing about web page http://www.amazon.co.uk/exec/obidos/ASIN/159059584X/qid%3D1140629254/202-1067120-0416610
Yeah, so the new Spring Web Flow + Spring MVC book has finally been released :)
This makes me happy because I wrote the two chapters regarding Spring Web Flow, so go and buy a copy :) :)
February 08, 2006
Useful Spring tips
Writing about web page http://www.onjava.com/pub/a/onjava/2006/01/25/spring-xml-configuration-best-practices.html?page=1
Nothing too outstanding here, and I am not sure I agree with all of the tips, but a useful page for newbies :)
In particular, I disagree with not using autowiring; autowiring by type is safer than byName, and is very useful. Maybe I am making this point too strongly; I think it is fine to either use it or not.
The point I most strongly disagree with is preferring setter injection over constructor injection. That is just plain wrong ;) Constructors for collaborators which the class requires to work, setters for optional parameters. Simple as that.
But all in all, a nice quick read.
So I wrote one myself.
Follow-up to Anyone know of a Composite proxy? from Colin's blog
So I wrote one myself: