All entries for December 2005

December 16, 2005

Interesting article on threadLocals

Writing about web page http://blog.arendsen.net/index.php/2005/02/22/threadlocals-and-memory-leaks-revisited/

link

Very good.


December 12, 2005

How to post process a Spring Bean?

So I have a FactoryBean which produces a FreeMarker configuration and it all works well.

Now I wanted to precompile all the freeMarker templates and started looking for the appropriate Springs infrastructure to tie into.

I came up with the following options:
[extend the existing BeanFactory
This just seemed hacky. I wasn't changing the strategy for loading the object so the factoryness hadn't changed.

[implement a BeanPostProcessor
This looked like promising; it executed after the factory had done it's thing and had a very convenient "postProcessAfterInitialization" method which passed in the name of the bean, and the bean itself. Cool. The problem is that the bean is the original beanFactory. Sure, I could call getObject() but it all started to feel a bit fragile and icky

[implement BeanFactoryPostProcessor
This went out of the window for two reasons; it suffers the same "problem" as BPP (not a "problem" with Spring, just the way I want to use it) and the single "postProcessBeanFactory" is called before the beans are realised (or instantiated as Spring prefers).

at this point I was thinking, surely there must be something more :)

and there is

[implement ApplicationListener
This little gem (thanks Dave Hewitt :)) listens to all the various events that hook in very nicely with the lifecycle of a BeanFactory, so there is a ContextClosed, ContextRefreshed and RequestHandled event. Implementing the single method "onApplicationEvent" which passed in the ApplicationEvent meant I could write the following bean:


public final class FreeMarkerCompilerEventListener implements ApplicationListener {
    private static final Logger LOGGER = Logger.getLogger(FreeMarkerCompilerEventListener.class);
    private final File templateDir;
    private final Configuration configuration;

    public FreeMarkerCompilerEventListener(final Configuration theConfiguration, final Resource theResource) {
        this.configuration = theConfiguration;
        this.templateDir = verifyResource(theResource);
    }

    public void onApplicationEvent(final ApplicationEvent event) {
        if (event instanceof ContextRefreshedEvent) {
            compile();
        }
    }

    private File verifyResource(final Resource resource) {
        File file;
        try {
            file = resource.getFile();
        } catch (final IOException e) {
            throw new IllegalStateException("Resource " + resource + " must be a directory!", e);
        }

        if (!file.isDirectory()) {
            throw new IllegalStateException("Resource " + resource + " must be a directory!");
        }

        return file;
    }

    private void compile() {
        String[] templateNames = getTemplateNames();
        for (String name: templateNames) {
            try {
                LOGGER.info("Precompiling freemarker template [" + name + "]");
                configuration.getTemplate(name);
            } catch (final IOException e) {
                throw new IllegalStateException("Cannot get template for " + name, e);
            }
        }
    }

    private String[] getTemplateNames() {
        List files = new ArrayList();
        for (File file: templateDir.listFiles()) {
            findFreeMarkerTemplates(file, "", files);
        }
        return files.toArray(new String[] {});
    }

    private void findFreeMarkerTemplates(final File root, final String parentPath, final List filesFound) {
        if (root.isDirectory()) {
            for (File file: root.listFiles()) {
                String newParentPath = parentPath;
                if (StringUtils.hasLength(newParentPath)) {
                    newParentPath += "/";
                }
                newParentPath += root.getName();
                findFreeMarkerTemplates(file, newParentPath, filesFound);
            }
        } else {
            if (root.getName().toLowerCase().endsWith(".ftl")) {
                filesFound.add(parentPath + "/" + root.getName());
            }
        }
    }
}

No messing around with BeanFactories, or fragile bean lookups by name, I simply wire this :


 <bean id="freeMarkerConfig" class="org.springframework.ui.freemarker.FreeMarkerConfigurationFactoryBean">
   <property name="templateLoaderPath"><value>/WEB-INF/freemarker/</value></property>
 </bean>

  <bean id="freeMarkerCompiler" class="uk.ac.warwick.sbr.freemarker.FreeMarkerCompilerEventListener">
    <constructor-arg index="0" ref="freeMarkerConfig"/>
    <constructor-arg index="1" value="/WEB-INF/freemarker/"/>
  </bean>

Spring will realise (via the proper use of it's BeanFactoryPostProcessor) that I have defined an ApplicationListener and will automatically call it when an ApplicationEvent is fired.

Cool.


December 02, 2005

Hibernate + Spring DI

Writing about web page http://www.springframework.org/docs/api/org/springframework/beans/factory/config/AutowireCapableBeanFactory.html

People keep asking how to inject service dependencies into Hibernate backed objects. I briefly responded here but I have recently revisited this code.

I stumbled across AutowireCapableBeanFactory which has a really useful method: autowireBeanProperties) which does the DI on an existing bean.

After reading the javadocs I created this simple class:


package uk.mycompany;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;

import uk.mycompany.ClassFilteringLoadEventListener.LoadedObjectListener;

public final class AutoWiringLoadedObjectListener implements LoadedObjectListener, BeanFactoryAware  {
    private AutowireCapableBeanFactory beanFactory;

    public void loaded(final Object loadedObject) {
        beanFactory.autowireBeanProperties(loadedObject, AutowireCapableBeanFactory.AUTOWIRE_BY_NAME, false);
    }

    public void setBeanFactory(final BeanFactory beanFactory) throws BeansException {
        this.beanFactory = (AutowireCapableBeanFactory) beanFactory;
    }
}

and replaced theuk.mycompany.ClassThatDoesTheAdvisingLoadedListener with the uk.mycompany.AutoWiringLoadedObjectListener and it works beatifully. Is it slow? Not at all. After load testing there was no discernable difference.

Now I don't need to write a class to do per class introspection. Just leave it up to Spring.

I love Spring.


December 2005

Mo Tu We Th Fr Sa Su
Nov |  Today  | Jan
         1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31   

Search this blog

Tags

Galleries

Most recent comments

  • Interesting… While I'm not completely convinced in such microbenchmarks, I'm pretty sure that 1ms … by Alexander Snaps on this entry
  • Hello. I bought the book yesterday. I was trying to find the source code for chapter 11 and chapter … by Suleman on this entry
  • http://woosight.net/account/login?username=demo by live mashup demo on this entry
  • Thanks mate ….. This blog was really helpful. by Maaz Hurzuk on this entry
  • Ty. Not directly helpful for my problem, but pointed me in the right direction. You will also get th… by Mike E. on this entry

Blog archive

Loading…
Not signed in
Sign in

Powered by BlogBuilder
© MMXX