脈絡思路:學習Spring的兩大特性IOC與AOP,都離不開容器,那麼就要先了解容器是什麼?如何使用?容器是對象從創建到使用,再到銷燬整個流程的控制。下面梳理下創建對象過程,加載配置文件 ——> 解析——> 封裝BeanDefinition對象 ——> 實例化 ——> 完整對象。。。
下面從加載配置文件入手:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd ">
<context:property-placeholder location="classpath:org/springframework/web/context/WEB-INF/myplaceholder.properties"/>
<bean id="myBean" class="org.springframework.beans.factory.access.TestBean">
<property name="name" value="${myBeanValue}"></property>
</bean>
</beans>
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.access.TestBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class SimpleDemoTest {
@Test
public void test(){
ApplicationContext context = new ClassPathXmlApplicationContext("org/springframework/web/context/beans1.xml");
TestBean bean = (TestBean) context.getBean("mybean");
System.out.println(bean.getName());
}
}
1、加載配置文件,封裝成beanDefinition對象
爲了可以擴展加載更多類型的配置文件,提供一層BeanDefinitionReader接口層(讓不同類型的加載Reader去實現)。加載XML配置文件,實際上用XmlBeanDefinitionReader讀取配置文件,統一封裝成BeanDefinition對象。
在啓動過程是一個核心方法refresh(),refresh()方法實現是在AbstractApplicationContext.java中
/**
* Create a new ClassPathXmlApplicationContext with the given parent,
* loading the definitions from the given XML files.
* @param configLocations array of resource locations
* @param refresh whether to automatically refresh the context,
* loading all bean definitions and creating all singletons.
* Alternatively, call refresh manually after further configuring the context.
* @param parent the parent context
* @throws BeansException if context creation failed
* @see #refresh()
*/
public ClassPathXmlApplicationContext(
String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
throws BeansException {
super(parent);
setConfigLocations(configLocations);
if (refresh) {
refresh();
}
}
下面對refresh()中各個方法做個簡單的介紹:
@Override
public void refresh() throws BeansException, IllegalStateException {
//startupShutdownMonitor對象在spring環境刷新和銷燬的時候都會用到,確保刷新和銷燬不會同時執行
synchronized (this.startupShutdownMonitor) {
// 準備工作,例如記錄事件,設置標誌,檢查環境變量等,並有留給子類擴展的位置,用來將屬性加入到applicationContext中
prepareRefresh();
// 創建beanFactory,這個對象作爲applicationContext的成員變量,可以被applicationContext拿來用,
// 並且解析資源(例如xml文件),取得bean的定義,放在beanFactory中
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 對beanFactory做一些設置,例如類加載器、spel解析器、指定bean的某些類型的成員變量對應某些對象等
prepareBeanFactory(beanFactory);
try {
// 子類擴展用,可以設置bean的後置處理器(bean在實例化之後這些後置處理器會執行)
postProcessBeanFactory(beanFactory);
// 執行beanFactory後置處理器(有別於bean後置處理器處理bean實例,beanFactory後置處理器處理bean定義)
invokeBeanFactoryPostProcessors(beanFactory);
// 將所有的bean的後置處理器排好序,但不會馬上用,bean實例化之後會用到
registerBeanPostProcessors(beanFactory);
// 初始化國際化服務
initMessageSource();
// 創建事件廣播器
initApplicationEventMulticaster();
// 空方法,留給子類自己實現的,在實例化bean之前做一些ApplicationContext相關的操作
onRefresh();
// 註冊一部分特殊的事件監聽器,剩下的只是準備好名字,留待bean實例化完成後再註冊
registerListeners();
// 單例模式的bean的實例化、成員變量注入、初始化等工作都在此完成
finishBeanFactoryInitialization(beanFactory);
// applicationContext刷新完成後的處理,例如生命週期監聽器的回調,廣播通知等
finishRefresh();
}
catch (BeansException ex) {
logger.warn("Exception encountered during context initialization - cancelling refresh attempt", ex);
// 刷新失敗後的處理,主要是將一些保存環境信息的集合做清理
destroyBeans();
// applicationContext是否已經激活的標誌,設置爲false
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
}
}
跟進方法obtainFreshBeanFactory(),可以看到核心方法AbstractRefreshableApplicationContext.java中refreshBeanFactory(),創建beanFactory,同時加載全部beanDefinition對象,此時只做簡單加載(其中配置佔位符不會被替換,替換是在beanFactoryPostProcessor中完成)
@Override
protected final void refreshBeanFactory() throws BeansException {
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
customizeBeanFactory(beanFactory);
//解析資源(例如xml文件),取得bean的定義,放在beanFactory中
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
2、創建beanFactory,執行後置處理器
BeanDefinition對象——>實例化,這個過程不只是new/invoke,還做了哪些操作?
BeanFactory(Interface):Spring的本質是一個bean工廠(beanFactory)或者bean容器。解決bean之間的依賴問題,達到了松耦合的效果。 在沒有spring這個beanFactory之前,我們都是直接通過new來實例化各種對象,現在各種對象bean的生產都是通過beanFactory來實例化的,這樣的話,spring這個beanFactory就可以在實例化bean的各個階段進行一些額外的處理。在bean的生命週期的各個階段對bean進行管理,並且spring將這些階段通過各種接口暴露給我們。 我們只要讓bean實現對應的接口,那麼spring就會在bean的生命週期調用我們實現的接口來處理該bean。
BeanFactoryPostProcessor(Interface): BeanFactory後置處理器,是對BeanDefinition對象進行修改。
BeanPostProcessor(Interface):Bean後置處理器,是對生成的Bean對象進行修改。 (初始化中使用)
後置處理器也被抽象出來,通過實現接口類BeanFactoryPostProcessor就可以自定義創建處理器。下面加入一個MyPostProcessor
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd ">
<context:property-placeholder location="classpath:org/springframework/web/context/WEB-INF/myplaceholder.properties"/>
<bean id="myPostProcessor" class="org.springframework.MyPostProcessor"/>
<bean id="myBean" class="org.springframework.beans.factory.access.TestBean">
<property name="name" value="${myBeanValue}"></property>
</bean>
</beans>
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
public class MyPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println("==> come to myPostProcessor ...");
}
}
控制檯打印:
---------------------------------
==> come to myPostProcessor ...
this is a test
BUILD SUCCESSFUL in 32s
註解是繼配置文件之後的擴展,也是在beanFactory後置處理器位置中做了處理。(同樣放在後置處理器的還有,Springboot中註解自動裝配功能實現方法,跟進ConfigurationClassPostProcessor中postProcessBeanDefinitionRegistry方法。可以仿照@autowire註解處理器AutowiredAnnotationBeanPostProcessor添加自定義註解,完成註解自動裝配需求的實現)
/**
* Derive further bean definitions from the configuration classes in the registry.
*/
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
int registryId = System.identityHashCode(registry);
if (this.registriesPostProcessed.contains(registryId)) {
throw new IllegalStateException(
"postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);
}
if (this.factoriesPostProcessed.contains(registryId)) {
throw new IllegalStateException(
"postProcessBeanFactory already called on this post-processor against " + registry);
}
this.registriesPostProcessed.add(registryId);
processConfigBeanDefinitions(registry);
}
/**
* Build and validate a configuration model based on the registry of
* {@link Configuration} classes.
*/
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
...
// Parse each @Configuration class
ConfigurationClassParser parser = new ConfigurationClassParser(
this.metadataReaderFactory, this.problemReporter, this.environment,
this.resourceLoader, this.componentScanBeanNameGenerator, registry);
Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
do {
parser.parse(candidates);
parser.validate();
...
}
}
class ConfigurationClassParser {
protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {
...
processConfigurationClass(new ConfigurationClass(metadata, beanName));
...
}
protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
...
do {
sourceClass = doProcessConfigurationClass(configClass, sourceClass);
}
...
}
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
throws IOException {
// Process any @ComponentScan annotations
Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
if (!componentScans.isEmpty() &&
!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
for (AnnotationAttributes componentScan : componentScans) {
// The config class is annotated with @ComponentScan -> perform the scan immediately
Set<BeanDefinitionHolder> scannedBeanDefinitions =
this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
// Check the set of scanned definitions for any further config classes and parse recursively if needed
for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
if (bdCand == null) {
bdCand = holder.getBeanDefinition();
}
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
parse(bdCand.getBeanClassName(), holder.getBeanName());
}
}
}
}
// Process any @Import annotations
processImports(configClass, sourceClass, getImports(sourceClass), true);
// Process any @ImportResource annotations
AnnotationAttributes importResource =
AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
if (importResource != null) {
String[] resources = importResource.getStringArray("locations");
Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
for (String resource : resources) {
String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
configClass.addImportedResource(resolvedResource, readerClass);
}
}
// Process individual @Bean methods
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
for (MethodMetadata methodMetadata : beanMethods) {
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
// Process default methods on interfaces
processInterfaces(configClass, sourceClass);
// Process superclass, if any
if (sourceClass.getMetadata().hasSuperClass()) {
String superclass = sourceClass.getMetadata().getSuperClassName();
if (superclass != null && !superclass.startsWith("java") &&
!this.knownSuperclasses.containsKey(superclass)) {
this.knownSuperclasses.put(superclass, configClass);
// Superclass found, return its annotation metadata and recurse
return sourceClass.getSuperClass();
}
}
return null;
}
}
3、對象實例化
猜測一下,通過反射的方式進行實例化代碼如下(在堆空間中開啓空間,屬性都是默認的)
Constructor ctor = clazz.getDeclareConsturctor();
Object obj = ctor.newinstance();
下面開始驗證,跟進下refresh()中 finishBeanFactoryInitialization(beanFactory)
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
// Initialize conversion service for this context.
if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
beanFactory.setConversionService(
beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
}
// Register a default embedded value resolver if no bean post-processor
// (such as a PropertyPlaceholderConfigurer bean) registered any before:
// at this point, primarily for resolution in annotation attribute values.
if (!beanFactory.hasEmbeddedValueResolver()) {
beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
}
// Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
for (String weaverAwareName : weaverAwareNames) {
getBean(weaverAwareName);
}
// Stop using the temporary ClassLoader for type matching.
beanFactory.setTempClassLoader(null);
// Allow for caching all bean definition metadata, not expecting further changes.
beanFactory.freezeConfiguration();
// Instantiate all remaining (non-lazy-init) singletons.
beanFactory.preInstantiateSingletons();
}
beanFactory.preInstantiateSingletons()默認創建單例的對象,繼續跟進。
@Override
public void preInstantiateSingletons() throws BeansException {
if (logger.isTraceEnabled()) {
logger.trace("Pre-instantiating singletons in " + this);
}
// Iterate over a copy to allow for init methods which in turn register new bean definitions.
// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
// Trigger initialization of all non-lazy singleton beans...
for (String beanName : beanNames) {
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
if (isFactoryBean(beanName)) {
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
if (bean instanceof FactoryBean) {
final FactoryBean<?> factory = (FactoryBean<?>) bean;
boolean isEagerInit;
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)
((SmartFactoryBean<?>) factory)::isEagerInit,
getAccessControlContext());
}
else {
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean<?>) factory).isEagerInit());
}
if (isEagerInit) {
getBean(beanName);
}
}
}
else {
getBean(beanName);
}
}
}
...
}
去查找beanName,跟進getBean(beanName)——>doGetBean(name)——>createBean(beanName, mbd, args)——>doCreateBean(beanName, mdbToUse, args)——>createBeanInstance(beanName, mbd, args)可以看到有構造器的創建——>instantiateBean(beanName, mbd)方法——>.instantiate(mbd, beanName, parent)有在創建構造器,那麼期待接下來創建實例new instance()——>BeanUtils.instantiateClass(constructorToUse)果然有new instance
Constructor<?> constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod;
public static <T> T instantiateClass(Constructor<T> ctor, Object... args) throws BeanInstantiationException { Assert.notNull(ctor, "Constructor must not be null"); try { ReflectionUtils.makeAccessible(ctor); if (KotlinDetector.isKotlinReflectPresent() && KotlinDetector.isKotlinType(ctor.getDeclaringClass())) { return KotlinDelegate.instantiateClass(ctor, args); } else { Class<?>[] parameterTypes = ctor.getParameterTypes(); Assert.isTrue(args.length <= parameterTypes.length, "Can't specify more arguments than constructor parameters"); Object[] argsWithDefaultValues = new Object[args.length]; for (int i = 0 ; i < args.length; i++) { if (args[i] == null) { Class<?> parameterType = parameterTypes[i]; argsWithDefaultValues[i] = (parameterType.isPrimitive() ? DEFAULT_TYPE_VALUES.get(parameterType) : null); } else { argsWithDefaultValues[i] = args[i]; } } return ctor.newInstance(argsWithDefaultValues); } } catch (InstantiationException ex) { throw new BeanInstantiationException(ctor, "Is it an abstract class?", ex); } catch (IllegalAccessException ex) { throw new BeanInstantiationException(ctor, "Is the constructor accessible?", ex); } catch (IllegalArgumentException ex) { throw new BeanInstantiationException(ctor, "Illegal arguments for constructor", ex); } catch (InvocationTargetException ex) { throw new BeanInstantiationException(ctor, "Constructor threw exception", ex.getTargetException()); } }
這就是實例化的老巢了...
4、對象的初始化
spring中一般分爲自定義bean對象和容器容器對象,當在自定義對象中調用容器對象,可以通過aware接口去代替get/set方法。
/**
* Interface to be implemented by beans that wish to be aware of their
* owning {@link BeanFactory}.
*/
public interface BeanFactoryAware extends Aware {
void setBeanFactory(BeanFactory beanFactory) throws BeansException;
}
/**
* Interface to be implemented by any object that wishes to be notified
* of the {@link ApplicationContext} that it runs in.
*/
public interface ApplicationContextAware extends Aware {
void setApplicationContext(ApplicationContext applicationContext) throws BeansException;
}
before、after對bean進行擴展beanPostProcessor,例如:AOP動態代理有cglib和jdk兩種方式,下面跟進一下BeanPostProcessor接口
public interface BeanPostProcessor {
@Nullable
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
@Nullable
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
可以找一下動態代理的實現類AbstractAutoProxyCreator,before方法直接返回bean,after方法中跟進wrapIfNecessary
public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
return bean;
}
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// Create proxy if we have advice.
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
/**
* Create an AOP proxy for the given bean.
* @param beanClass the class of the bean
* @param beanName the name of the bean
* @param specificInterceptors the set of interceptors that is
* specific to this bean (may be empty, but not null)
* @param targetSource the TargetSource for the proxy,
* already pre-configured to access the bean
* @return the AOP proxy for the bean
* @see #buildAdvisors
*/
protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
@Nullable Object[] specificInterceptors, TargetSource targetSource) {
if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
}
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this);
if (!proxyFactory.isProxyTargetClass()) {
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
}
else {
evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
proxyFactory.addAdvisors(advisors);
proxyFactory.setTargetSource(targetSource);
customizeProxyFactory(proxyFactory);
proxyFactory.setFrozen(this.freezeProxy);
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}
return proxyFactory.getProxy(getProxyClassLoader());
}
init方法,執行配置文件中init-method方法
下面來找一個初始化的老巢,同之前的實例化refresh()——>finishBeanFactoryInitialization(beanFactory)——>getBean(beanName)——>doGetBean(name)——>createBean(beanName, mbd, args)——>doCreateBean(beanName, mdbToUse, args),在這個方法裏,createBeanInstance(beanName, mbd, args)之後返回實例化對象,然後執行——>populateBean(beanName, mbd, instanceWrapper)填充屬性和initializeBean(beanName, exposedObject, mbd)調用aware方法初始化
====================================================
梳理下容器對象的創建流程:(搞懂Refresh()裏面的13個方法,後面將會細化學習)
- 創建容器 —— prepareRefresh()
- 加載配置文件,封裝成 BeanDefinition —— obtainFreshBeanFactory()
- 調用 BeanFactoryPostProcessor —— invokeBeanFactoryPostProcessors(beanFactory)
- 準備工作① BeanPostProcessor —— registerBeanPostProcessors(beanFactory)
- 準備工作② 監聽器、事件、廣播器等 —— initApplicationEventMulticaster()、registerListeners()
- 實例化 —— finishBeanFactoryInitialization(beanFactory)
- 初始化—— finishBeanFactoryInitialization(beanFactory)
- 獲取完整對象 —— finishBeanFactoryInitialization(beanFactory)