[spring]從頭開始-Initializing Bean
開發工具:IntelliJ IDEA 13
開發環境:jdk1.6.0_45
Framework:spring 3
一般spring在注入時,並非只能單純inject 各個 field 而已,還可以加上 initial Method 來對該field做初始化/驗證的動作,這其中有幾種方法,先從最簡單的 init-method 開始
建立一個可以演繹的類別
SimpleBean1.java
package foo.bar;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;
/**
* Created by Hsu on 2014/7/14.
*/
public class SimpleBean1 {
private static final String DEFAULT_NAME = "Luke Skywalker";
private String name = null;
private int age = Integer.MIN_VALUE;
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
//用來初始化的Method
public void init() {
System.out.println("Initializing bean");
if (name == null) {
System.out.println("Using default name");
name = DEFAULT_NAME;
}
if (age == Integer.MIN_VALUE) {
throw new IllegalArgumentException(
"You must set the age property of any beans of type " + SimpleBean1.class);
}
}
public String toString() {
return "Name: " + name + "\nAge: " + age;
}
public static void main(String[] args) {
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:initMethod.xml");
ctx.refresh(); // Refresh the ApplicationContext after XML config file loaded
SimpleBean1 simpleBean1 = getBean("simpleBean1", ctx);
SimpleBean1 simpleBean2 = getBean("simpleBean2", ctx);
SimpleBean1 simpleBean3 = getBean("simpleBean3", ctx);
}
private static SimpleBean1 getBean(String beanName, ApplicationContext ctx) {
try {
SimpleBean1 bean =(SimpleBean1) ctx.getBean(beanName);
System.out.println(bean);
return bean;
} catch (BeanCreationException ex) {
System.out.println("An error occured in bean configuration: "
+ ex.getMessage());
return null;
}
}
}
接下來重要的配置檔也一併建立
initMethod.xml
..
..標頭的部分省略
<bean id="simpleBean1"
class="foo.bar.SimpleBean1"
init-method="init">
<property name="name">
<value>Clarence Ho</value>
</property>
<property name="age">
<value>100</value>
</property>
</bean>
<bean id="simpleBean2"
class="foo.bar.SimpleBean1"
init-method="init">
<property name="age">
<value>100</value>
</property>
</bean>
<bean id="simpleBean3"
class="foo.bar.SimpleBean1"
init-method="init">
<property name="name">
<value>Clarence Ho</value>
</property>
</bean>
..結尾省略
我們可以看到在配置檔中建立了三個bean,每個bean都各給一個init-method,對應到該bean中的 function init(),直接看結果可以看到其中的關係:
Initializing bean
Initializing bean
Using default name
Initializing bean
Name: Clarence Ho
Age: 100
Name: Luke Skywalker
Age: 100
Name: Clarence Ho
Age: 90
第一個 bean 我們有給 name/age,所以只有出現Initializing bean
第二個 bean 我們只有給 age,經過init Method 後,name套用在該方法中指定的值
第三個 bean 我們只有給 name,但是卻若沒有給age,經過init Method後,則會拋出例外
Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'simpleBean3' defined in class path resource [initMethod.xml]: Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: You must set the age property of any beans of type class foo.bar.SimpleBean1
init-method之後,接著是使用Implement InitializingBean 這個類別來演繹
這個方式主要為將要初始化的類別 implement InitializingBean 這個類,先建立一個來看看:
SimpleBeanWithInterface.java
package foo.bar;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;
/**
* Created by Hsu on 2014/7/14.
*/
public class SimpleBeanWithInterface implements InitializingBean {
private static final String DEFAULT_NAME = "Luke Skywalker";
private String name = null;
private int age = Integer.MIN_VALUE;
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
public void myInit() {
System.out.println("My Init");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("Initializing bean");
if (name == null) {
System.out.println("Using default name");
name = DEFAULT_NAME;
}
if (age == Integer.MIN_VALUE) {
throw new IllegalArgumentException(
"You must set the age property of any beans of type " + SimpleBean.class);
}
}
public String toString() {
return "Name: " + name + "\nAge: " + age;
}
public static void main(String[] args) {
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:initInterface.xml");
ctx.refresh();
SimpleBeanWithInterface simpleBean1 = getBean("simpleBean1", ctx);
SimpleBeanWithInterface simpleBean2 = getBean("simpleBean2", ctx);
SimpleBeanWithInterface simpleBean3 = getBean("simpleBean3", ctx);
}
private static SimpleBeanWithInterface getBean(String beanName,
ApplicationContext ctx) {
try {
SimpleBeanWithInterface bean = (SimpleBeanWithInterface) ctx.getBean(beanName);
System.out.println(bean);
return bean;
} catch (BeanCreationException ex) {
System.out.println("An error occured in bean configuration: "
+ ex.getMessage());
return null;
}
}
}
最主要需要 Override afterPropertiesSet() 這個方法,將原本寫在init-method中的內容搬到裡面去
配置檔如下:
initInterface.xml
..
..標頭的部分省略
<!-- 等同使用imit-method -->
<bean id="simpleBean1"
class="foo.bar.SimpleBeanWithInterface">
<property name="name">
<value>Clarence Ho</value>
</property>
<property name="age">
<value>100</value>
</property>
</bean>
<bean id="simpleBean2"
class="foo.bar.SimpleBeanWithInterface">
<property name="age">
<value>100</value>
</property>
</bean>
<bean id="simpleBean3"
class="foo.bar.SimpleBeanWithInterface">
<property name="name">
<value>Clarence Ho</value>
</property>
<property name="age">
<value>50</value>
</property>
</bean>
..結尾省略
執行出來的結果如下:
Initializing bean
Initializing bean
Using default name
Initializing bean
Name: Clarence Ho
Age: 100
Name: Luke Skywalker
Age: 100
Name: Clarence Ho
Age: 50
若未設定Age的話,則將會得到與前一方法相同的 Exception
最後我們使用 Annotation 的方式來演繹相同的狀況,主要是靠 import javax.annotation.PostConstruct 這個類別,並使用 @PostConstruct 來達成。
範例如下:
SimpleBean2.java
package foo.bar;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;
import javax.annotation.PostConstruct;
/**
* Created by Hsu on 2014/7/14.
*/
public class SimpleBean2 {
private static final String DEFAULT_NAME = "Luke Skywalker";
private String name = null;
private int age = Integer.MIN_VALUE;
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
//宣告該方法為該 bean 的建構方法,對應的方法名稱可以自訂,不一定要使用init
@PostConstruct
public void init() {
System.out.println("Initializing bean");
if (name == null) {
System.out.println("Using default name");
name = DEFAULT_NAME;
}
if (age == Integer.MIN_VALUE) {
throw new IllegalArgumentException(
"You must set the age property of any beans of type " + SimpleBean2.class);
}
}
public String toString() {
return "Name: " + name + "\nAge: " + age;
}
public static void main(String[] args) {
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:initMethodByAnnotation.xml");
ctx.refresh(); // Refresh the ApplicationContext after XML config file loaded
SimpleBean2 simpleBean1 = getBean("simpleBean1", ctx);
SimpleBean2 simpleBean2 = getBean("simpleBean2", ctx);
SimpleBean2 simpleBean3 = getBean("simpleBean3", ctx);
}
private static SimpleBean2 getBean(String beanName, ApplicationContext ctx) {
try {
SimpleBean2 bean =(SimpleBean2) ctx.getBean(beanName);
System.out.println(bean);
return bean;
} catch (BeanCreationException ex) {
System.out.println("An error occured in bean configuration: "
+ ex.getMessage());
return null;
}
}
}
接下來是對應的 spring configuration file
initMethodByAnnotation.xml
..
..標頭的部分省略
<context:annotation-config />
<context:component-scan base-package="foo.bar"/>
<!-- 等同使用imit-method 使用 @PostConstruct-->
<bean id="simpleBean1"
class="foo.bar.SimpleBean2">
<property name="name">
<value>Clarence Ho</value>
</property>
<property name="age">
<value>100</value>
</property>
</bean>
<bean id="simpleBean2"
class="foo.bar.SimpleBean2">
<property name="age">
<value>100</value>
</property>
</bean>
<bean id="simpleBean3"
class="foo.bar.SimpleBean2">
<property name="name">
<value>Clarence Ho</value>
</property>
<property name="age">
<value>90</value>
</property>
</bean>
..結尾省略
執行之後的結果如下:
Name: Clarence Ho
Age: 100
Name: null
Age: 100
Name: Clarence Ho
Age: 90
三種initial的方式,其實看專案的配置方式,最好決定之後,都使用同一種方式,以利維護