目錄
BeanFactory開發流程
ApplicationContext
BeanFactory與ApplicationContext對比
基于XML方式的Bean的配置
自動裝配
BeanFactory開發流程
這里的第三方指的是Spring提供的BeanFactory,Spring啟動時會初始化BeanFactory,然后讀取配置清單(xml文件)獲取需要被加載的bean。實現上面流程圖的具體代碼如下
創建beans.xml文件
public class Test {public static void main(String[] args) {//定義出一個bean工廠DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();//讀取xml文件的讀取器XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);//讀取配置文件reader.loadBeanDefinitions("beans.xml");UserService userService = (UserService) beanFactory.getBean("userService");System.out.println(userService);}
}
因為我們在開發中要遵循三層架構,業務層需要定義數據層,那么接下來我們再在xml文件中指定要一個數據層bean。代碼如下
public class UserServiceImpl implements UserService {//該方法由beanFactory來調用,set注入public void setUserDao(UserDao userDao){System.out.println("由bean工廠調用該set方法");}
}
需要注意的是,需要property標簽中的屬性的name應該是setXxx()方法中的Xxx第一個子母小寫之后的字符,ref標簽指的是bean定義的id。接下來我們查看Test類的運行結果
public class Test {public static void main(String[] args) {//定義出一個bean工廠DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();//讀取xml文件的讀取器XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);//讀取配置文件reader.loadBeanDefinitions("beans.xml");UserService userService = (UserService) beanFactory.getBean("userService");}
}
執行結果截圖?
BeanFactory是Spring中最重要的核心類,下文中的ApplicationContext雖然叫做Spring容器,但實際上在該類中最后調用的還是BeanFactory。
ApplicationContext
ApplicationContext稱為Spring容器,內部封裝了BeanFactory,比BeanFactory功能更豐富,使用ApplicationContext時,xml文件配置我們習慣叫做applicationContext.xml。接下來是一個示例代碼
public class ApplicationContextTest {public static void main(String[] args) {ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");Object userService = context.getBean("userService");}
}
BeanFactory與ApplicationContext對比
- BeanFactory是Spring的早期接口,稱為Spring的Bean工廠,ApplicationContext是后期更高級接口,稱之為Spring 容器
- ApplicationContext在BeanFactory基礎上對功能進行了擴展,例如: 監聽功能、國際化功能等。BeanFactory的API更偏向底層,ApplicationContext的API大多數是對這些底層API的封裝;
- Bean創建的主要邏輯和功能都被封裝在BeanFactory中ApplicationContext不僅繼承了BeanFactory,而且ApplicationContext內部還維護著BeanFactory的引用,所以,ApplicationContext與BeanFactory既有繼承關系,又有融合關系。
- Bean的初始化時機不同,原始BeanFactory是在首次調用getBean時才進行Bean的創建,而ApplicationContext則是配置文件加載,容器一創建就將Bean都實例化并初始化好
基于XML方式的Bean的配置
XmI配置方式 | 功能描述 |
<bean id="class=""> | Bean的id和全限定名配置 |
<bean name=""> | 通過name設置Bean的別名,通過別名也能直接獲取到Bean實例 |
<bean scope=""> | Bean的作用范圍,BeanFactory作為容器時取值singleton和prototype |
<bean lazy-init=""> | Bean的實例化時機,是否延遲加載。BeanFactory作為容器時無效 |
<bean init-method=""> | Bean實例化后自動執行的初始化方法,method指定方法名 |
<bean destroy-method=""> | Bean實例銷毀前的方法,method指定方法名 |
<bean autowire="byType"> | 設置自動注入模式,常用的有按照類型byType,按照名字byName |
<bean factory-bean="" factory-method=""/> | 指定哪個工廠Bean的哪個方法完成Bean的創建 |
默認情況下,單純的Spring環境的Bean的作用范圍有兩個:Singleton與Prototype
- Singleton:單例,默認值,Spring容器創建的時候,就會進行Bean的實例化,并存儲到容器內部的單例池中,每次getBean時都是從單例池中獲取相同的Bean實例。
- Prototype:原型,Spring容器初始化時不會創建Bean實例,當調用getBean時才會實例化Bean,每次getBean都會創建一個新的Bean實例。
Spring實例化Bean的兩種方式如下:
一:通過構造方法實例化
默認在xml文件中配置的信息都是調用了無參構造器,但是如果我們需要參數時,需要添加constructor-arg標簽,該標簽標識向方法中傳遞參數。
<beans><bean id="userService" class="com.zmt.service.impl.UserServiceImpl"><!-- 默認采用無參構造器,但如果需要參數,則需要進行配置 --><constructor-arg name="參數名稱" value="參數值"></constructor-arg><property name="userDao" ref="userDao"></property></bean><bean id="userDao" class="com.zmt.dao.impl.UserDaoImpl"></bean>
</beans>
二:通過調用自定義的工廠方法對Bean進行實例化
靜態工廠方法實例化Bean
public class MyBeanFactory {public static UserDao getUserDao(){//在實例化Bean之前,我們可以進行一些業務邏輯操作return new UserDaoImpl();}
}
<beans><!--指定執行自定義的Bean工廠的指定方法去實例化Bean--><bean id="userDao1" class="com.zmt.factory.MyBeanFactory" factory-method="getUserDao"></bean><bean id="userService" class="com.zmt.service.impl.UserServiceImpl"><property name="userDao" ref="userDao"></property></bean><bean id="userDao" class="com.zmt.dao.impl.UserDaoImpl"></bean></beans>
可以看到執行結果,一個是通過無參構造器創建出來的Bean一個是通過自定義的靜態工廠創建的。
實例工廠方法實例化Bean
與靜態工廠方法實例化Bean區別在于,我們需要將工廠類也加載為Bean對象,然后通過該Bean對象去實例化
public class MyBeanFactory1 {public UserDao getUserDao(){//在實例化Bean之前,我們可以進行一些業務邏輯操作return new UserDaoImpl();}
}
<beans><!--加載工廠Bean--><bean id="myBeanFactory1" class="com.zmt.factory.MyBeanFactory1"></bean><!--通過工廠Bean去獲取需要的對象--><bean id="userDao2" factory-bean="myBeanFactory1" factory-method="getUserDao"></bean><!--指定執行自定義的Bean工廠的指定方法去實例化Bean--><bean id="userDao1" class="com.zmt.factory.MyBeanFactory" factory-method="getUserDao"></bean><bean id="userService" class="com.zmt.service.impl.UserServiceImpl"><property name="userDao" ref="userDao"></property></bean><bean id="userDao" class="com.zmt.dao.impl.UserDaoImpl"></bean>
</beans>
實現FactoryBean規范延遲實例化Bean
//需要指定FactoryBean的泛型
public class MyBeanFactory2 implements FactoryBean<UserDao> {//該方法在執行getBean的時候去執行@Overridepublic UserDao getObject() throws Exception {return new UserDaoImpl();}//獲取該Bean工廠產生的Bean類型@Overridepublic Class<?> getObjectType() {return UserDao.class;}
}
<beans><!--Bean名稱是userDao3,但加載的是工廠類--><bean id="userDao3" class="com.zmt.factory.MyBeanFactory2"></bean><!--加載工廠Bean--><bean id="myBeanFactory1" class="com.zmt.factory.MyBeanFactory1"></bean><!--通過工廠Bean去獲取需要的對象--><bean id="userDao2" factory-bean="myBeanFactory1" factory-method="getUserDao"></bean><!--指定執行自定義的Bean工廠的指定方法去實例化Bean--><bean id="userDao1" class="com.zmt.factory.MyBeanFactory" factory-method="getUserDao"></bean><bean id="userService" class="com.zmt.service.impl.UserServiceImpl"><property name="userDao" ref="userDao"></property></bean><bean id="userDao" class="com.zmt.dao.impl.UserDaoImpl"></bean></beans>
延遲加載Bean實際上是先加載了工廠Bean類,當需要用到Bean時,會從單例池中獲取FactoryBean后調用該對象中的getObject()方法獲取到真正的的Bean對象,并將該Bean對象緩存在factoryBeanObjectCache中,當使用到該Bean對象時從該Map中獲取。
自動裝配
我們通過編寫property標簽進行的注入叫做手動注入,而自動裝配是不需要編寫property標簽的,而是在bean標簽中使用autowire屬性來實現自動注入,aotuwire的值有兩個:byName、byType
- byName:通過屬性名自動裝配,去匹配setXxx與id="xxx"是否一致
- byType:通過Bean的類型從容器中匹配,匹配出多個相同Bean類型時,報錯
UserServiceImpl存在一個setUserDao方法,因此我們可以這么編寫,同樣可以將屬性注入到UserServiceImpl中
<beans><bean id="userService" class="com.zmt.service.impl.UserServiceImpl" autowire="byName"></bean><bean id="userDao" class="com.zmt.dao.impl.UserDaoImpl"></bean>
</beans>