我们将从如下程序演进中初识Spring。
1、简单的消息取得、消息显示程序原型
消息取得接口:
MessageSupplier.java
package tutorial.spring;
public interface MessageSupplier {
String getMessage();
}
实现类:
package tutorial.spring.impl;
import tutorial.spring.MessageSupplier;
public class HelloWorldMessageSupplier implements MessageSupplier {
public String getMessage() {
return "Hello World";
}
}
消息显示接口:
package tutorial.spring;
public interface MessageDisplayer {
void setMessageSupplier(MessageSupplier supplier);
MessageSupplier getMessageSupplier();
void display();
}
实现类:
package tutorial.spring.impl;
import tutorial.spring.MessageDisplayer;
import tutorial.spring.MessageSupplier;
public class ConcreteMessageDisplayer implements MessageDisplayer {
private MessageSupplier messageSupplier = null;
public void display() {
if(messageSupplier == null) {
throw new RuntimeException(
"必须设定messageSupplier属性: "+
ConcreteMessageDisplayer.class.getName());
}
System.out.println(messageSupplier.getMessage());
}
public MessageSupplier getMessageSupplier() {
return messageSupplier;
}
public void setMessageSupplier(MessageSupplier supplier) {
this.messageSupplier = supplier;
}
}
主程序:
package tutorial.spring;
import tutorial.spring.impl.ConcreteMessageDisplayer;
import tutorial.spring.impl.HelloWorldMessageSupplier;
public class HelloWorldBetterUsage {
public static void main(String[] args) {
MessageDisplayer msgDisplayer = new ConcreteMessageDisplayer();
MessageSupplier msgSupplier = new HelloWorldMessageSupplier();
msgDisplayer.setMessageSupplier(msgSupplier);
msgDisplayer.display();
}
}
首先分别创建ConcreteMessageDisplayer实例和HelloWorldSupplier实例,随后将MessageSupplier传递给MessageDisplayer,最后调用MessageDisplayer的display()方法,执行后的预期结果为:
Hello World
2、引入单例工厂
创建工厂类,通过引用外部文件来读取相应实例类的名字,并由工厂类来负责实例化。
package tutorial.spring;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Properties;
public class MessageSupportFactory {
private static MessageSupportFactory instance = null;
private Properties props = null;
/**
*
* 使用synchronized来保障线程安全性
*/
public synchronized static MessageSupportFactory getInstance() {
if(instance == null)
instance = new MessageSupportFactory();
return instance;
}
private MessageSupportFactory() {
props = new Properties();
try {
props.load(new FileInputStream("src/msgbean.properties"));
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public MessageDisplayer makeDisplayer() {
String displayerClass = props.getProperty("displayer.class");
try{
return(MessageDisplayer)Class.forName(displayerClass).newInstance();
} catch(ClassNotFoundException e) {
System.out.println("Couldn't find class " + displayerClass);
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return null;
}
public MessageSupplier makeSupplier() {
String supplierClass = props.getProperty("supplier.class");
try {
return (MessageSupplier)Class.forName(supplierClass).newInstance();
} catch(Exception e) {
e.printStackTrace();
}
return null;
}
}
msgbean.properties
displayer.class=tutorial.spring.impl.ConcreteMessageDisplayer ################## ################### supplier.class=tutorial.spring.impl.HelloWorldMessageSupplier
通过类反射Class.forName()机制,由外部属性文件来读入实现类的全限定名,并产生各自的实例。
主程序类:
package tutorial.spring;
public class HelloWorldBetterWithFactoryUsage {
public static void main(String[] args) {
MessageDisplayer msgDisplayer =
MessageSupportFactory.getInstance().makeDisplayer();
MessageSupplier msgSupplier =
MessageSupportFactory.getInstance().makeSupplier();
msgDisplayer.setMessageSupplier(msgSupplier);
msgDisplayer.display();
}
}
使用Spring对程序进行重构
package tutorial.spring;
import java.io.FileInputStream;
import java.util.Properties;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.PropertiesBeanDefinitionReader;
public class HelloWorldWithSpringUsage {
public static void main(String[] args) throws Exception {
BeanFactory factory = getBeanFactory();
MessageDisplayer displayer =
(MessageDisplayer) factory.getBean("displayer");
MessageSupplier supplier =
(MessageSupplier) factory.getBean("supplier");
displayer.setMessageSupplier(supplier);
displayer.display();
}
private static BeanFactory getBeanFactory() throws Exception {
DefaultListableBeanFactory factory =
new DefaultListableBeanFactory();
PropertiesBeanDefinitionReader rdr =
new PropertiesBeanDefinitionReader(factory);
Properties props = new Properties();
props.load(new FileInputStream("src/msgbean.properties"));
rdr.registerBeanDefinitions(props);
return factory;
}
}
msgbean.properties文件同上。
使用Spring之后,可以从程序中抛弃MessageSupportFactory,转而直接使用Spring框架自带的工厂类,省去的异常处理由Spring代为处理。遗憾的是仍要手动将MessageSupplier的实现注入MessageDisplayer中。
实现依赖注入
package tutorial.spring;
import java.io.FileInputStream;
import java.util.Properties;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.PropertiesBeanDefinitionReader;
public class HelloWorldWithSpringUsage {
public static void main(String[] args) throws Exception {
BeanFactory factory = getBeanFactory();
MessageDisplayer displayer =
(MessageDisplayer) factory.getBean("displayer");
// MessageSupplier supplier =
// (MessageSupplier) factory.getBean("supplier");
//
// displayer.setMessageSupplier(supplier);
//
displayer.display();
}
private static BeanFactory getBeanFactory() throws Exception {
DefaultListableBeanFactory factory =
new DefaultListableBeanFactory();
PropertiesBeanDefinitionReader rdr =
new PropertiesBeanDefinitionReader(factory);
Properties props = new Properties();
props.load(new FileInputStream("src/msgbean.properties"));
rdr.registerBeanDefinitions(props);
return factory;
}
}
msgbean.properties如下:
displayer.class=tutorial.spring.impl.ConcreteMessageDisplayer
##################
displayer.messageSupplier(ref)=supplier
###################
supplier.class=tutorial.spring.impl.HelloWorldMessageSupplier
(ref)关键字意思是该属性的值将引用另外一个Bean的标示key的值。相比以前代码,在主程序中去除了任何组件依赖相关的代码了。不过这种直接使用Spring框架Api读取属性文件的方式通常在真实情况下不常使用。
Web程序
代码在附件中