文章部分图片来自参考资料,本文介绍的是 Spring 的两个重要概念,是学习总结。 html
咱们依旧提出几个问题,帮助咱们在学习中带着问题解答。 java
问题 : spring
他们的关系以下图所示。api
上图咱们能够得出 : app
控制反转是目的,而依赖注入是实现控制反转的手段。框架
理解这一点很重要。要始终记得控制反转这个思路是咱们要追求的目的。ide
用通俗的语言来解释控制反转能够参考下面几篇文章 : 学习
经过前面四篇文章的阅读能够了解到控制反转的概念和能够解决到的问题, 咱们下面再来总结一下几个知识点 。ui
IoC 主要的做用就是解耦各个组件,让高层模块不依赖底层模块,而是让二者依赖接口和抽象来实现。this
ioc的思想最核心的地方在于,资源不禁使用资源的双方管理,而由不使用资源的第三方管理,这能够带来不少好处。
1. 资源集中管理,实现资源的可配置和易管理。
2. 下降了使用资源双方的依赖程度,也就是咱们说的耦合度
而IoC Container (控制反转容器)是经过维护一个configuration 文件初始化Bean对象的容器,它的好处 :
依赖注入的主要做用是配置和管理咱们的应用对象,依赖注入的方式有 :
bean 在Ioc Container 中,那么容器中如何注入和管理的又是谁?咱们又是如何从容器中获取出来bean的呢?容器的管理者正是 BeanFactory ,而获取管理的bean天然须要一个上下文对象 : ApplicationContext
下面将会介绍BeanFactory和ApplicationContext这二者的知识点,并介绍了 FactoryBean
BeanFactory 和 ApplicationContext 二者都是接口,前者提供了一个高级的机制去管理任何类型的对象(bean);后者是 BeanFactory的子接口,它增长多了如下功能 :
• 更轻松地与Spring的AOP功能集成
• 消息资源处理(用于国际化)
• 事件发布
• 特定于应用程序层次的上下文,例如WebApplicationContext,用于Web应用程序
下面这一段这是关于 BeanFactory的介绍。
The
BeanFactory
API provides the underlying basis for Spring’s IoC functionality. Its specific contracts are mostly used in integration with other parts of Spring and related third-party frameworks, and itsDefaultListableBeanFactory
implementation is a key delegate within the higher-levelGenericApplicationContext
container.
BeanFactory
and related interfaces (such asBeanFactoryAware
,InitializingBean
,DisposableBean
) are important integration points for other framework components. By not requiring any annotations or even reflection, they allow for very efficient interaction between the container and its components.
总而言之,BeanFactory 提供了配置框架和基础的功能,而 ApplicationContext 添加了更多与企业级别相关的功能,ApplicationContext 是BeanFactory 的全子集,提供了不少 BeanFactory 所不及的功能。下图列举了这两种接口能够完成的功能对比 :
Spring自带了多种类型的应用上下文。 下面罗列的几个是你最有可能遇到的。
这些都是 ApplicationContext 的子类,这些子类在不一样场景发挥着做用。(从名字咱们就能够判断在哪些场景了)
FactoryBean 是个接口,它的做用是返回一些真实须要的bean,便是说某些bean并不能一步到位能够注入到Container ,须要通过特殊的构造,它的常见的子类实现是 : ProxyFactoryBean 和 JndiRmiProxyFactoryBean 。 从它的子类,咱们就能够知道FactoryBean 对于一些有特定要求的Bean 解决这一痛点发挥着做用。
public interface FactoryBean<T> { @Nullable T getObject() throws Exception; @Nullable Class<?> getObjectType(); default boolean isSingleton() { return true; } }
从上面的解释中好难理解 FactoryBean 真实的做用是什么(开始看到这个东西的时候)。推荐阅读这两篇资料 : fb_doc 和 what's the fb ,资料讲到的 FactoryBean 的做用 :
A
FactoryBean
is a pattern to encapsulate interesting object construction logic in a class. It might be used, for example, to encode the construction of a complex object graph in a reusable way. Often this is used to construct complex objects that have many dependencies. It might also be used when the construction logic itself is highly volatile and depends on the configuration. AFactoryBean
is also useful to help Spring construct objects that it couldn’t easily construct itself. For example, in order to inject a reference to a bean that was obtained from JNDI, the reference must first be obtained. You can use theJndiFactoryBean
to obtain this reference in a consistent way. You may inject the result of aFactoryBean
’sgetObject()
method into any other property.
第二篇文章用到一个示例代码,以下 :
public class Person { private Car car ; private void setCar(Car car){ this.car = car; } } public class MyCarFactoryBean implements FactoryBean<Car>{ private String make; private int year ; public void setMake(String m){ this.make =m ; } public void setYear(int y){ this.year = y; } public Car getObject(){ // wouldn't be a very useful FactoryBean // if we could simply instantiate the object! CarBuilder cb = CarBuilder.car(); if(year!=0) cb.setYear(this.year); if(StringUtils.hasText(this.make)) cb.setMake( this.make ); return cb.factory(); } public Class<Car> getObjectType() { return Car.class ; } public boolean isSingleton() { return false; } } <bean class = "a.b.c.MyCarFactoryBean" id = "car"> <property name = "make" value ="Honda"/> <property name = "year" value ="1984"/> </bean> <bean class = "a.b.c.Person" id = "josh"> <property name = "car" ref = "car"/> </bean> //或是 javaConfig 的形式 // identical configuration in Java to the XML above @Configuration public class CarConfiguration { @Bean public MyCarFactoryBean carFactoryBean(){ MyCarFactoryBean cfb = new MyCarFactoryBean(); cfb.setMake("Honda"); cfb.setYear(1984); return cfb; } @Bean public Person aPerson(){ Person person = new Person(); person.setCar( carFactoryBean().getObject()); return person; } }
上面的示例能够看到,返回的bean 对象并非 FactoryBean ,而是通过“封装”事后的对象,这正是FactoryBean 的做用。
FactoryBean 和其余Spring Bean 同样也是享有一样的 lifecycle hooks 和 services(like AOP) ,因此当你想要在设置属性以前,让spring container 返回一个回调给你也是行的,只要继承 InitializingBean 接口。详细地见下面引用,来自第二篇推荐文章 :
Spring
FactoryBean
s have all the other characteristics of any other Spring bean, including the lifecycle hooks and services (like AOP) that all beans in the Spring container enjoy.So, if you’d like a chance to perform construction logic after the properties on the
FactoryBean
have been set, but before thegetObject()
method has been called, then you can tell the Spring container give yourFactoryBean
a callback. One way to do this is to implement theInitializingBean
interface. This will be called no matter what. A far more POJO-centric alternative is to annotate a method with@PostConstruct
. This method will be called, in this case, after both the code>make and theyear
properties have been set. You might use this callback to do sanity checks before the object construction’s finished, but after the configuration by the container has finished.
@PostConstruct public void setup() throws Throwable { // these methods throw an exception that // will arrest construction if the assertions aren't met Assert.notNull(this.make, "the 'make' must not be null") ; Assert.isTrue(this.year > 0, "the 'year' must be a valid value"); }