1 Spring框架Bean實例化的方式:
提供了三種方式實例化Bean.
- 構造方法實例化:(默認無參數)
- 靜態工廠實例化:
- 實例工廠實例化:
無參數構造方法的實例化:
<!-- 默認情況下使用的就是無參數的構造方法. -->
<bean id="bean1" class="cn.itcast.spring3.demo2.Bean1"></bean>
靜態工廠實例化:
<!-- 第二種使用靜態工廠實例化 -->
<bean id="bean2" class="cn.itcast.spring3.demo2.Bean2Factory" factory-method="getBean2"></bean>
需要寫兩個類一個是實例化的類bean2,另外一個是實例化類的工廠Bean2Factory,這個實例方法必須要是靜態的,通過這個方法就實例化這個bean2了
public class Bean2Factory {
public static Bean2 getBean2(){
System.out.println("靜態工廠的獲得Bean2的方法...");
return new Bean2();
}
}
實例工廠實例化:
<!-- 第三種使用實例工廠實例化 -->
<bean id="bean3" factory-bean="bean3Factory" factory-method="getBean3"></bean>
<bean id="bean3Factory" class="cn.itcast.spring3.demo2.Bean3Factory"/>
這個是表示首先需要實例化工廠,然后指定需要實例的對象bean3,並給他指定實例化他的類和實例化他的方法
public class Bean3Factory {
public Bean3 getBean3(){
System.out.println("Bean3實例工廠的getBean3方法...");
return new Bean3();
}
}
注意:以上三種實例化方法我們主要是使用第一種利用無參構造函數來實例化一個對象,所以在寫類的時候最好加一個無參的構造函數
2 Bean的其他配置:
(1) id和name的區別:
- id遵守XML約束的id的約束.id約束保證這個屬性的值是唯一的,而且必須以字母開始,可以使用字母、數字、連字符、下划線、句話、冒號
- name沒有這些要求
- 注意:
- 如果bean標簽上沒有配置id,那么name可以作為id.
- 開發中Spring和Struts1整合的時候, /login.這種不能作為id只能作為name了。
- 現在的開發中都使用id屬性即可.
(2) 類的作用范圍:
scope屬性 :
- singleton :單例的.(默認的值.)
- prototype :多例的.
- request :web開發中.創建了一個對象,將這個對象存入request范圍,request.setAttribute();
- session :web開發中.創建了一個對象,將這個對象存入session范圍,session.setAttribute();
- globalSession :一般用於Porlet應用環境.指的是分布式開發.不是porlet環境,globalSession等同於session;
實際開發中主要使用singleton,prototype
(3) Bean的生命周期:
- 配置Bean的初始化和銷毀的方法:
- 配置初始化和銷毀的方法:
* init-method=”setup”
* destroy-method=”teardown”
- 執行銷毀的時候,必須手動關閉工廠,而且只對scope=”singleton”有效.
<bean id="helloService" class="HelloService" init-method="setup" destroy-method="teardown"/>
也就是說在實例化這個對象的時候指定了初始化的方法就是setup,而銷毀的方法是teardown,初始化是指在構造器結束之后也就是對象實例化之后先執行的方法,而銷毀方法是指對象銷毀的時候執行的方法,通常我們可以通過classPathXmlApplicationContext.close();
來實現對象的銷毀。
Bean的生命周期的11個步驟:
- instantiate bean對象實例化
- populate properties 封裝屬性
- 如果Bean實現BeanNameAware 執行 setBeanName
- 如果Bean實現BeanFactoryAware 或者 ApplicationContextAware 設置工廠 setBeanFactory 或者上下文對象 setApplicationContext
- 如果存在類實現 BeanPostProcessor(后處理Bean) ,執行postProcessBeforeInitialization
- 如果Bean實現InitializingBean 執行 afterPropertiesSet
- 調用
指定初始化方法 init
- 如果存在類實現 BeanPostProcessor(處理Bean) ,執行postProcessAfterInitialization
- 執行業務處理
- 如果Bean實現 DisposableBean 執行 destroy
- 調用
指定銷毀方法 customerDestroy
觀察生命周期
public class CustomerServiceImpl implements CustomerService, BeanNameAware,ApplicationContextAware,InitializingBean,DisposableBean {
private String name;
public void setName(String name) {
System.out.println("第二步:屬性的注入.");
this.name = name;
}
public CustomerServiceImpl() {
super();
System.out.println("第一步:實例化類.");
}
public void add(){
System.out.println("添加客戶...");
}
public void find(){
System.out.println("查詢客戶...");
}
public void setBeanName(String name) {
System.out.println("第三步:注入配置的類的名稱"+name);
}
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
System.out.println("第四步:注入applicationContext"+applicationContext);
}
public void afterPropertiesSet() throws Exception {
System.out.println("第六步:屬性設置后執行...");
}
public void setup(){
System.out.println("第七步:調用手動設置的初始化方法...");
}
public void destroy() throws Exception {
System.out.println("第十步:調用銷毀的方法...");
}
public void teardown(){
System.out.println("第十一步:調用手動銷毀方法...");
}
}
存在一個類實現BeanPostProcessor
public class MyBeanPostProcessor implements BeanPostProcessor{
/**
* bean:實例對象
* beanName:在配置文件中配置的類的標識.
*/
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
System.out.println("第五步:初始化之前執行...");
return bean;
}
public Object postProcessAfterInitialization(final Object bean, String beanName)
throws BeansException {
System.out.println("第八步:初始化后執行...");
// 動態代理:
if(beanName.equals("customerService")){
Object proxy = Proxy.newProxyInstance(bean.getClass().getClassLoader(), bean.getClass().getInterfaces() , new InvocationHandler() {
// 調用目標方法的時候,調用invoke方法.
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
if("add".equals(method.getName())){
System.out.println("權限校驗...");
Object result = method.invoke(bean, args);
//System.out.println(System.currentTimeMillis());
return result;
}
return method.invoke(bean, args);
}
});
return proxy;
}
return bean;
}
}
配置
<!-- demo4Bean的生命周期==================================== -->
<bean id="customerService" class="cn.itcast.spring3.demo4.CustomerServiceImpl" init-method="setup" destroy-method="teardown">
<property name="name" value="itcast"></property>
</bean>
<bean class="cn.itcast.spring3.demo4.MyBeanPostProcessor"></bean>
一旦配置文件里有類實現了BeanPostProcessor,那么配置文件中的所有類實例化的時候都需要去執行這個類里面的先處理bean和后處理bean的兩個方法,所以是否配置這個是需要考慮的,它主要用處也可以在權限校驗的時候作用比較明顯。
在CustomerService類的add方法之前進行權限校驗?
3 Bean中屬性注入:
Spring支持構造方法注入和setter方法注入:
構造器注入:
這里面通過構造注入需要在寫一個帶參數的構造器,但是無參的構造器也要有,否則不能實例化類了,如果出入的屬性只是一般屬性那么用value傳值就可以了,name屬性主要指定傳給哪一個屬性,當然也可以通過index來指定給第幾個參數傳值,也可以指定參數的類型type,這個是可選的。
<bean id="car" class="cn.itcast.spring3.demo5.Car">
<!-- <constructor-arg name="name" value="寶馬"/>
<constructor-arg name="price" value="1000000"/> -->
<constructor-arg index="0" type="java.lang.String" value="奔馳"/>
<constructor-arg index="1" type="java.lang.Double" value="2000000"/>
</bean>
setter方法注入:
注意這里面通過setter方式意思就是實例化類里面需要讓屬性有setXXX方法才能夠注入進去否則不行
<bean id="car2" class="cn.itcast.spring3.demo5.Car2">
<!-- <property>標簽中name就是屬性名稱,value是普通屬性的值,ref:引用其他的對象 -->
<property name="name" value="保時捷"/>
<property name="price" value="5000000"/>
</bean>
setter方法注入對象屬性:
<property name="car2" ref="car2"/>
名稱空間p:注入屬性(一般不用):
Spring2.5版本引入了名稱空間p.
p:<屬性名>="xxx" 引入常量值
p:<屬性名>-ref="xxx" 引用其它Bean對象
引入名稱空間:
<beans xmlns="http://www.springframework.org/schema/beans"
<font color=red> xmlns:p="http://www.springframework.org/schema/p"</font>
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="car2" class="cn.itcast.spring3.demo5.Car2" p:name="寶馬" p:price="400000"/>
<bean id="person" class="cn.itcast.spring3.demo5.Person" p:name="童童" p:car2-ref="car2"/>
SpEL:屬性的注入(我覺得也一般不用):
Spring3.0提供注入屬性方式:
語法:#{表達式}
- 注意這里面我們注入屬性的話就全部用value,如果是普通屬性就用‘’,如果是引用其他對象就直接將該對象的id加進來就可以了,同時還可以注入其他對象的屬性或者方法的值。
<bean id="car2" class="cn.itcast.spring3.demo5.Car2">
<property name="name" value="#{'大眾'}"></property>
<property name="price" value="#{'120000'}"></property>
</bean>
<bean id="person" class="cn.itcast.spring3.demo5.Person">
<!--<property name="name" value="#{personInfo.name}"/>-->
<property name="name" value="#{personInfo.showName()}"/>
<property name="car2" value="#{car2}"/>
</bean>
<bean id="personInfo" class="cn.itcast.spring3.demo5.PersonInfo">
<property name="name" value="張三"/>
</bean>
4 集合屬性的注入:
<bean id="collectionBean" class="cn.itcast.spring3.demo6.CollectionBean">
<!-- 注入List集合 -->
<property name="list">
<list>
<value>童童</value>
<value>小鳳</value>
</list>
</property>
<!-- 注入set集合 -->
<property name="set">
<set>
<value>杜宏</value>
<value>如花</value>
</set>
</property>
<!-- 注入map集合 -->
<property name="map">
<map>
<entry key="剛剛" value="111"/>
<entry key="嬌嬌" value="333"/>
</map>
</property>
<property name="properties">
<props>
<prop key="username">root</prop>
<prop key="password">123</prop>
</props>
</property>
</bean>
實例化的類
public class CollectionBean {
private List<String> list;
private Set<String> set;
private Map<String,Integer> map;
private Properties properties;
public void setSet(Set<String> set) {
this.set = set;
}
public void setList(List<String> list) {
this.list = list;
}
public void setMap(Map<String, Integer> map) {
this.map = map;
}
public void setProperties(Properties properties) {
this.properties = properties;
}
@Override
public String toString() {
return "CollectionBean [list=" + list + ", set=" + set + ", map=" + map
+ ", properties=" + properties + "]";
}
}
5加載配置文件:
如果配置文件過多或者為了保證不讓一個配置文件內容太多可以分開寫,那么在加載的時候是可以通過這兩種方式加載多個配置文件的,其中第二種方式是在某個配置文件中拼接另外一個配置文件。
一種寫法:
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean1.xml",”bean2.xml”);
二種方法:
<import resource="applicationContext2.xml"/>