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。