Spring 扩展点概览及实践
学习 Spring 代码,最重要的是掌握 Spring 有哪些扩展点,可以利用这些扩展点对 Spring 做什么扩展操作。说得更具体一点,如果自己开发一个框架,如何与 Spring 进行整合,如果对 Spring 的扩展点有一个比较清晰的认识,势必会事半功倍。
@Import
先来看一下 @Import
注解的定义:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Import {
/**
* {@link Configuration @Configuration}, {@link ImportSelector},
* {@link ImportBeanDefinitionRegistrar}, or regular component classes to import.
*/
Class<?>[] value();
}
从声明可以看出,使用时,只需要指定 Class
实例即可;从方法的文档中可以看出,Class
实例可以分为三种:ImportSelector
、ImportBeanDefinitionRegistrar
和常规组件类。示例如下:
@Configuration
@Import(LogImportSelector.class)
public static class Config {
}
在 org.springframework.context.annotation.ConfigurationClassParser#processImports
方法中,集中了对 @Import
注解的处理。从代码可以非常清晰地看出,分了三种情况进行处理:
ImportSelector
ImportBeanDefinitionRegistrar
常规组件
Class
下面分别对其进行介绍。
ImportSelector
先来看一下 ImportSelector
接口的定义:
/**
* Interface to be implemented by types that determine which @{@link Configuration}
* class(es) should be imported based on a given selection criteria, usually one or
* more annotation attributes.
*
* <p>{@code ImportSelector} implementations are usually processed in the same way
* as regular {@code @Import} annotations, however, it is also possible to defer
* selection of imports until all {@code @Configuration} classes have been processed
* (see {@link DeferredImportSelector} for details).
*
* @since 3.1
* @see DeferredImportSelector
* @see Import
* @see ImportBeanDefinitionRegistrar
* @see Configuration
*/
public interface ImportSelector {
/**
* Select and return the names of which class(es) should be imported based on
* the {@link AnnotationMetadata} of the importing @{@link Configuration} class.
* @return the class names, or an empty array if none
*/
String[] selectImports(AnnotationMetadata importingClassMetadata);
/**
* Return a predicate for excluding classes from the import candidates, to be
* transitively applied to all classes found through this selector's imports.
* <p>If this predicate returns {@code true} for a given fully-qualified
* class name, said class will not be considered as an imported configuration
* class, bypassing class file loading as well as metadata introspection.
* @return the filter predicate for fully-qualified candidate class names
* of transitively imported configuration classes, or {@code null} if none
* @since 5.2.4
*/
@Nullable
default Predicate<String> getExclusionFilter() {
return null;
}
}
从接口文档中就可以看出,使用 String[] selectImports(AnnotationMetadata importingClassMetadata)
方法,返回所需要引入的类全限定名即可。实例如下:
public class LogImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{
UserDao.class.getName(),
UserService.class.getName(),
ProtoService.class.getName()
};
}
}
ImportBeanDefinitionRegistrar
先来看一下 ImportBeanDefinitionRegistrar
接口的定义:
/**
* Interface to be implemented by types that register additional bean definitions when
* processing @{@link Configuration} classes. Useful when operating at the bean definition
* level (as opposed to {@code @Bean} method/instance level) is desired or necessary.
*
* <p>Along with {@code @Configuration} and {@link ImportSelector}, classes of this type
* may be provided to the @{@link Import} annotation (or may also be returned from an
* {@code ImportSelector}).
*
* <p>See implementations and associated unit tests for usage examples.
*
* @since 3.1
* @see Import
* @see ImportSelector
* @see Configuration
*/
public interface ImportBeanDefinitionRegistrar {
/**
* Register bean definitions as necessary based on the given annotation metadata of
* the importing {@code @Configuration} class.
* <p>Note that {@link BeanDefinitionRegistryPostProcessor} types may <em>not</em> be
* registered here, due to lifecycle constraints related to {@code @Configuration}
* class processing.
* <p>The default implementation delegates to
* {@link #registerBeanDefinitions(AnnotationMetadata, BeanDefinitionRegistry)}.
* @param importingClassMetadata annotation metadata of the importing class
* @param registry current bean definition registry
* @param importBeanNameGenerator the bean name generator strategy for imported beans:
* {@link ConfigurationClassPostProcessor#IMPORT_BEAN_NAME_GENERATOR} by default, or a
* user-provided one if {@link ConfigurationClassPostProcessor#setBeanNameGenerator}
* has been set. In the latter case, the passed-in strategy will be the same used for
* component scanning in the containing application context (otherwise, the default
* component-scan naming strategy is {@link AnnotationBeanNameGenerator#INSTANCE}).
* @since 5.2
* @see ConfigurationClassPostProcessor#IMPORT_BEAN_NAME_GENERATOR
* @see ConfigurationClassPostProcessor#setBeanNameGenerator
*/
default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry,
BeanNameGenerator importBeanNameGenerator) {
registerBeanDefinitions(importingClassMetadata, registry);
}
/**
* Register bean definitions as necessary based on the given annotation metadata of
* the importing {@code @Configuration} class.
* <p>Note that {@link BeanDefinitionRegistryPostProcessor} types may <em>not</em> be
* registered here, due to lifecycle constraints related to {@code @Configuration}
* class processing.
* <p>The default implementation is empty.
* @param importingClassMetadata annotation metadata of the importing class
* @param registry current bean definition registry
*/
default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
}
}
这里使用到了 BeanDefinitionRegistry
接口,来看一下这个接口的定义:
/**
* Interface for registries that hold bean definitions, for example RootBeanDefinition
* and ChildBeanDefinition instances. Typically implemented by BeanFactories that
* internally work with the AbstractBeanDefinition hierarchy.
*
* <p>This is the only interface in Spring's bean factory packages that encapsulates
* <i>registration</i> of bean definitions. The standard BeanFactory interfaces
* only cover access to a <i>fully configured factory instance</i>.
*
* <p>Spring's bean definition readers expect to work on an implementation of this
* interface. Known implementors within the Spring core are DefaultListableBeanFactory
* and GenericApplicationContext.
*
* @author Juergen Hoeller
* @since 26.11.2003
* @see org.springframework.beans.factory.config.BeanDefinition
* @see AbstractBeanDefinition
* @see RootBeanDefinition
* @see ChildBeanDefinition
* @see DefaultListableBeanFactory
* @see org.springframework.context.support.GenericApplicationContext
* @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader
* @see PropertiesBeanDefinitionReader
*/
public interface BeanDefinitionRegistry extends AliasRegistry {
/**
* Register a new bean definition with this registry.
* Must support RootBeanDefinition and ChildBeanDefinition.
* @param beanName the name of the bean instance to register
* @param beanDefinition definition of the bean instance to register
* @throws BeanDefinitionStoreException if the BeanDefinition is invalid
* @throws BeanDefinitionOverrideException if there is already a BeanDefinition
* for the specified bean name and we are not allowed to override it
* @see GenericBeanDefinition
* @see RootBeanDefinition
* @see ChildBeanDefinition
*/
void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException;
/**
* Remove the BeanDefinition for the given name.
* @param beanName the name of the bean instance to register
* @throws NoSuchBeanDefinitionException if there is no such bean definition
*/
void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
/**
* Return the BeanDefinition for the given bean name.
* @param beanName name of the bean to find a definition for
* @return the BeanDefinition for the given name (never {@code null})
* @throws NoSuchBeanDefinitionException if there is no such bean definition
*/
BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
/**
* Check if this registry contains a bean definition with the given name.
* @param beanName the name of the bean to look for
* @return if this registry contains a bean definition with the given name
*/
boolean containsBeanDefinition(String beanName);
/**
* Return the names of all beans defined in this registry.
* @return the names of all beans defined in this registry,
* or an empty array if none defined
*/
String[] getBeanDefinitionNames();
/**
* Return the number of beans defined in the registry.
* @return the number of beans defined in the registry
*/
int getBeanDefinitionCount();
/**
* Determine whether the given bean name is already in use within this registry,
* i.e. whether there is a local bean or alias registered under this name.
* @param beanName the name to check
* @return whether the given bean name is already in use
*/
boolean isBeanNameInUse(String beanName);
}
很明显,可以通过 registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
方法,向容器在中注入所需要的 BeanDefinition
,而 BeanDefinition
是常见的 Bean 实例的基石。示例如下:
public class LogImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
BeanDefinitionRegistry registry) {
RootBeanDefinition definition = new RootBeanDefinition(UserService.class);
registry.registerBeanDefinition(UserService.class.getName(), definition);
}
}
常规组件 Class
这是最简单的情况,直接举例:
@Configuration
@Import(UserService.class)
public static class Config {
}
BeanDefinitionRegistryPostProcessor
先来看一下 BeanDefinitionRegistryPostProcessor
的定义:
/**
* Extension to the standard {@link BeanFactoryPostProcessor} SPI, allowing for
* the registration of further bean definitions <i>before</i> regular
* BeanFactoryPostProcessor detection kicks in. In particular,
* BeanDefinitionRegistryPostProcessor may register further bean definitions
* which in turn define BeanFactoryPostProcessor instances.
*
* @author Juergen Hoeller
* @since 3.0.1
* @see org.springframework.context.annotation.ConfigurationClassPostProcessor
*/
public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {
/**
* Modify the application context's internal bean definition registry after its
* standard initialization. All regular bean definitions will have been loaded,
* but no beans will have been instantiated yet. This allows for adding further
* bean definitions before the next post-processing phase kicks in.
* @param registry the bean definition registry used by the application context
* @throws org.springframework.beans.BeansException in case of errors
*/
void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;
}
这个接口扩展了标准的 BeanFactoryPostProcessor
接口,允许在普通的 BeanFactoryPostProcessor
接口实现类执行之前注册更多的 BeanDefinition
。特别地是,BeanDefinitionRegistryPostProcessor
可以注册 BeanFactoryPostProcessor
的 BeanDefinition
。
postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry)
方法可以修改在 BeanDefinitionRegistry
接口实现类中注册的任意 BeanDefinition
,也可以增加和删除 BeanDefinition
。原因是这个方法执行前,所有常规的 BeanDefinition
已经被加载到 BeanDefinitionRegistry
接口实现类中,但还没有bean被实例化。
实例如下:
public class LogBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
System.out.println(getAndIncrement()
+ "LogBeanDefinitionRegistryPostProcessor.postProcessBeanDefinitionRegistry\n");
RootBeanDefinition beanDefinition = new RootBeanDefinition(LogBeanFactoryPostProcessor.class);
registry.registerBeanDefinition(beanDefinition.getBeanClassName(), beanDefinition);
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println(getAndIncrement()
+ "LogBeanDefinitionRegistryPostProcessor.postProcessBeanFactory\n");
}
}
BeanDefinitionRegistryPostProcessor
在 Spring 内部的使用,最重要的示例就是 ConfigurationClassPostProcessor
,这个类负责解析 @Import
和 @Configuration
等注解。感兴趣可以认真研究一下这个类的代码。
BeanFactoryPostProcessor
BeanFactory
生成后,如果想对 BeanFactory
进行一些处理,该怎么办呢?BeanFactoryPostProcessor
接口就是用来处理 BeanFactory
的。
先来看一下接口定义:
/**
* Factory hook that allows for custom modification of an application context's
* bean definitions, adapting the bean property values of the context's underlying
* bean factory.
*
* <p>Useful for custom config files targeted at system administrators that
* override bean properties configured in the application context. See
* {@link PropertyResourceConfigurer} and its concrete implementations for
* out-of-the-box solutions that address such configuration needs.
*
* <p>A {@code BeanFactoryPostProcessor} may interact with and modify bean
* definitions, but never bean instances. Doing so may cause premature bean
* instantiation, violating the container and causing unintended side-effects.
* If bean instance interaction is required, consider implementing
* {@link BeanPostProcessor} instead.
*
* <h3>Registration</h3>
* <p>An {@code ApplicationContext} auto-detects {@code BeanFactoryPostProcessor}
* beans in its bean definitions and applies them before any other beans get created.
* A {@code BeanFactoryPostProcessor} may also be registered programmatically
* with a {@code ConfigurableApplicationContext}.
*
* <h3>Ordering</h3>
* <p>{@code BeanFactoryPostProcessor} beans that are autodetected in an
* {@code ApplicationContext} will be ordered according to
* {@link org.springframework.core.PriorityOrdered} and
* {@link org.springframework.core.Ordered} semantics. In contrast,
* {@code BeanFactoryPostProcessor} beans that are registered programmatically
* with a {@code ConfigurableApplicationContext} will be applied in the order of
* registration; any ordering semantics expressed through implementing the
* {@code PriorityOrdered} or {@code Ordered} interface will be ignored for
* programmatically registered post-processors. Furthermore, the
* {@link org.springframework.core.annotation.Order @Order} annotation is not
* taken into account for {@code BeanFactoryPostProcessor} beans.
*
* @author Juergen Hoeller
* @author Sam Brannen
* @since 06.07.2003
* @see BeanPostProcessor
* @see PropertyResourceConfigurer
*/
@FunctionalInterface
public interface BeanFactoryPostProcessor {
/**
* Modify the application context's internal bean factory after its standard
* initialization. All bean definitions will have been loaded, but no beans
* will have been instantiated yet. This allows for overriding or adding
* properties even to eager-initializing beans.
* @param beanFactory the bean factory used by the application context
* @throws org.springframework.beans.BeansException in case of errors
*/
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}
若 IoC 容器内添加了实现了 BeanFactoryPostProcessor
接口的实现类 Bean,那么在该容器中实例化任何其他 Bean 之前可以回调该 Bean 中的 postPrcessorBeanFactory()
方法来对 Bean 的配置元数据进行更改,比如设置 init-method
,或者将 Scope
从 SINGLETON
改为 PROTOTYPE
。示例如下:
public class LogBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println(getAndIncrement()
+ "LogBeanFactoryPostProcessor.postProcessBeanFactory\n");
System.out.println(Arrays.toString(beanFactory.getBeanDefinitionNames()).replaceAll(",", ",\n"));
BeanDefinition definition = beanFactory.getBeanDefinition(UserService.class.getName());
// 设置 init 方法
definition.setInitMethodName("init");
}
}
在代码 org.springframework.context.support.AbstractApplicationContext#invokeBeanFactoryPostProcessors
中,集中了对 BeanFactoryPostProcessor
的调用。该方法把处理过程,委托给了 org.springframework.context.support.PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory, java.util.List<BeanFactoryPostProcessor>)
方法来处理。根据代码可以整理出处理流程如下:
如果
beanFactory
是一个BeanDefinitionRegistry
实例,则:首先处理参数传过来的
List<BeanFactoryPostProcessor> beanFactoryPostProcessors
对象如果
postProcessor
是BeanDefinitionRegistryPostProcessor
实现类,则直接调用postProcessBeanDefinitionRegistry
,然后加入到List<BeanDefinitionRegistryPostProcessor> registryProcessors
列表中;如果不是,则加入到
List<BeanFactoryPostProcessor> regularPostProcessors
列表中;
从
BeanFactory
中通过beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false)
方法获取BeanDefinitionRegistryPostProcessor
名称列表。筛选出实现了PriorityOrdered
接口的实例,然后排序再逐一调用postProcessBeanDefinitionRegistry
方法。最后,加入到List<BeanDefinitionRegistryPostProcessor> registryProcessors
列表中。从
BeanFactory
中通过beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false)
方法获取BeanDefinitionRegistryPostProcessor
名称列表。筛选出实现了Ordered
接口的实例,然后排序再逐一调用postProcessBeanDefinitionRegistry
方法。最后,加入到List<BeanDefinitionRegistryPostProcessor> registryProcessors
列表中。(注意:上一步已经调用过的则不再重复调用。)从
BeanFactory
中通过beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false)
方法获取BeanDefinitionRegistryPostProcessor
名称列表。剔除掉前两步调用过的类,排序再逐一调用postProcessBeanDefinitionRegistry
方法。最后,加入到List<BeanDefinitionRegistryPostProcessor> registryProcessors
列表中。要强调的一点是:这里是通过一个循环来反复执行这一步,D瓜哥认为是在调用postProcessBeanDefinitionRegistry
方法中,有会参数新注册的BeanDefinitionRegistryPostProcessor
,所以需要反复调用。大家如果有不同见解,也欢迎留言讨论。调用
BeanDefinitionRegistryPostProcessor
对象的postProcessBeanFactory
方法;调用
BeanFactoryPostProcessor
对象的postProcessBeanFactory
方法;
如果
beanFactory
不是BeanDefinitionRegistry
实例,则直接调用BeanFactoryPostProcessor
对象的postProcessBeanFactory
方法;从
BeanFactory
中通过beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false)
方法获取BeanFactoryPostProcessor
名称列表。将其分为:实现
PriorityOrdered
接口的实例实现
Ordered
接口的实例未排序的实例
按照这个顺序,排除已经处理过的实例,再分类,然后排序再跟着这个顺序依次逐一调用
BeanFactoryPostProcessor
对象的postProcessBeanFactory
方法;
最后,向
BeanFactory
注册ApplicationListenerDetector
实例。
InstantiationAwareBeanPostProcessor
注意区分 Instantiation
和 Initialization
。
Instantiation
— 实例化,在实例化之前还没有生成对象。Initialization
— 初始化,对象已经生成,需要对其做进一步的处理,比如赋值等。
FactoryBean
在对象生成上,有时也许需要做些特殊处理。比如,创建对象过程比较繁琐,希望可以通过实现 FactoryBean
来封装初始化过程。
在 Spring 官方文档 Core Technologies: Customizing Instantiation Logic with a FactoryBean
也有进一步的说明。
目前,Spring 源码中,FactoryBean
的实现类就有五十多个,随便举几个栗子🌰:
org.springframework.http.converter.json.GsonFactoryBean
org.springframework.cache.jcache.JCacheManagerFactoryBean
org.springframework.aop.framework.ProxyFactoryBean
示例如下:
package com.diguage.truman.context;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.context.annotation.*;
import java.util.Arrays;
/**
* FactoryBean 测试
*
* @author D瓜哥, https://www.diguage.com/
* @since 2020-05-26 16:34
*/
public class FactoryBeanTest {
@Test
public void test() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(Config.class);
context.refresh();
UserService userService = context.getBean(UserService.class);
System.out.println(userService.getById(119L));
System.out.println("-↓----");
System.out.println("&userServiceFactoryBean = " (1)
+ context.getBean("&userServiceFactoryBean"));
System.out.println(" userServiceFactoryBean = " (2)
+ context.getBean("userServiceFactoryBean"));
System.out.println("-↑----");
UserServiceFactoryBean factoryBean = context.getBean(UserServiceFactoryBean.class);
System.out.println(factoryBean);
System.out.println(Arrays.toString(context.getBeanDefinitionNames())
.replaceAll(",", ",\n"));
}
@Configuration
public static class Config {
@Bean
public UserServiceFactoryBean userServiceFactoryBean() {
return new UserServiceFactoryBean();
}
}
public static class UserService {
public String getById(Long id) {
return "Name-" + id;
}
}
public static class UserServiceFactoryBean implements FactoryBean<UserService> {
@Override
public UserService getObject() throws Exception {
return new UserService();
}
@Override
public Class<?> getObjectType() {
return UserService.class;
}
@Override
public boolean isSingleton() {
return false;
}
}
}
1 | 通过 Bean 名称 &userServiceFactoryBean 获得的 Bean 是 UserServiceFactoryBean 对象; |
2 | 通过 Bean 名称 userServiceFactoryBean 获得的 Bean 是 UserService 对象; |
有一点需要强调一下:&
符号的使用需要注意。上面的代码和相应注释给出了说明。
ObjectFactory
D瓜哥个人认为 FactoryBean
和 ObjectFactory
功能有些重叠,都是为了创建对象而设计的。
通过 ObjectFactory
的文档,Spring 给出了官方解释:
Spring 在解决循环依赖时和在创建 Bean 时,都使用到接口。它似乎可以脱离 Spring 单独使用。
ObjectProvider
ObjectProvider
继承了 ObjectFactory
接口,它是后者的一个变体,提供了更加丰富的操作 T getIfAvailable()
,T getIfUnique() 等。在 Spring 5.1 以后,有继承了 Iterable<T>
接口,方法用于循环或者 forEach
方法。在 org.springframework.beans.factory.support.DefaultListableBeanFactory
中有使用示例。
BeanPostProcessor
BeanPostProcessor
是 Spring 中最最重要的扩展点。Spring 内部大量的功能 IoC 和 AOP 也都是通过 BeanPostProcessor
来实现的。先来看一下接口定义:
/**
* Factory hook that allows for custom modification of new bean instances —
* for example, checking for marker interfaces or wrapping beans with proxies.
*
* <p>Typically, post-processors that populate beans via marker interfaces
* or the like will implement {@link #postProcessBeforeInitialization},
* while post-processors that wrap beans with proxies will normally
* implement {@link #postProcessAfterInitialization}.
*
* <h3>Registration</h3>
* <p>An {@code ApplicationContext} can autodetect {@code BeanPostProcessor} beans
* in its bean definitions and apply those post-processors to any beans subsequently
* created. A plain {@code BeanFactory} allows for programmatic registration of
* post-processors, applying them to all beans created through the bean factory.
*
* <h3>Ordering</h3>
* <p>{@code BeanPostProcessor} beans that are autodetected in an
* {@code ApplicationContext} will be ordered according to
* {@link org.springframework.core.PriorityOrdered} and
* {@link org.springframework.core.Ordered} semantics. In contrast,
* {@code BeanPostProcessor} beans that are registered programmatically with a
* {@code BeanFactory} will be applied in the order of registration; any ordering
* semantics expressed through implementing the
* {@code PriorityOrdered} or {@code Ordered} interface will be ignored for
* programmatically registered post-processors. Furthermore, the
* {@link org.springframework.core.annotation.Order @Order} annotation is not
* taken into account for {@code BeanPostProcessor} beans.
*
* @author Juergen Hoeller
* @author Sam Brannen
* @since 10.10.2003
* @see InstantiationAwareBeanPostProcessor
* @see DestructionAwareBeanPostProcessor
* @see ConfigurableBeanFactory#addBeanPostProcessor
* @see BeanFactoryPostProcessor
*/
public interface BeanPostProcessor {
/**
* Apply this {@code BeanPostProcessor} to the given new bean instance <i>before</i> any bean
* initialization callbacks (like InitializingBean's {@code afterPropertiesSet}
* or a custom init-method). The bean will already be populated with property values.
* The returned bean instance may be a wrapper around the original.
* <p>The default implementation returns the given {@code bean} as-is.
* @param bean the new bean instance
* @param beanName the name of the bean
* @return the bean instance to use, either the original or a wrapped one;
* if {@code null}, no subsequent BeanPostProcessors will be invoked
* @throws org.springframework.beans.BeansException in case of errors
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet
*/
@Nullable
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
/**
* Apply this {@code BeanPostProcessor} to the given new bean instance <i>after</i> any bean
* initialization callbacks (like InitializingBean's {@code afterPropertiesSet}
* or a custom init-method). The bean will already be populated with property values.
* The returned bean instance may be a wrapper around the original.
* <p>In case of a FactoryBean, this callback will be invoked for both the FactoryBean
* instance and the objects created by the FactoryBean (as of Spring 2.0). The
* post-processor can decide whether to apply to either the FactoryBean or created
* objects or both through corresponding {@code bean instanceof FactoryBean} checks.
* <p>This callback will also be invoked after a short-circuiting triggered by a
* {@link InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation} method,
* in contrast to all other {@code BeanPostProcessor} callbacks.
* <p>The default implementation returns the given {@code bean} as-is.
* @param bean the new bean instance
* @param beanName the name of the bean
* @return the bean instance to use, either the original or a wrapped one;
* if {@code null}, no subsequent BeanPostProcessors will be invoked
* @throws org.springframework.beans.BeansException in case of errors
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet
* @see org.springframework.beans.factory.FactoryBean
*/
@Nullable
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
具体到实际应用上,Spring 内置了大量的应用:
ApplicationContextAwareProcessor
—Aware
接口的处理。InitDestroyAnnotationBeanPostProcessor
—init-method
和destroy-method
方法的调用。InstantiationAwareBeanPostProcessor
CommonAnnotationBeanPostProcessor
— 常用注解@Resource
、@PostConstruct
和@PreDestroy
的解析。AutowiredAnnotationBeanPostProcessor
— 常用注解@Autowired
、@Value
和@Inject
的解析。BeanValidationPostProcessor
— 字段校验。AbstractAutoProxyCreator
— 生成代理。
少废话,直接上代码:
public class LogBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof UserService) {
System.out.println(getAndIncrement()
+ "LogBeanPostProcessor.postProcessBeforeInitialization");
System.out.println(bean);
System.out.println();
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof UserService) {
System.out.println(getAndIncrement()
+ "LogBeanPostProcessor.postProcessAfterInitialization");
System.out.println(bean);
System.out.println();
}
return bean;
}
}
// 将其注册到 BeanFactory 上
beanFactory.addBeanPostProcessor(new LogBeanPostProcessor());
在 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean(String, Object, RootBeanDefinition)
方法中,通过 applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName)
和 applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName)
来分别调用 postProcessBeforeInitialization
和 postProcessAfterInitialization
方法。
各种 Aware
有时,自己开发的代码可能需要 ApplicationContext
或者 BeanFactory
等实例。则可以通过实现相应的 Aware
接口来获得对应的实例。目前有如下这些 Aware
接口:
ApplicationContextAware
ApplicationEventPublisherAware
BeanClassLoaderAware
BeanFactoryAware
BeanNameAware
BootstrapContextAware
EmbeddedValueResolverAware
EnvironmentAware
ImportAware
LoadTimeWeaverAware
MessageSourceAware
NotificationPublisherAware
ResourceLoaderAware
SchedulerContextAware
ServletConfigAware
ServletContextAware
在代码 org.springframework.context.support.ApplicationContextAwareProcessor#invokeAwareInterfaces
中,集中处理了 EnvironmentAware
、EmbeddedValueResolverAware
、ResourceLoaderAware
、ApplicationEventPublisherAware
、MessageSourceAware
和 ApplicationContextAware
等六种 Aware
注入。值得一提的是,通过类的定义可以得知,ApplicationContextAwareProcessor
是一个 BeanPostProcessor
实现类,那么 BeanPostProcessor
的处理机制也通过适用于该类。
ApplicationContextAware
如果某个 Bean 实现了 ApplicationContextAware
接口,那么 Spring 将会将该 Bean 所在的上下文环境 ApplicationContext
传递给 setApplicationContext()
方法,在 Bean 类中新增一个 ApplicationContext
字段用来保存 ApplicationContext
的值,并实现 setApplicationContext()
方法。
@Service
public static class UserService implements InitializingBean, ApplicationContextAware {
@Resource
UserDao userDao;
ApplicationContext applicationContext;
public UserService() {
System.out.println(getAndIncrement()
+ "UserService()\n");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println(getAndIncrement()
+ "UserService.afterPropertiesSet\n");
}
public void init() {
System.out.println(getAndIncrement()
+ "UserService.init\n");
}
String getById(Long id) {
return userDao.getById(id);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
System.out.println(getAndIncrement()
+ "UserService.setApplicationContext\n");
this.applicationContext = applicationContext;
}
}
BeanClassLoaderAware
如果某个 Bean 实现了 BeanClassLoaderAware
接口,那么 Spring 将会将创建 Bean 的 ClassLoader
传递给 setBeanClassLoader()
方法,在 Bean 类中新增了一个 classLoader
字段用来保存 ClassLoader
的值,并实现 setBeanClassLoader()
方法。
BeanFactoryAware
如果某个 Bean 实现了 BeanFactoryAware
接口,那么 Spring 将会将创建 Bean 的 BeanFactory
传递给 setBeanFactory()
方法,在 Bean 类中新增了一个 beanFactory
字段用来保存 BeanFactory
的值,并实现 setBeanFactory()
方法。
BeanNameAware
如果某个 Bean 实现了 BeanNameAware
接口,那么 Spring 将会将 Bean 实例的ID传递给 setBeanName()
方法,在 Bean 类中新增一个 beanName
字段,并实现 setBeanName()
方法。
ServletContextAware
这个接口只能在 Web 项目中使用。
如果某个 Bean 实现了 ServletContextAware
接口,那么 Spring 将会将 ServletContext
传递给 setServletContext()
方法,在 Bean 类中新增一个字段,并实现 setServletContext()
方法。
InitializingBean
与 init-method
设置 init-method
方法和实现 InitializingBean
方法达到的效果是一样的。在代码 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#invokeInitMethods
中可以看到很详细的处理流程:
判断 Bean 是否是
InitializingBean
实例,如果是,则做类型转换,然后再调用其afterPropertiesSet()
方法;获取
AbstractBeanDefinition#initMethodName
属性,然后判断是否合法(①长度大于零,②和第一步条件不重复,③不是外部管理的初始化方法),如果合法,则调用该方法。
init-method
是通过反射执行的,而 afterPropertiesSet()
是直接执行的。所以 afterPropertiesSet()
的执行效率比 init-method
要高;不过 init-method
消除了 Bean 对 Spring 依赖。
其实,按照一种方式设置即可。如果两者同时存在,则按照上述顺序执行。示例见上面的 ApplicationContextAware
示例。
DestructionAwareBeanPostProcessor
能否在 Bean 销毁之前,对其做些操作呢?答案是可以的。
DestructionAwareBeanPostProcessor
就可以实现这个功能。先来看一下接口定义:
/**
* Subinterface of {@link BeanPostProcessor} that adds a before-destruction callback.
*
* <p>The typical usage will be to invoke custom destruction callbacks on
* specific bean types, matching corresponding initialization callbacks.
*
* @author Juergen Hoeller
* @since 1.0.1
*/
public interface DestructionAwareBeanPostProcessor extends BeanPostProcessor {
/**
* Apply this BeanPostProcessor to the given bean instance before its
* destruction, e.g. invoking custom destruction callbacks.
* <p>Like DisposableBean's {@code destroy} and a custom destroy method, this
* callback will only apply to beans which the container fully manages the
* lifecycle for. This is usually the case for singletons and scoped beans.
* @param bean the bean instance to be destroyed
* @param beanName the name of the bean
* @throws org.springframework.beans.BeansException in case of errors
* @see org.springframework.beans.factory.DisposableBean#destroy()
* @see org.springframework.beans.factory.support.AbstractBeanDefinition#setDestroyMethodName(String)
*/
void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException;
/**
* Determine whether the given bean instance requires destruction by this
* post-processor.
* <p>The default implementation returns {@code true}. If a pre-5 implementation
* of {@code DestructionAwareBeanPostProcessor} does not provide a concrete
* implementation of this method, Spring silently assumes {@code true} as well.
* @param bean the bean instance to check
* @return {@code true} if {@link #postProcessBeforeDestruction} is supposed to
* be called for this bean instance eventually, or {@code false} if not needed
* @since 4.3
*/
default boolean requiresDestruction(Object bean) {
return true;
}
}
由于 DestructionAwareBeanPostProcessor
是 BeanPostProcessor
子类,由此可见,可以像操作 BeanPostProcessor
一样来操作 DestructionAwareBeanPostProcessor
实现类。示例如下:
public class LogDestructionAwareBeanPostProcessor implements DestructionAwareBeanPostProcessor {
@Override
public void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException {
System.out.println(getAndIncrement()
+ "LogDestructionAwareBeanPostProcessor.postProcessBeforeDestruction");
System.out.println(bean.getClass().getName());
}
}
// 将其注册到 BeanFactory 上
beanFactory.addBeanPostProcessor(new LogDestructionAwareBeanPostProcessor());
调用是在 org.springframework.beans.factory.support.DisposableBeanAdapter#destroy
方法中实现的。
当调用 beanFactory.destroyBean(bean)
来手动销毁 Bean 时,就会创建 DisposableBeanAdapter
实例,然后调用 destroy()
来触发这个回调。也是在这个方法中,当调用完回调后,就会触发下面的 DisposableBean
回调。
DisposableBean
与 destroy-method
想要触发生命周期函数的 destroy()
方法,必须要要手动调用 beanFactory.destroyBean(bean)
方法才行:
DggDisposableBean dggDisposableBean = applicationContext.getBean(DggDisposableBean.class);
ConfigurableListableBeanFactory beanFactory = ApplicationContext.getBeanFactory();
beanFactory.destroyBean(dggDisposableBean);
调用是在 org.springframework.beans.factory.support.DisposableBeanAdapter#destroy
方法中实现的。
和 InitializingBean
与 init-method
类似,destroy-method
也是在 DisposableBean#destroy()
之后执行的。如果同时存在,只要两者不重复,则两个同时都会执行。
ApplicationListener
在 org.springframework.context.support.AbstractApplicationContext#finishRefresh
中,发布了 ContextRefreshedEvent
事件。
整合实践
上面介绍那么多,现在找一些实际项目对整合过程做个分析。先来个简单的。
Hibernate 与 Spring 整合
在 Spring 官网中,给出了非常详细的介绍: Data Access: Hibernate
Hibernate 与 Spring 整合主要涉及下面几个类:
LocalSessionFactoryBean
— 声明 Hibernate 配置信息;或者注入数据库连接池对象。HibernateTransactionManager
— 负责处理 Hibernate 的事务。
实例代码:
<beans>
<bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="org.hsqldb.jdbcDriver"/>
<property name="url" value="jdbc:hsqldb:hsql://localhost:9001"/>
<property name="username" value="sa"/>
<property name="password" value=""/>
</bean>
<bean id="mySessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<property name="dataSource" ref="myDataSource"/>
<property name="mappingResources">
<list>
<value>product.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<value>
hibernate.dialect=org.hibernate.dialect.HSQLDialect
</value>
</property>
</bean>
<bean id="transactionManager"
class="org.springframework.orm.hibernate5.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<tx:annotation-driven/>
<bean id="myProductDao" class="product.ProductDaoImpl">
<property name="sessionFactory" ref="mySessionFactory"/>
</bean>
<bean id="myProductService" class="product.SimpleProductService">
<property name="productDao" ref="myProductDao"/>
</bean>
</beans>
Spring 与 Hibernate 的整合过程还是比较简单的,就是把 Hibernate 的相关对象当做普通的 Bean 注册到 Spring 容器中即可。
另外,还有一种 HibernateTemplate
方式,和上面的方式类似,就不再赘述。
原计划还准备添加 Spring 与 MyBATIS 和 Apache Dubbo 整合分析。考虑到本篇内容已经非常长,仔细分析它们的整合过程又需要大篇幅内容,所以,另外单独开文章进行说明。