Using FactoryBean


Spring provides the FactoryBean interface that acts as an adaptor for objects that cannot be created and managed using the standard Spring semantics. Typically, you use a FactoryBean to create beans you cannot use the new operator to create, such as those you access through static factory methods, although this is not always the case. Simply put, a FactoryBean is a bean that acts as a factory for other beans. FactoryBean implementations are configured within your BeanFactory like any normal bean. However, when Spring uses the FactoryBean to satisfy a dependency or lookup request, it does not return the FactoryBean; instead, it invokes the FactoryBean.getObject() method and returns the result of that invocation.


The MessageDigestFactoryBean


Often, the projects that we work on require some kind of cryptographic processing; typically, this involves generating a message digest or hash of a user’s password to be stored in a database. In Java, the MessageDigest class provides functionality for creating a digest of any arbitrary data. MessageDigest itself is abstract, and you obtain concrete implementations by calling MessageDigest.getInstance() and passing in the name of the digest algorithm you want to use. For instance, if we want to use the MD5 algorithm to create a digest, we use the following code to create the MessageDigest instance

MessageDigest md5 = MessageDigest.getInstance(“MD5”);

If we want to use Spring to manage the creation of the MessageDigest object, the best way we can do so without a FactoryBean is to create a property algorithmName on our bean and use an initialization callback to call MessageDigest.getInstance(). Using a FactoryBean, we can encapsulate this logic inside a bean. Once we do so, any beans that require a MessageDigest instance can simply declare a property, messageDigest and use the FactoryBean to obtain the instance

The MessageDigestFactoryBean Class

public class MessageDigestFactoryBean implements FactoryBean, InitializingBean {
private static final String DEFAULT_ALGORITHM = "MD5";
private String algorithm = DEFAULT_ALGORITHM;
private MessageDigest messageDigest;
public Object getObject() throws Exception {
return this.messageDigest.clone();
}
public Class getObjectType() {
return MessageDigest.class;
}

public boolean isSingleton() {
return true;
}
public void setAlgorithm(String algorithm) {
this.algorithm = algorithm;
}
public void afterPropertiesSet() throws Exception {
this.messageDigest = MessageDigest.getInstance(this.algorithm);
}

}

The FactoryBean interface declares three methods: getObject(), getObjectType(), and
isSingleton(). Spring calls the getObject() method to retrieve the Object created by the FactoryBean. This is the actual Object that is passed to other beans that use the FactoryBean as a collaborator.

you can see that the MessageDigestFactoryBean passes a clone of the stored MessageDigest

instance that is created in the InitializingBean.afterPropertiesSet() callback.

The getObjectType() method allows you to tell Spring what type of Object your FactoryBean will return. The returned type can be null if you do not know the type in advance, but if you specify a type, Spring can use it for automatic wiring purposes. We return MessageDigest as our type, because we do not know what concrete type will be returned—not that it matters because all beans will define their dependencies using MessageDigest anyway.

The isSingleton() property allows you to inform Spring whether the FactoryBean is managing a singleton instance or not. Remember that by setting the scope="singleton" of the FactoryBean’s <bean> tag, you tell Spring about the singleton status of the FactoryBean itself, not the Objects it is returning.

The MessageDigestDemo Class

public class MessageDigestDemo {
public static void main(String[] args) {
XmlBeanFactory factory = new XmlBeanFactory(
new ClassPathResource("/META-INF/spring/factorydemo-context.xml")
);
MessageDigest d1 = (MessageDigest)factory.getBean("sha");
MessageDigest d2 = (MessageDigest)factory.getBean("md5");
calculateDigest("Hello, world", d1);
calculateDigest("Hello, world", d2);
}
private static void calculateDigest(String message, MessageDigest digest) {
System.out.print("Digest using " + digest.getAlgorithm() + ": ");
digest.reset();
final byte[] bytes = digest.digest(message.getBytes());
for (byte b : bytes) {
System.out.print(String.format("%02x", b));
}
System.out.println("");
}

}

Configuring Factory Beans

<?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="sha"
class="com.apress.prospring2.ch04.factoy.MessageDigestFactoryBean">
<property name="algorithm" value="SHA1"/>
</bean>
<bean id="md5"
class="com.apress.prospring2.ch04.factoy.MessageDigestFactoryBean"/>

</beans>


Accessing a FactoryBean Directly


Given that Spring automatically satisfies any references to a FactoryBean by the objects produced by that FactoryBean, you may be wondering if you can actually access the FactoryBean directly. The answer is, “Yes.”

Accessing the FactoryBean is actually very simple: you prefix the bean name with an ampersand in the call to getBean(),

public class MessageDigestFactoryDemo {
public static void main(String[] args) throws Exception {
XmlBeanFactory factory = new XmlBeanFactory(
new ClassPathResource("/META-INF/spring/factorydemo-context.xml")
);
MessageDigestFactoryBean factoryBean =

(MessageDigestFactoryBean)factory.getBean("&sha");
MessageDigest d1 = (MessageDigest)factory.getBean("sha");
MessageDigest d2 = (MessageDigest)factoryBean.getObject();
System.out.println("Equal MessageDigests created? "
+ (d1.getAlgorithm().equals(d2.getAlgorithm())));
}

}

Leave a Reply

Subscribe to Posts | Subscribe to Comments

About This Site

Howdy! My name is Suersh Rohan and I am the developer and maintainer of this blog. It mainly consists of my thoughts and opinions on the technologies I learn,use and develop with.

Blog Archive

Powered by Blogger.

- Copyright © My Code Snapshots -Metrominimalist- Powered by Blogger - Designed by Suresh Rohan -