interface Burger { int getPrice(); } interface Drink { int getPrice(); } class ZingerBurger implements Burger { public int getPrice() { return 10; } } class PepsiCola implements Drink { public int getPrice() { return 5; } } /** * 香辣雞腿堡套餐 */ class ZingerBurgerCombo { private Burger burger = new ZingerBurger(); private Drink drink = new PepsiCola(); public int getPrice() { return burger.getPrice() + drink.getPrice(); } }
上述案例中咱們實現了一個香辣雞腿堡套餐,在ZingerBurgerCombo
中,咱們發現套餐與漢堡、套餐與飲品產生了直接的耦合。要知道肯德基中的套餐是很是多的,這樣須要創建大量不一樣套餐的類;並且若是該套餐中的百事可樂若是須要換成其餘飲品的話,是不容易改變的。java
class KFCCombo { private Burger burger; private Drink drink; public KFCCombo(Burger burger, Drink drink) { this.burger = burger; this.drink = drink; } } class KFCWaiter { public KFCCombo getZingerBurgerCombo() { return new KFCCombo(new ZingerBurger(), new PepsiCola()); } // else combo… }
爲了防止套餐和漢堡、飲品的耦合,咱們統一用KFCCombo
來表示全部的套餐組合,引入了一個新的類KFCWaiter
,讓她負責全部套餐的裝配。git
IoC的字面意思是控制反轉,它包括兩部分的內容:github
對於Spring來講,咱們經過Spring容器管理來管理和控制Bean的裝配。web
因爲IoC這個重要的概念比較晦澀隱諱,Martin Fowler提出了DI(Dependency Injection,依賴注入)的概念用以代替IoC,即讓調用類對某一接口實現類的依賴關係由第三方(容器或協做類)注入,以移除調用類對某一接口實現類的依賴。spring
Spring就是一個容器,它經過配置文件或註解描述類和類之間的依賴關係,自動完成類的初始化和依賴注入的工做。讓開發着能夠從這些底層實現類的實例化、依賴關係裝配等工做中解脫出來,專一於更有意義的業務邏輯開發。編程
從注入方法上看,IoC能夠分爲:構造函數注入、屬性注入、接口注入數組
class KFCCombo { private Burger burger; private Drink drink; // 在此注入對應的內容 public KFCCombo(Burger burger, Drink drink) { this.burger = burger; this.drink = drink; } }
class KFCCombo { private Burger burger; private Drink drink; // 在此注入對應的內容 public void setBurger(Burger burger) { this.burger = burger; } // 在此注入對應的內容 public void setDrink(Drink drink) { this.drink = drink; } }
interface InjectFood { void injectBurger(Burger burger); void injectDrink(Drink drink); } class KFCCombo implements InjectFood { private Burger burger; private Drink drink; // 在此注入對應的內容 public void injectBurger(Burger burger) { this.burger = burger; } // 在此注入對應的內容 public void injectDrink(Drink drink) { this.drink = drink; } }
接口注入和屬性注入並沒有本質的區別,並且還增長了一個額外的接口致使代碼增長,所以不推薦該方式。緩存
JDK提供的訪問資源的類(如java.net.URL、File等)並不能很好地知足各類底層資源的訪問需求,好比缺乏從類路徑或者Web容器上下文中獲取資源的操做類。所以,Spring提供了Resource
接口,並由此裝載各類資源,包括配置文件、國際化屬性文件等資源。服務器
FileSystemResource
和PathResource
。java.net.URL
,它使用戶可以訪問任何能夠經過URL表示的資源,如文件系統的資源、HTTP資源、FTP資源PathResource
封裝了java.net.URL
、java.nio.file.Path
、文件系統資源,它使用戶可以訪問任何能夠經過URL、Path、系統文件路徑標識的資源,如文件系統的資源、HTTP資源、FTP資源爲了訪問不一樣類型的資源,Resource接口下提供了不一樣的子類,這形成了使用上的不便。Spring提供了一個強大的加載資源的方式,在不顯示使用Resource實現類的狀況下,僅經過不一樣資源地址的特殊標示就能夠訪問對應的資源。架構
地址前綴 | 實例 | 釋義 |
---|---|---|
classpath: | classpath:com/ankeetc/spring/Main.class | 從類不經中加載資源,classpath: 和 classpath:/ 是等價的,都是相對於類的根路徑,資源文件能夠在標準的文件系統中,也能夠在jar或者zip的類包中 |
file: | file:/Users/zhengzhaoxi/.gitconfig | 使用UrlResource從文件系統目錄中裝載資源,能夠採用絕對路徑或者相對路徑 |
http:// | http://spiderlucas.github.io/... | 使用UrlResource從web服務器中加載資源 |
ftp:// | ftp://spiderlucas.github.io/atom.xml | 使用UrlResource從FTP服務器中裝載資源 |
沒有前綴 | com/ankeetc/spring/Main.class | 根據ApplicationContext的具體實現類採用對應類型的Resource |
假設有多個Jar包或者文件系統類路徑下擁有一個相同包名(如com.ankeetc):
這對於分模塊打包的應用很是有用,假設一個應用分爲2個模塊,每個模塊對應一個配置文件,分別爲module1.yaml 、module2.yaml,都放在了com.ankeetc的目錄下,每一個模塊單獨打成JAR包。可使用 classpath*:com/ankeetc/module*.xml
加載全部模塊的配置文件。
?
匹配文件名中的一個字符*
匹配文件名中的任意字符**
匹配多層路徑
ResourceLoader
接口僅有一個getResource(String loacation)方法,能夠根據一個資源地址加載文件資源。不過,資源地址僅支持帶資源類型前綴的表達式,不支持Ant風格的資源路徑表達式。ResourcePatternResolver
擴展ResourceLoader接口,定義了一個新的接口方法getResource(String locationPattern),改方法支持帶資源類型前綴及Ant風格的資源路徑表達式。PathMatchingResourcePatternResolver
是Spring提供的標準實現類。
getBean(String beanName)
,該方法從容器中返回特定名稱的Bean,BeanFactory的功能經過其餘接口而獲得不斷擴展。BeanFactory有多種實現,最經常使用的是 XmlBeanFactory,但在Spring 3.2時已被廢棄。目前建議使用XmlBeanDefinitionReader與DefaultListableBeanFactory。
<?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-4.0.xsd"> <bean id="car" class="com.ankeetc.spring.Car"></bean> </beans>
public static void main(String[] args) throws Exception { ResourceLoader resourceLoader = new DefaultResourceLoader(); Resource resource = resourceLoader.getResource("beans.xml"); DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory); reader.loadBeanDefinitions(resource); beanFactory.getBean(""); }
InstantiationAwareBeanPostProcessor
接口,則在實例化Bean以前,調用postProcessBeforeInstantiation()方法。InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation()
。InstantiationAwareBeanPostProcessor#postProcessPropertyValues()
方法。BeanNameAware
接口,則將調用BeanNameAware#setBeanName()
接口方法,將配置文件中該Bean對應的名稱設置到Bean中。BeanFactoryAware
接口,將調用BeanFactoryAware#setBeanFactory()
接口方法。BeanPostProcessor
接口,將調用BeanPostProcessor#postProcessBeforeInitialization()
方法。入參Bean是當前正在處理的Bean,BeanName是當前Bean的配置名,返回的對象爲處理後的Bean。BeanPostProcessor在Spring框架中佔有重要的地位,爲容器提供對Bean進行後續加工處理的切入點,AOP、動態代理都經過BeanPostProcessor來實現。InitializingBean
接口,則將調用InitializingBean#afterPropertiesSet()
方法。BeanPostProcessor#postProcessAfterInitialization()
方法再次加工Bean。scope='singleton'
的Bean,當容器關閉時,將觸發Spring對Bean的後續生命週期的管理工做。若是Bean實現了DisposableBean
接口,將調用DisposableBean#destroy()
方法。Ordered
接口,容器將按照特定的順序依此調用這些後處理器。public class Main { public static void main(String[] args) { Resource resource = new PathMatchingResourcePatternResolver().getResource("classpath:beans.xml"); DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory); reader.loadBeanDefinitions(resource); beanFactory.addBeanPostProcessor(new InstantiationAwareBeanPostProcessor() { public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException { System.out.println("InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation()"); return null; } public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException { System.out.println("InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation()"); return true; } public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException { System.out.println("InstantiationAwareBeanPostProcessor.postProcessPropertyValues()"); return pvs; } public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { System.out.println("BeanPostProcessor.postProcessBeforeInitialization()"); return bean; } public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { System.out.println("BeanPostProcessor.postProcessAfterInitialization()"); return bean; } }); MyBean myBean = beanFactory.getBean("myBean", MyBean.class); beanFactory.destroySingletons(); } } class MyBean implements BeanNameAware, BeanFactoryAware, InitializingBean, DisposableBean { private String prop; public MyBean() { System.out.println("MyBean:構造方法"); } public String getProp() { System.out.println("MyBean:get方法"); return prop; } public void setProp(String prop) { System.out.println("MyBean:set方法"); this.prop = prop; } public void setBeanFactory(BeanFactory beanFactory) throws BeansException { System.out.println("MyBean:BeanFactoryAware.setBeanFactory()"); } public void setBeanName(String name) { System.out.println("MyBean:BeanNameAware.setBeanName()"); } public void destroy() throws Exception { System.out.println("MyBean:DisposableBean.destroy()"); } public void afterPropertiesSet() throws Exception { System.out.println("MyBean:InitializingBean.afterPropertiesSet()"); } // 配置文件中init-method public void myInit() { System.out.println("MyBean:myInit()"); } // 配置文件中destroy-method public void myDestroy() { System.out.println("MyBean:myDestroy()"); } }
<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-4.0.xsd"> <bean class="com.ankeetc.spring.MyBean" name="myBean" init-method="myInit" destroy-method="myDestroy"> <property name="prop" value="prop"/> </bean> </beans>
init-method
和destroy-method
屬性配置方式爲Bean指定初始化和銷燬的方法,採用這種方式對Bean生命週期的控制效果和經過實現InitializingBean
、DisposableBean
接口所達到的效果是徹底相同的,並且達到了框架解耦的目的。
public static void main(String[] args) throws Exception { ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("beans.xml"); FileSystemXmlApplicationContext fileSystemXmlApplicationContext = new FileSystemXmlApplicationContext("file:/Users/zhengzhaoxi/Git/spring/src/main/resources/beans.xml"); AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(Config.class); }
見後續章節
Bean在ApplicationContext和BeanFactory中生命週期相似,但有如下不一樣點
ApplicationContextAware
接口,則會增長一個調用該接口方法的ApplicationContextAware.setApplicationContext
的方法。BeanFactoryPostProcessor
的實現類,則應用上下文在裝在配置文件以後、初始化Bean實例以前會調用這些BeanFactoryPostProcessor對配置信息進行加工處理。Spring提供了多個工廠容器,如CustomEditorConfigure
、PropertyPlaceholderConfigurer
等。工廠後處理器是容器級的,只在應用上下文初始化時調用一次,其目的是完成一些配置文件加工處理工做。BeanPostProcessor
、InstantiationAwareBeanPostProcessor
、BeanFactoryPostProcessor
,並自動將它們註冊到應用上下文中(以下所示);而BeanFactory須要經過手工調用addBeanPostProcessor()
方法註冊。<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-4.0.xsd"> <bean class="com.ankeetc.spring.MyBean" name="myBean" init-method="myInit" destroy-method="myDestroy"> <property name="prop" value="prop"/> </bean> <!-- 工廠後處理器 --> <bean id="myBeanPostProcessor" class="com.ankeetc.spring.MyBeanPostProcessor"/> <!-- 註冊Bean後處理器 --> <bean id="myBeanFactoryPostProcessor" class="com.ankeetc.spring.MyBeanFactoryPostProcessor"/> </beans>
com.springframework.beans.factory.BeanFactory
)是Spring框架中最核心的接口,它提供了高級 IoC 的配置機制 。BeanFactory使管理不一樣類型的Java對象成爲可能。BeanFactory是Spring框架的基礎設施,面向Spring自己。com.springframework.context.ApplicationContext
)創建在BeanFactory基礎之上,提供了更多面向應用的功能,它提供了國際化支持和框架事件體系,更易於建立實際應用 。 ApplicationContext 面向使用 Spring 框架的開發者,幾乎全部的應用場合均可以直接使用 ApplicationContext。BeanPostProcessor
、InstantiationAwareBeanPostProcessor
、BeanFactoryPostProcessor
,並自動將它們註冊到應用上下文中;而BeanFactory須要經過手工調用addBeanPostProcessor()
方法註冊。HierarchicalBeanFactory
接口,Spring的IoC容器能夠創建父子層級關聯的容器體系,子容器能夠訪問父容器中的 Bean,但父容器不能訪問子容器的Bean。