7️⃣更多Bean的特性
Spring框架提供了许多接口,您可以使用这些接口自定义bean的性质。 本节将它们归类如下:
生命周期回调
ApplicationContextAware和BeanNameAware
其他rAware 接口
🍀(1)生命周期回调
初始化回调
org.springframework.beans.factory.InitializingBean.InitializingBean的接口允许bean在容器设置了bean上的所有必要属性之后执行【初始化工作】。【InitializingBean】接口指定了一个方法:
void afterPropertiesSet() throws Exception;
建议您不要使用【InitializingBean】接口,因为这将你的代码与Spring的代码耦合在一起。 我们更推荐使用【@PostConstruct】注解或指定POJO初始化方法。
在基于xml的配置元数据的情况下,您可以使用【init-method】属性指定具有void无参数签名的方法的名称。 在Java配置中,您可以使用【@Bean】的【initMethod】属性。可以看看下面的例子:
<bean id="exampleInitBean" class="examples.ExampleBean" init-method="init"/>
public class ExampleBean { public void init() { // do some initialization work } }
前面的示例几乎与下面的示例(包含两个例子)具有完全相同的效果:
<bean id="exampleInitBean" class="examples.AnotherExampleBean"/>
public class AnotherExampleBean implements InitializingBean { @Override public void afterPropertiesSet() { // do some initialization work } }
然而,前面两个示例中的第一个并没有将代码与Spring耦合起来。
🍀(2)销毁回调
实现org.springframework.beans.factory.DisposableBean接口可以让bean在管理它的容器被销毁时获得回调。 ’ DisposableBean '接口指定了一个方法:
void destroy() throws Exception;
同样,我们并不建议您使用【DisposableBean】回调接口,因为我们没有必要将自己的代码与Spring耦合在一起。 另外,我们建议使用【@PreDestroy】注解或指定beanDifination支持的销毁方法。 对于基于xml的配置元数据,您可以在<bean/>上使用’ destroy-method '属性。 在Java配置中,您可以使用“@Bean”的【destroyMethod】属性。如下所示:
<bean id="exampleInitBean" class="examples.ExampleBean" destroy-method="cleanup"/>
public class ExampleBean { public void cleanup() { // do some destruction work (like releasing pooled connections) } }
前面的定义与下面的定义几乎完全相同:
<bean id="exampleInitBean" class="examples.AnotherExampleBean"/>
public class AnotherExampleBean implements DisposableBean { @Override public void destroy() { // do some destruction work (like releasing pooled connections) } }
🍀(3)默认初始化和销毁方法
当我们不使用spring特有的InitializingBean和disapablebean回调接口进行初始化和销毁时,我们通常会编写名为【init()】、 【initialize()】、 【dispose()】等的方法。 理想情况下,这种生命周期回调方法的名称在项目中应该是标准化的(项目经理规定了都必须这么写),以便所有开发人员使用相同的方法名称,并确保一致性。
您可以配置统一的bean的初始化和销毁方法。 这意味着,作为应用程序开发人员,您可以仅仅声明一个名为【init()】的初始化方法即可,而不必为每个beanDifination配置一个【init method = “init"】属性。
假设你的初始化回调方法名为“init()”,你的destroy回调方法名为“destroy()”。 你的类就像下面这个例子中的类:
public class DefaultBlogService implements BlogService { private BlogDao blogDao; public void setBlogDao(BlogDao blogDao) { this.blogDao = blogDao; } // this is (unsurprisingly) the initialization callback method public void init() { if (this.blogDao == null) { throw new IllegalStateException("The [blogDao] property must be set."); } } }
然后,您可以在bean中使用该类,类似如下:
<beans default-init-method="init"> <bean id="blogService" class="com.something.DefaultBlogService"> <property name="blogDao" ref="blogDao" /> </bean> </beans>
顶层<beans/>元素属性上的【default-init-method】属性导致Spring IoC容器将bean类上的一个名为【init】的方法识别为初始化方法回调。 在创建和组装bean时,如果bean类有这样的方法,就会在适当的时候调用它。
如果现有的bean类已经有按约定命名的回调方法,那么您可以通过使用<bean/>本身的【init-method】和【destroy-method】属性指定对应方法来覆盖默认值。
🍀(4)总结
从Spring 2.5开始,你有三个选项来控制bean的生命周期行为:
InitializingBean和 DisposableBean 和 DisposableBean回调接口
自定义 init()和 destroy() 方法
@PostConstruct 和 @PreDestroy 您可以组合这些机制来控制给定的bean
为同一个bean配置的多个生命周期机制(具有不同的初始化方法),调用顺序如下:
(1)用“@PostConstruct”注解的方法
(2)afterPropertiesSet() 由 InitializingBean 回调接口
(3)自定义配置的init()方法
Destroy方法的调用顺序相同:
(1)用@PreDestroy注解的方法
(2)destroy()由 DisposableBean 回调接口定义
(3)自定义配置的 destroy() 方法
🍀(5)ApplicationContextAware 和 BeanNameAware
下面显示了“ApplicationContextAware”接口的定义:
public interface ApplicationContextAware { void setApplicationContext(ApplicationContext applicationContext) throws BeansException; }
因此,bean可以通过【ApplicationContextAware】接口,以编程方式【操作】创建它们的【ApplicationContext】。 其中一个用途是对其他bean进行编程检索, 有时这种能力是有用的。 但是,一般来说,您应该【避免使用它】,因为它将代码与Spring耦合在一起,而不遵循控制反转(Inversion of Control)风格,在这种风格中,协作者作为属性提供给bean。 ApplicationContext的其他方法提供了对文件资源的访问、发布应用程序事件和访问MessageSource。
当ApplicationContext创建一个实现了BeanNameAware接口的类时。 他提供了对其关联对象定义中定义的名称的引用。 下面的例子显示了BeanNameAware接口的定义:
public interface BeanNameAware { void setBeanName(String name) throws BeansException; }
回调在填充普通bean属性之后,但在初始化回调(如“InitializingBean.afterPropertiesSet()”或自定义初始化方法之前调用。
总结: 实现了aware相关的接口,ioc容器不在遵循ioc风格,意思就是不在遵循按需初始化并注入依赖,而是在统一的地方统一注入,这个在源码中有所体现,后边的内容会涉及。
🍀(6)Other Aware Interfaces
除了“ApplicationContextAware”和“BeanNameAware”,spring提供了一个广泛的“aware”回调接口,让bean指示容器,他们需要一定【基础设施】的依赖。 作为一般规则,名称指示了所需依赖项的类型。 下表总结了一些最重要的“Aware”接口:
命名 | 依赖注入 |
ApplicationContextAware | 将ApplicationContext注入bean当中 |
ApplicationEventPublisherAware | 将ApplicationEventPublisherAware注入bean当中 |
BeanClassLoaderAware | 将类加载器用于装入bean类 |
BeanFactoryAware | 将BeanFactory注入bean当中 |
BeanNameAware | 将bean的名称注入bean中 |
ResourceLoaderAware | 配置了用于访问资源的加载器 |
ServletConfigAware | 当前的’ ServletConfig '容器运行。 仅在web感知的Spring ’ ApplicationContext '中有效。 |
ServletContextAware | 当前运行容器的“ServletContext”。 仅在web感知的Spring ’ ApplicationContext '中有效。 |
再次注意,使用这些接口将您的代码与Spring API绑定在一起,而不是遵循控制反转风格。 因此,我们将它们推荐给需要对容器进行编程访问的基础架构bean。
🍀(7)Bean的继承
bean的定义可以包含大量配置信息,包括构造函数参数、属性值和特定于容器的信息,比如初始化方法、静态工厂方法名,等等。 子beanDifination可以从父beanDifination继承配置数据。 子beanDifination可以根据需要覆盖一些值或添加其他值。 使用父beanDifination和子beanDifination可以节省大量输入。 实际上,这是模板的一种形式。
当您使用基于xml的配置元数据时,您可以通过使用“parent”属性来指示子beanDifination,下面的例子展示了如何做到这一点:
<bean id="inheritedTestBean" abstract="true" class="org.springframework.beans.TestBean"> <property name="name" value="parent"/> <property name="age" value="1"/> </bean> <bean id="inheritsWithDifferentClass" class="org.springframework.beans.DerivedTestBean" parent="inheritedTestBean" init-method="initialize"> <property name="name" value="override"/> <!-- the age property value of 1 will be inherited from parent --> </bean>
如果没有指定,子beanDifination将使用来自父beanDifination的bean类,但也可以覆盖它。 在后一种情况下,子bean类必须与父bean兼容(也就是说,它必须接受父bean的属性值)。
子beanDifination从父bean继承范围、构造函数参数值、属性值和方法覆盖,并可选择添加新值。 您指定的任何scope、初始化方法、销毁方法或“静态”工厂方法设置都会覆盖相应的父方法设置。
其余的设置总是取自子定义:依赖、自动装配模式、依赖项检查、单例和延迟初始化。
前面的示例通过使用【 abstract 】属性显式地将父beanDifination标记为抽象。 如果父beanDifination没有指定类,则需要显式地将父beanDifination标记为【抽象】,如下例所示:
<bean id="inheritedTestBeanWithoutClass" abstract="true"> <property name="name" value="parent"/> <property name="age" value="1"/> </bean> <bean id="inheritsWithClass" class="org.springframework.beans.DerivedTestBean" parent="inheritedTestBeanWithoutClass" init-method="initialize"> <property name="name" value="override"/> <!-- age will inherit the value of 1 from the parent bean definition--> </bean>
父bean不能单独实例化,因为它是不完整的,而且它也显式地被标记为“抽象”。 当定义是【抽象的】时,它只能作为作为一个父beanDifination的【纯模板beanDifination使用】。 试图单独使用这样一个【抽象】的父bean,通过将其作为另一个bean的ref属性引用,或使用父bean ID执行显式的“getBean()”调用,将返回错误。 类似地,容器内部的’ preinstantiatesingleton() '方法会忽略定义为抽象的beanDifination。
8️⃣基于注解的容器配置
在配置Spring时,注解比XML更好吗?
引入基于注解的配置提出了这样一个问题:这种方法是否比XML“更好”, 简短的回答是“视情况而定”。 长期的答案是,每种方法都有其优点和缺点。通常,由开发人员决定哪种策略更适合他们。 由于注解在其声明中提供了【大量上下文】,从而导致配置更简短、更简洁。 然而,XML擅长【连接组件】,而无需修改它们的源代码或重新编译它们。 一些开发人员更喜欢接近源代码进行连接,而另一些开发人员则认为带注解的类不再是pojo,而且配置变得分散且更难控制。
使用注解配置,我们需要开启以下的配置:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> <context:annotation-config/> </beans>
🍀(1)使用 @Autowired
作用就是自动装配,有byType的语义。你可以将@Autowired注解应用到构造函数中,如下面的例子所示
public class MovieRecommender { private final CustomerPreferenceDao customerPreferenceDao; @Autowired public MovieRecommender(CustomerPreferenceDao customerPreferenceDao) { this.customerPreferenceDao = customerPreferenceDao; } // ... }
注意: 从Spring Framework 4.3开始,如果目标bean只定义了一个构造函数,就不再需要在这样的构造函数上添加【 @Autowired 】注解。 然而,如果有几个构造函数可用,并且没有主/默认构造函数,那么至少其中一个构造函数必须用【@Autowired 】注解,以便告诉容器使用哪个构造函数。
你也可以将@Autowired注解应用到传统的 setter方法,如下面的例子所示:
public class SimpleMovieLister { private MovieFinder movieFinder; @Autowired public void setMovieFinder(MovieFinder movieFinder) { this.movieFinder = movieFinder; } // ... }
你还可以将注解应用到具有任意名称和多个参数的方法,如下面的示例所示:
public class MovieRecommender { private MovieCatalog movieCatalog; private CustomerPreferenceDao customerPreferenceDao; @Autowired public void prepare(MovieCatalog movieCatalog, CustomerPreferenceDao customerPreferenceDao) { this.movieCatalog = movieCatalog; this.customerPreferenceDao = customerPreferenceDao; } // ... }
用的最多的但spring官方并不推荐的方法是,你也可以将 @Autowired 应用到字段上,甚至可以将它与构造函数混合使用,如下面的示例所示:
public class MovieRecommender { private final CustomerPreferenceDao customerPreferenceDao; @Autowired private MovieCatalog movieCatalog; @Autowired public MovieRecommender(CustomerPreferenceDao customerPreferenceDao) { this.customerPreferenceDao = customerPreferenceDao; } // ... }
你也可以通过在一个字段或方法中添加【@Autowired】注解来指示Spring从【ApplicationContext】中提供所有特定类型的bean,该字段或方法需要该类型的数组,如下面的例子所示:
public class MovieRecommender { @Autowired private MovieCatalog[] movieCatalogs; // ... }
这同样适用于类型化的集合,如下例所示:
public class MovieRecommender { private Set<MovieCatalog> movieCatalogs; @Autowired public void setMovieCatalogs(Set<MovieCatalog> movieCatalogs) { this.movieCatalogs = movieCatalogs; } // ... }
即使是类型化的“Map”实例,只要期望的键类型是“String”,也可以自动连接。 映射值包含预期类型的所有bean,键包含相应的bean名,如下例所示:
public class MovieRecommender { private Map<String, MovieCatalog> movieCatalogs; @Autowired public void setMovieCatalogs(Map<String, MovieCatalog> movieCatalogs) { this.movieCatalogs = movieCatalogs; } // ... }
注意: 默认情况下,当给定注入点没有可用的匹配候选bean时,自动装配将失败。 对于声明的数组、集合或映射,至少需要一个匹配元素。
默认行为是将带注解的方法和字段视为指示所需的依赖关系。 你可以像下面的例子一样改变这种行为,通过将一个不满足的注入点标记为非必需的(例如,通过将【 @Autowired】中的' required '属性设置为' false ')来让框架跳过它:
public class SimpleMovieLister { private MovieFinder movieFinder; @Autowired(required = false) public void setMovieFinder(MovieFinder movieFinder) { this.movieFinder = movieFinder; } // ... }
🍀(2)使用 @Primary微调基于注解的自动装配
由于按类型自动装配可能会导致多个【候选者】,因此通常需要对选择过程进行更多的控制。 实现这一点的一种方法是使用Spring的【@Primary】注解。 【@Primary】表示当多个bean可以作为一个依赖项的候选bean时,应该优先考虑某个特定bean。 如果在候选bean中恰好存在一个主要的bean,那么它将成为自动连接的值。
考虑以下配置,将’ firstMovieCatalog ‘定义为主要的’ MovieCatalog ':
以下内容【@Bean】是下个章节的:
@Configuration public class MovieConfiguration { @Bean @Primary public MovieCatalog firstMovieCatalog() { ... } @Bean public MovieCatalog secondMovieCatalog() { ... } // ... }
通过上述配置,下面的“MovieRecommender”将自动与“firstMovieCatalog”连接:
public class MovieRecommender { @Autowired private MovieCatalog movieCatalog; // ... }
当然在xml中我们可以如下配置、相应的beanDifination如下,效果是等价的:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> <context:annotation-config/> <bean class="example.SimpleMovieCatalog" primary="true"> <!-- inject any dependencies required by this bean --> </bean> <bean class="example.SimpleMovieCatalog"> <!-- inject any dependencies required by this bean --> </bean> <bean id="movieRecommender" class="example.MovieRecommender"/> </beans>
🍀(3)使用@Qualifier微调基于注解的自动装配
当可以确定一个主要候选时,【@Primary】注解可以轻松完成这个工作。 当您需要对选择过程进行更多控制时,可以使用Spring的【@Qualifier】注解。 您可以将【限定符值】与特定的参数关联起来,从而缩小类型匹配的集合,以便为每个参数选择特定的bean。 在最简单的情况下,这可以是一个简单的描述性值,如下例所示:
public class MovieRecommender { @Autowired @Qualifier("main") private MovieCatalog movieCatalog; // ... }
您还可以在单个构造函数参数或方法参数上指定’ @Qualifier '注解,如下面的示例所示:
public class MovieRecommender { private MovieCatalog movieCatalog; private CustomerPreferenceDao customerPreferenceDao; @Autowired public void prepare(@Qualifier("main") MovieCatalog movieCatalog, CustomerPreferenceDao customerPreferenceDao) { this.movieCatalog = movieCatalog; this.customerPreferenceDao = customerPreferenceDao; } // ... }
下面的示例显示了相应的beanDifination:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> <context:annotation-config/> <bean class="example.SimpleMovieCatalog"> <qualifier value="main"/> <!-- inject any dependencies required by this bean --> </bean> <bean class="example.SimpleMovieCatalog"> <qualifier value="action"/> <!-- inject any dependencies required by this bean --> </bean> <bean id="movieRecommender" class="example.MovieRecommender"/> </beans>
注意: 除了使用qualifier标签决定,其实 @Qualifier可以使用id,name等属性定义的任何标识符。
其实,如果您打算按【名称标识符】完成的注入,那么就可以不使用【@Autowired 】,即使它能够在类型匹配的候选对象中按bean名称进行选择(需要配合@Qualifier同时使用)。 有一个更好的选择是使用JSR-250的 【@Resource】注解,该注解在语义上定义为通过惟一的【名称标识】选择特定的目标组件,声明的类型与匹配过程无关。
🍀(4)使用 @Resource
Spring还通过在字段或bean属性设置方法上使用JSR-250的 【@Resource】注解(' javax.annotation.Resource ')来支持注入。 这是Java EE中的常见模式, Spring也支持这种模式用于Spring管理的对象。
@Resource 带有一个name属性。 默认情况下,Spring将该值解释为要注入的bean名。 换句话说,它遵循by-name语义,如下面的示例所示:
public class SimpleMovieLister { private MovieFinder movieFinder; @Resource(name="myMovieFinder") public void setMovieFinder(MovieFinder movieFinder) { this.movieFinder = movieFinder; } }
如果没有显式指定名称,则默认名称为【字段名或setter方法的参数名】。 对于字段,它接受字段名。 对于setter方法,它采用bean属性名。 下面的例子将把名为【movieFinder】的bean注入到它的setter方法中:
public class SimpleMovieLister { private MovieFinder movieFinder; @Resource public void setMovieFinder(MovieFinder movieFinder) { this.movieFinder = movieFinder; } }
因此,在下面的示例中,' customerPreferenceDao '字段首先查找名为"customerPreferenceDao"的bean,然后按照类型' customerPreferenceDao '的主类型匹配:
public class MovieRecommender { @Resource private CustomerPreferenceDao customerPreferenceDao; @Resource private ApplicationContext context; public MovieRecommender() { } // ... }
9️⃣容器的启动过程
核心方法: refresh()
@Override public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // 准备刷新,准备开店,检查环境,是不是适合开店,比如我选用哪个日志 prepareRefresh(); // 把门面租下来,获得一个bean工厂,loadBeanDefinitions(beanFactory)获取蛋糕的制作流程 ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context. prepareBeanFactory(beanFactory); // 忽略对应的自动装配 //beanFactory.ignoreDependencyInterface(EnvironmentAware.class); try { // Allows post-processing of the bean factory in context subclasses. postProcessBeanFactory(beanFactory); // bean工厂已经基本好了,后置处理器 invokeBeanFactoryPostProcessors(beanFactory); // Register bean processors that intercept bean creation. registerBeanPostProcessors(beanFactory); // Initialize message source for this context. initMessageSource(); // Initialize event multicaster for this context. initApplicationEventMulticaster(); // Initialize other special beans in specific context subclasses. onRefresh(); // Check for listener beans and register them. registerListeners(); // 初始化bean finishBeanFactoryInitialization(beanFactory); // Last step: publish corresponding event. finishRefresh(); } catch (BeansException ex) { if (logger.isWarnEnabled()) { logger.warn("Exception encountered during context initialization - " + "cancelling refresh attempt: " + ex); } // Destroy already created singletons to avoid dangling resources. destroyBeans(); // Reset 'active' flag. cancelRefresh(ex); // Propagate exception to caller. throw ex; } finally { // Reset common introspection caches in Spring's core, since we // might not ever need metadata for singleton beans anymore... resetCommonCaches(); } } }
// 已经完成了创建和属性填充给你的工作 protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) { if (System.getSecurityManager() != null) { AccessController.doPrivileged((PrivilegedAction<Object>) () -> { invokeAwareMethods(beanName, bean); return null; }, getAccessControlContext()); } else { // 1、调用实现的aware接口 invokeAwareMethods(beanName, bean); } Object wrappedBean = bean; if (mbd == null || !mbd.isSynthetic()) { // 调用beanpostproccessor的BeforeInitialization方法 wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); } try { // 调用初始化方法在这里 invokeInitMethods(beanName, wrappedBean, mbd); } catch (Throwable ex) { throw new BeanCreationException( (mbd != null ? mbd.getResourceDescription() : null), beanName, "Invocation of init method failed", ex); } if (mbd == null || !mbd.isSynthetic()) { // 调用beanpostproccessor的AfterInitialization wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); } return wrappedBean; }
🍀(1)初始化Spring容器
这个阶段相当于考察一下地理环境怎么样。
prepareRefresh(): 做一些准备阶段做的是:标记容器为active状态,以及检查当前的运行环境,比如使用log4j,还是jdklog等。
🍀(2)获得一个新的容器
这个阶段相当于租一个门面,同时准备好产品的制作流程。
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
如果有旧的容器,那么清空容器和容器中注册了的bean,创建新的容器DefaultListableBeanFactory。
protected final void refreshBeanFactory() throws BeansException { if (hasBeanFactory()) { destroyBeans(); closeBeanFactory(); } try { DefaultListableBeanFactory beanFactory = createBeanFactory(); beanFactory.setSerializationId(getId()); customizeBeanFactory(beanFactory); loadBeanDefinitions(beanFactory); this.beanFactory = beanFactory; } catch (IOException ex) { throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex); } }
🍀(3)bean工厂的准备阶段
相当于做一些基础装修,比如设备的采购。
prepareBeanFactory(beanFactory);
设置一些处理器:
tandardBeanExpressionResolver ResourceEditorRegistrar
🍀(4)调用所有的BeanFactory后置处理器
这是留给我们进行扩展的,同事spring在也有很多的扩展实现。
执行:
// Invoke factory processors registered as beans in the context. invokeBeanFactoryPostProcessors(beanFactory);
🍀(5)注册BeanPostProcessors
🍀(6)完成bean的创建
beanFactory.preInstantiateSingletons();
在创建bean的过程中,会执行如下流程:
- (1)创建bean
- (2)执行BeanPostProcessors
postProcessBeforeInitialization
(3)执行配置的初始化方法
(4)执行BeanPostProcessors
postProcessAfterInitialization
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) { if (System.getSecurityManager() != null) { AccessController.doPrivileged((PrivilegedAction<Object>) () -> { invokeAwareMethods(beanName, bean); return null; }, getAccessControlContext()); } else { invokeAwareMethods(beanName, bean); } Object wrappedBean = bean; if (mbd == null || !mbd.isSynthetic()) { wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); } try { invokeInitMethods(beanName, wrappedBean, mbd); } catch (Throwable ex) { throw new BeanCreationException( (mbd != null ? mbd.getResourceDescription() : null), beanName, "Invocation of init method failed", ex); } if (mbd == null || !mbd.isSynthetic()) { wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); } return wrappedBean; }
一些重要的BeanFactory后置处理器:
BeanFactoryPostProcessor:BeanFactory后置处理器
ConfigurationClassPostProcessor:解析配置类的BeanFactory后置处理器
一些重要的BeanFactory:
InstantiationAwareBeanPostProcessor:Bean实例化前后运行的后置处理器,还负责设置属性值populateBean()
AutowiredAnnotationBeanPostProcessor:对注解@Autowired的实现
CommonAnnotationBeanPostProcessor:对注解 @Resource的实现
InitDestroyAnnotationBeanPostProcessor:主要是实现了Bean的@PostConstruct和@PreDestroy方法。
AnnotationAwareAspectJAutoProxyCreator:AOP代理的后置处理器,AOP生成代理的地方就是在后置处理器postProcessAfterInitialization方法中实现的。
InfrastructureAdvisorAutoProxyCreator:自动代理创建器,仅考虑基础结构Advisor
Bean,而忽略任何应用程序定义的Advisor。Spring 的事务使用的是这个后置处理器。