Ioc-Spring核心接口
内容大纲
- 本章主要讲述Spring Ioc中几个比较重要的接口
- BeanFactory的含义及其使用
- BeanFactoryPostProcessor的作用以及使用
- BeanPostProcessor的作用以及使用
- BeanDefinitionReader的作用以及使用
- FactoryBean的作用以及使用
简介
我们一般配置Bean的方式有两种:1、使用Xml进行Bean的配置,2、使用@Component,@Bean等注解进行Bean的配置。
当然Spring为了处理这些不同的配置定义了一个接口(BeanDefinitionReader
)来统一将这些配置加载并生成BeanDefinition。
当BeanDefinition被加载后,我们出于某些因素需要修改BeanDefinition,Spring向我们提供了BeanFactoryPostProcessor
回调接口来修改BeanDefinition(在BeanDefinition被加载进BeanFactory时进行回调)。
接着实例化具体的Bean并放入到BeanFactory中,实例化后我们可能需要对实例进行一些包装,比如 AOP。Spring向我们提供了BeanPostProcessor回调接口来对Bean实例进行包装(在Bean实例被创建后进行回调)。
此时Ioc容器已经加载完毕了,但是上面的步骤都是在Bean实例化这个步骤前后进行操作,那我们怎么在操作实例化这个步骤呢?
Spring为提供了FactoryBean这个接口,让开发人员自己实现创建Bean实例的步骤。
坐标
Gradle 坐标
1 2 3 4 5 6 7
| testCompile 'junit:junit:4.13'
compile 'org.aspectj:aspectjweaver:1.9.5'
compile 'org.springframework:spring-beans:5.2.2.RELEASE' compile 'org.springframework:spring-aop:5.2.2.RELEASE' compile 'org.springframework:spring-context:5.2.2.RELEASE'
|
Maven坐标
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>5.2.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.2.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>5.2.2.RELEASE</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.5</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.5</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.13</version> <scope>test</scope> </dependency>
|
核心接口
Spring 框架中
BeanDefinitionReader
:读取XML或注解配置的Bean并生成BeanDefinition
BeanFactoryPostProcesser
:BeanFactory加载BeanDefinition后增强的扩展接口,可以新增/修改BeanDefinition
。
BeanPostProcesser
:BeanFactory实例化Bean后增强的扩展接口,可以包装Bean,例如AOP。
BeanFactory
:Spring Ioc的顶级接口,主要负责创建,实例化,管理Bean实例。
FactoryBean
:Spring提供给开发人员自定义实例化Bean的接口。
BeanFactory
概述
BeanFactory是访问Spring Bean容器的根接口。该接口由包含多个Bean定义的对象实现,每个定义均由String名称唯一标识。
它负责实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。
源代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| public interface BeanFactory {
String FACTORY_BEAN_PREFIX = "&";
Object getBean(String name) throws BeansException;
<T> T getBean(String name, Class<T> requiredType) throws BeansException;
Object getBean(String name, Object... args) throws BeansException;
<T> T getBean(Class<T> requiredType) throws BeansException;
<T> T getBean(Class<T> requiredType, Object... args) throws BeansException;
<T> ObjectProvider<T> getBeanProvider(Class<T> requiredType);
<T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType);
boolean containsBean(String name);
boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;
boolean isTypeMatch(String name, Class<?> typeToMatch) throws NoSuchBeanDefinitionException; Class<?> getType(String name) throws NoSuchBeanDefinitionException;
Class<?> getType(String name, boolean allowFactoryBeanInit) throws NoSuchBeanDefinitionException; String[] getAliases(String name); }
|
我们常用的方法就是重载的getBean()
。
Bean生命周期
初始生命周期
BeanNameAware:将Bean在容器中的名称
BeanClassLoaderAware:将加载Bean的类加载器提供给Bean的回调接口
BeanFactoryAware:将管理当前Bean的BeanFactory返回给Bean的回调接口
EnvironmentAware:返回当前Spring的环境变量的回调接口
EmbeddedValueResolverAware:
ResourceLoaderAware: 资源加载器的回调接口
ApplicationEventPublisherAware:应用事件发送器获取的回调接口
MessageSourceAware:MessageSource获取的回调接口
ApplicationContextAware:Application Context获取的回调接口
ServletContextAware:Servlet Context获取的
BeanPostProcessor.postProcessBeforeInitialization :在Bean初始化前执行
InitializingBean:由BeanFactory设置完所有属性后执行
自定义的初始化方法定义:@Bean(initMethod = "init",destroyMethod = "destroy")
BeanPostProcessor.postProcessAfterInitialization:在Bean初始化后执行
销毁生命周期
- DestructionAwareBeanPostProcessor.postProcessBeforeDestruction
- DisposableBean.destroy
- 自定义的销毁方法:
@Bean(initMethod = "init",destroyMethod = "destroy")
总结
初始化流程:
- 调用目标对象构造器创建对象
- 通过一系列Aware接口注入一些常用的属性
- 执行BeanPostProcessor.postProcessBeforeInitialization方法
- 执行InitializingBean.afterPropertiesSet方法
- 执行Bean自定义的初始化方法
- 执行BeanPostProcessor.postProcessAfterInitialization方法
销毁流程:
- 执行DestructionAwareBeanPostProcessors.postProcessBeforeDestruction方法
- 执行DisposableBean.destroy方法
- 执行Bean自定义的销毁方法
BeanFactoryPostBeanPostProcessor
概述
BeanFactoryPostBeanPostProcessor
是一个回调接口,可以在BeanDefinition被加载到BeanFactory后如果想再次对BeanDefinition进行修改就可以实现此接口。Spring会在加载完BeanDefinition后回调此接口。
注意:再此接口实现中不能与Bean实例进行交互。
源代码
1 2 3 4 5 6 7 8 9
| @FunctionalInterface public interface BeanFactoryPostProcessor {
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException; }
|
作用
BeanFactoryPostProcessor主要用于当BeanDefinition被加载到BeanFactory中后,对BeanDefinition进行修改。
示例代码
1 2 3 4 5 6 7 8 9
| @Configuration @ComponentScan(basePackages = "io.better.spring.ioc") public class IocConfiguration {
@Bean public IocBean iocBean() { return new IocBean(); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public class IocBean {
private String name;
public IocBean() { System.out.println("IocBean init"); } public void init() { System.out.println("IocBean custom init"); } public void destroy() { System.out.println("IocBean custom destroy"); } }
|
在IocConfiguration配置中我们并没有指定IocBean的初始化和销毁方法,以及懒加载
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| @Component public class IocBeanFactoryProcessor implements BeanFactoryPostProcessor {
@Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { System.out.println("BeanFactoryPostProcessor .....");
BeanDefinition iocBeanDefinition = beanFactory.getBeanDefinition("iocBean");
iocBeanDefinition.setInitMethodName("init"); iocBeanDefinition.setDestroyMethodName("destroy"); iocBeanDefinition.setLazyInit(true); } }
|
在BeanFactoryPostProcessor实现中我们为IocBean指定了初始化和销毁的方法,以及懒加载。
测试代码
1 2 3 4 5 6 7 8 9
| @Test public void testIocBeanFactoryPostProcessor() { AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(IocConfiguration.class);
IocBean bean = (IocBean) applicationContext.getBean("iocBean");
System.out.println(bean); applicationContext.close(); }
|
测试结果
1 2 3 4 5
| BeanFactoryPostProcessor ..... IocBean Constructor IocBean custom init io.better.spring.ioc.IocBean@9225652 IocBean custom destroy
|
从测试结果可以看出,我们在BeanFactoryPostProcessor中成功的操作了已经被BeanFactory加载的BeanDefinition并对其进行了修改。
到这里你可能会想既然能修改BeanDefinition,那能不能注册一个BeanDefinition呢?
要想往BeanFactory中注册一个BeanDefinition需要实现接口BeanDefinitionRegistryPostProcessor
。
该接口是BeanFactoryPostProcessor的子接口。
BeanDefinitionRegistryPostProcessor
源代码
1 2 3 4
| public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor { void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException; }
|
示例代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| @Component public class IocBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
@Override public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException { System.out.println("BeanDefinitionRegistryPostProcessor"); BeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(IocRegistryTestBean.class) .addPropertyValue("name", "registry post processor inject") .getBeanDefinition(); registry.registerBeanDefinition("iocRegistryTestBean", beanDefinition); }
@Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
BeanDefinition iocRegistryTestBean = beanFactory.getBeanDefinition("iocRegistryTestBean");
iocRegistryTestBean.setInitMethodName("init"); iocRegistryTestBean.setDestroyMethodName("destroy"); iocRegistryTestBean.setLazyInit(true); } }
|
1 2 3 4
| @Configuration @ComponentScan(basePackages = "io.better.spring.ioc") public class IocConfiguration { }
|
测试代码
1 2 3 4 5 6 7 8 9 10 11
| @Test public void testIocBeanFactoryPostProcessor() { AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(IocConfiguration.class);
IocRegistryTestBean iocRegistryTestBean = (IocRegistryTestBean) applicationContext.getBean("iocRegistryTestBean");
System.out.println(iocRegistryTestBean); applicationContext.close(); }
|
测试结果
1 2 3 4 5
| BeanDefinitionRegistryPostProcessor BeanFactoryPostProcessor ..... IocRegistryTestBean custom init IocRegistryTestBean{name='registry post processor inject'} IocRegistryTestBean custom destroy
|
从执行结果看出在BeanDefinitionRegistryPostProcessor
想BeanFactory中注册了一个IocRegistryTestBean实例,并指定了其初始化和销毁的方法以及懒加载。
BeanDefinitionRegistryPostProcessor
比BeanFactoryPostProcessor
先执行。
其他
ConfigurationClassPostProcessor作用
BeanDefinitionReader
概述
BeanDefinitionReader是一个接口,主要是读取XML或注解标识的类并将其转成BeanDefinition,提供了使用Resource
和String location
参数指定加载方法。
此接口是个规范接口,具体的BeanDefinitionReader无需实现此接口。BeanDefinition读取的简单接口。
源代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| public interface BeanDefinitionReader {
BeanDefinitionRegistry getRegistry();
@Nullable ResourceLoader getResourceLoader();
@Nullable ClassLoader getBeanClassLoader();
BeanNameGenerator getBeanNameGenerator(); int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException;
int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException;
int loadBeanDefinitions(String location) throws BeanDefinitionStoreException; int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException; }
|
实例代码
我们以XmlBeanDefinitionReader
为例
1 2 3 4 5 6 7 8 9
| <?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.xsd">
<bean name="iocBean" class="io.better.spring.ioc.IocBean" init-method="init" destroy-method="destroy"> <property name="name" value="test-xml"/> </bean> </beans>
|
1 2 3 4
| public GenericXmlApplicationContext(String... resourceLocations) { load(resourceLocations); refresh(); }
|
1 2 3
| public void load(String... resourceLocations) { this.reader.loadBeanDefinitions(resourceLocations); }
|
1
| private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);
|
可以看出GenericXmlApplicationContext
中持有了XmlBeanDefinitionReader
的引用,并在初始化时调用了XmlBeanDefinitionReader的loadBeanDefinitions方法加载了BeanDefinition。
测试代码
1 2 3 4 5 6
| @Test public void testIocBeanDefinitionReader() { GenericXmlApplicationContext applicationContext = new GenericXmlApplicationContext("Ioc.xml");
System.out.println(applicationContext.getBean("iocBean")); }
|
BeanPostProcessor
概述
BeanPostProcessor为一个接口,用于在BeanFactory实例化Bean后对Bean进行扩展需要实现的接口,Spring会在初始化每个Bean后会回调这个接口。
如果有多个BeanPostProcessor
实例,我们可以通过设置order
属性或实现Ordered
接口来控制执行顺序。
BeanPostProcessor接口由两个回调方法组成,即postprocessbeforeinitialize()
和postprocessafterinitialize()
。
我们可以对实例化的Bean进行包装或修改,例如Aop
(使用的是AbstractAdvisingBeanPostProcessor
类)就是一个很好的例子。
源代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public interface BeanPostProcessor {
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { return bean; }
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { return bean; } }
|
我们利用BeanPostProcessor来实现一个简单的Aop代理功能,示例代码如下:
示例代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
| @Component public class IocBeanPostProcessor implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { if (bean instanceof IocBean) { IocBean iocBean = (IocBean) bean; iocBean.setName("test-BeanPostProcessor"); System.out.println("IocBeanPostProcessor Before " + beanName); } return bean; }
@Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { if (bean instanceof IocBean) { System.out.println("IocBeanPostProcessor After " + beanName); IocBean iocBean = (IocBean) bean;
Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(IocBean.class); enhancer.setCallback(new CglibProxy(iocBean)); return enhancer.create(); } return bean; } }
class CglibProxy implements MethodInterceptor {
private Object proxyTarget;
public CglibProxy(Object proxyTarget) { this.proxyTarget = proxyTarget; }
@Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("BeanPostProcessor Cglib 代理执行前");
Object invoke = method.invoke(proxyTarget, objects);
System.out.println("BeanPostProcessor Cglib 代理执行后"); return invoke; } }
|
代码中在Before中为IocBean的Name属性进行了赋值,在After中为IocBean创建了代理对象。
测试代码
1 2 3 4 5 6 7
| @Test public void testIocBeanPostProcessor() { AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(IocConfiguration.class); IocBean bean = applicationContext.getBean(IocBean.class); bean.say(); }
|
当我们从Application Context获取的Bean实例是在BeanPostProcessor中创建的代理对象。
测试结果
1 2 3 4 5 6 7 8
| IocBean Constructor // 初始化bean IocBeanPostProcessor Before iocBean // 设置name属性 IocBeanPostProcessor After iocBean // 创建Cglib代理 IocBean Constructor // cglib代理类调用 // 执行Say方法 BeanPostProcessor Cglib 代理执行前 IocBean Say :test-BeanPostProcessor BeanPostProcessor Cglib 代理执行后
|
FactoryBean
概述
FactoryBean是一个接口,如果Bean实现此接口,则它将用作对象公开的工厂,而不是直接用作将自身公开的bean实例。
FactoryBeans可以支持单例和原型,并且可以按需延迟创建对象,也可以在启动时急于创建对象。
注意:实现此接口的Bean不能用作普通Bean。 FactoryBean以Bean样式定义(名称,别名和普通Bean一致),但是为Bean引用公开的对象始终是由Factory.getObject()
方法创建的对象。
作用
在Spring中我们注册实例化Bean的方式一般都是使用@Component,@Bean
等注解将Bean注册到容器中,整个过程对于开发人员来说是不可见的(除非阅读源码)。Spring为了更好的扩展提供了FactoryBean
这个接口让开发人员可以自定义Bean的实例化和注册过程。
实现了FactoryBean<T>
接口的Bean,Spring会向容器中注册两个Bean,一个是FactoryBean实例本身,一个是FactoryBean.getObject()
方法返回值所代表的Bean。
根据该Bean的ID从BeanFactory中获取的实际上是FactoryBean.getObject()
返回的对象,而不是FactoryBean本身,如果要获取FactoryBean对象,请在id前面加一个&
符号来获取(和BeanFactory中的静态变量FACTORY_BEAN_PREFIX
对应)。
源代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public interface FactoryBean<T> {
String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType"; T getObject() throws Exception;
Class<?> getObjectType(); default boolean isSingleton() { return true; } }
|
示例代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| public class IocBean implements FactoryBean<Object> {
private String name;
public IocBean() { System.out.println("IocBean init"); System.out.println(this); }
public void init() { System.out.println("IocBean custom init"); } public void destroy() { System.out.println("IocBean custom destroy"); }
@Override public Object getObject() throws Exception { System.out.println("FactoryBean Create IocBean Instance"); return new IocBean(); }
@Override public Class<?> getObjectType() { return IocBean.class; } }
|
测试代码
1 2 3 4 5 6 7 8 9 10 11 12
| @Test public void testIoc() { AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(IocConfiguration.class);
IocBean bean = (IocBean) applicationContext.getBean("iocBean"); IocBean factoryBean = (IocBean) applicationContext.getBean("&iocBean");
System.out.println(bean); System.out.println(factoryBean); applicationContext.close(); }
|
执行结果
1 2 3 4 5 6 7 8 9 10 11
| // 第一次初始化 IocBean init io.better.spring.ioc.IocBean@159f197 // BeanFactory.getObject()执行 FactoryBean Create IocBean Instance // 第二次初始化 IocBean init io.better.spring.ioc.IocBean@6fe7aac8 // sout输出内容 io.better.spring.ioc.IocBean@6fe7aac8 io.better.spring.ioc.IocBean@159f197
|
结论
从执行结果可以看出IocBean的实例对象是由FactoryBean.getObject()
方法创建的。
通过打印从容器获取FactoryBean实例
和构造器中打印语句
得出:IocBean类被实例化了两次
- 第一次实例化的是FactoryBean实例
- 第二次实例化的是IocBean实例(是通过FactoryBean.getObject方法创建的)