предисловие
Общие понятия не вводятся по одному (например, некоторые методы инъекций, некоторые есть в официальных документах, а в конце документа будет дана ссылка), здесь мы ориентируемся на костяк, и с точки зрения Бога , мы можем просто узнать принцип IOC.
Базовые концепты
Через официальное высокоуровневое представление это легко понять: контейнер помогает нам создавать объекты через конфигурацию (форма аннотации/xml), нам нужно только отвечать за получение, а затем делать это; это равносильно тому, что контейнер сделал слой развязки: зачистка процесса создания и уничтожения экземпляров объекта и процесса вызова, вызывающей стороне нужно заботиться только о самом объекте, а контейнер поможет нам управлять жизнью и смертью объекта.
Когда Spring запускается, он считывает информацию о конфигурации Bean, предоставленную приложением, и создает соответствующий реестр конфигурации Bean в контейнере Spring, а затем создает экземпляр Bean в соответствии с этим реестром и собирает зависимости между bean-компонентами для приложения верхнего уровня. Обеспечьте готовую рабочую среду Пул буферов Bean реализован как HashMap
основной состав
BeanDefinition
Это интерфейс внутри Spring, который определяет базовую спецификацию Bean (beanClassName, scope, lazyInit и т. д.), абстракцию объектов в контейнере;
Property | Объясняется в… |
---|---|
Class | Instantiating Beans |
Name | Naming Beans |
Scope | Bean Scopes |
Constructor arguments | Dependency Injection |
Properties | Dependency Injection |
Autowiring mode | Autowiring Collaborators |
Lazy initialization mode | Lazy-initialized Beans |
Initialization method | Initialization Callbacks |
Destruction method | Destruction Callbacks |
Официальная документация дает следующие инструкции:
In addition to bean definitions that contain information on how to create a specific bean, the ApplicationContext
Реализации также позволяют регистрировать существующие объекты, созданные вне контейнера (пользователями).Это делается путем доступа к BeanFactory ApplicationContext через методgetBeanFactory()
method, which returns the BeanFactory DefaultListableBeanFactory
implementation. DefaultListableBeanFactory
supports this registration through the registerSingleton(..)
and registerBeanDefinition(..)
methods. However, typical applications work solely with beans defined through regular bean definition metadata.
Переворот машины:
В дополнение к определениям bean-компонентов, которые содержат информацию о том, как создать конкретный bean-компонент, реализации ApplicationContext позволяют регистрировать существующие объекты, созданные вне контейнера (пользователем). Это делается путем доступа к BeanFactory ApplicationContext через метод getBeanFactory(), который возвращает реализацию BeanFactory DefaultListableBeanFactory. DefaultListableBeanFactory поддерживает эту регистрацию с помощью методов registerSingleton(..) и registerBeanDefinition(..). Однако типичное приложение может работать только с bean-компонентами, определенными с помощью обычных метаданных определения bean-компонента.
короче
Как играть в BeanDefinition, зарегистрировать его через getBeanFactory().registerBeanDefinition() (то есть поставить)
BeanFactory
Расположенный в верхней части дерева структуры классов, его основным методом является getBean(String beanName), который возвращает Bean с определенным именем из контейнера.Функция BeanFactory постоянно расширяется через другие интерфейсы.
ApplicationContext
ApplicationContext является производным от BeanFactory и предоставляет более практичные функции, ориентированные на приложения.ApplicationContext наследует интерфейсы HierarchicalBeanFactory и ListableBeanFactory.На этой основе он также расширяет функции BeanFactory через несколько других интерфейсов.
FileSystemXmlApplicationContext: загружать файлы конфигурации из файловой системы по умолчанию.
-
ApplicationEventPublisher: позволить контейнеру иметь функцию публикации событий контекста приложения, включая события запуска контейнера.
события, события отключения и т. д.
MessageSource: обеспечивает функцию интернационализированного доступа к сообщениям i18n для приложений;
-
ResourcePatternResolver: все классы реализации ApplicationContext реализуют что-то вроде
Функция PathMatchingResourcePatternResolver может передавать файл ресурсов в стиле Ant с префиксом.
путь к файлу для загрузки файла конфигурации Spring.
-
LifeCycle: этот интерфейс добавлен в Spring 2.0.Этот интерфейс предоставляет два метода: start() и stop().
Используется для управления асинхронной обработкой. При специальном использовании интерфейс реализуется ApplicationContext и конкретными bean-компонентами одновременно.ApplicationContext будет передавать информацию о запуске/остановке всем bean-компонентам в контейнере, реализующем этот интерфейс, для управления и контроля JMX, планирования задач и других целей.
ConfigurableApplicationContext расширяет ApplicationContext, добавляя два новых основных метода: refresh() и close(), которые дают ApplicationContext возможность запускать, обновлять и закрывать контексты приложения. Когда контекст приложения закрыт, вызовите refresh(), чтобы запустить контекст приложения.В уже запущенном состоянии вызовите refresh(), чтобы очистить кеш и перезагрузить информацию о конфигурации, и вызовите close(), чтобы закрыть контекст приложения.
Принципиальный анализ
С введением предыдущих основных понятий три оси МОК
- Информация о конфигурации bean-компонента инкапсулируется в BeanDefinition и помещается в реестр. Через getBeanFactory().registerBeanDefinition()
- Разбирать и создавать экземпляры bean-компонентов в соответствии с информацией реестра и помещать их в кэш карты.
- Вызывающий getBean получает соответствующий bean-компонент
Итак, чтобы понять три вышеуказанных шага, мы поймем общий принцип
Демонстрационный пример очень прост
Java-код
@Setter
@Getter
public class AliasDemo {
private String content;
}
// test方法
@Test
public void testAlias() {
String configLocation = "application-alias.xml";
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(configLocation);
System.out.println(" alias-hello -> " + applicationContext.getBean("alias-hello"));
}
XML-конфигурация
<?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.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"
default-lazy-init="true">
<context:component-scan base-package="com.zhangpeng.**"/>
<bean id="hello" class="com.zhangpeng.study.ioc.alias.AliasDemo">
<property name="content" value="hello"/>
</bean>
<alias name="hello" alias="alias-hello"/>
</beans>
debug
1. Чтение конфигурации IOC
public class ClassPathXmlApplicationContext extends AbstractXmlApplicationContext {
@Nullable
private Resource[] configResources;
...省略部分源码...
// 这是我们上面例子跳转进去的构造,传入一个配置路径
public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
this(new String[] {configLocation}, true, null);
}
// 看看重载的构造方法里面有个setConfigLocations,
// 那肯定就是设置配置路径了
// 还有个refresh方法
public ClassPathXmlApplicationContext(
String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
throws BeansException {
super(parent);
setConfigLocations(configLocations);
if (refresh) {
refresh();
}
}
}
setConfigLocations предназначен в основном для настройки некоторых путей
2. Метод обновления ядра
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
// 1.获取全新的BeanFactory实例
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
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();
// Instantiate all remaining (non-lazy-init) singletons.
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();
}
}
}
2.1 obtainFreshBeanFactory()
@Override
protected final void refreshBeanFactory() throws BeansException {
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
customizeBeanFactory(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);
}
}
Имя метода хорошо названо и легко для понимания
- Сначала уничтожьте beanFactory и создайте экземпляр DefaultListableBeanFactory.
- настроитьBeanFactory настроить некоторые свойства (поддерживать ли переопределяемое BeanDefinition, поддерживать циклические зависимости и т. д.)
Затем введите loadBeanDefinitions
//org.springframework.context.support.AbstractXmlApplicationContext#loadBeanDefinitions(org.springframework.beans.factory.support.DefaultListableBeanFactory)
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// Create a new XmlBeanDefinitionReader for the given BeanFactory.
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
// Configure the bean definition reader with this context's
// resource loading environment.
beanDefinitionReader.setEnvironment(this.getEnvironment());
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
// Allow a subclass to provide custom initialization of the reader,
// then proceed with actually loading the bean definitions.
initBeanDefinitionReader(beanDefinitionReader);
loadBeanDefinitions(beanDefinitionReader);
}
Затем перейдите к doLoadBeanDefinitions, имя метода очень верхнее xx -> doXx
// 接着看下具体解析的地方
/**
* Actually load bean definitions from the specified XML file.
* @param inputSource the SAX InputSource to read from
* @param resource the resource descriptor for the XML file
* @return the number of bean definitions found
* @throws BeanDefinitionStoreException in case of loading or parsing errors
* @see #doLoadDocument
* @see #registerBeanDefinitions
*/
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
// ...省略...
try {
Document doc = doLoadDocument(inputSource, resource);
int count = registerBeanDefinitions(doc, resource);
if (logger.isDebugEnabled()) {
logger.debug("Loaded " + count + " bean definitions from " + resource);
}
return count;
}
// ...省略...
}
Затем посмотрите на registerBeanDefinitions
//org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader#registerBeanDefinitions
/**
* This implementation parses bean definitions according to the "spring-beans" XSD
* (or DTD, historically).
* <p>Opens a DOM Document; then initializes the default settings
* specified at the {@code <beans/>} level; then parses the contained bean definitions.
*/
@Override
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
this.readerContext = readerContext;
doRegisterBeanDefinitions(doc.getDocumentElement());
}
//org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader#doRegisterBeanDefinitions
/**
* Register each bean definition within the given root {@code <beans/>} element.
*/
@SuppressWarnings("deprecation") // for Environment.acceptsProfiles(String...)
protected void doRegisterBeanDefinitions(Element root) {
// Any nested <beans> elements will cause recursion in this method. In
// order to propagate and preserve <beans> default-* attributes correctly,
// keep track of the current (parent) delegate, which may be null. Create
// the new (child) delegate with a reference to the parent for fallback purposes,
// then ultimately reset this.delegate back to its original (parent) reference.
// this behavior emulates a stack of delegates without actually necessitating one.
BeanDefinitionParserDelegate parent = this.delegate;
this.delegate = createDelegate(getReaderContext(), root, parent);
// ...省略...
// 标准开头pre前置
preProcessXml(root);
// 解析doc
parseBeanDefinitions(root, this.delegate);
// 标准结尾post后置
postProcessXml(root);
this.delegate = parent;
}
Я натер еще одну волну doXX, это потрясающе
Наконец, взгляните на parseBeanDefinitions, не вдаваясь в подробности синтаксического анализа.
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
if (delegate.isDefaultNamespace(root)) {
NodeList nl = root.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (node instanceof Element) {
Element ele = (Element) node;
if (delegate.isDefaultNamespace(ele)) {
parseDefaultElement(ele, delegate);
}
else {
delegate.parseCustomElement(ele);
}
}
}
}
else {
delegate.parseCustomElement(root);
}
}
// 解析默认元素
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
importBeanDefinitionResource(ele);
}
else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
processAliasRegistration(ele);
}
else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
processBeanDefinition(ele, delegate);
}
else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
// recurse
doRegisterBeanDefinitions(ele);
}
}
// 最终实际解析BeanDefinition的地方
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
// 这一步采用BeanDefinitionHolder进一步封装BeanDefinition数据
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// Register the final decorated instance.
// 注册最终的装饰实例
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" +
bdHolder.getBeanName() + "'", ele, ex);
}
// Send registration event.
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
В этот момент BeanDefinition рождается и инкапсулируется в BeanDefinitionHolder, который может отвечать первой половине первой половины первого шага трехосного IOC, причем процесс BeanDefinition анализируется конфигурацией.
Теперь, когда BeanDefinition есть, его нужно зарегистрировать, а затем приведенный выше код продолжается.
/**
* Register the given bean definition with the given bean factory.
* @param definitionHolder the bean definition including name and aliases
* @param registry the bean factory to register with
* @throws BeanDefinitionStoreException if registration failed
*/
// 通过指定的bean factory注册,默认就是DefaultListableBeanFactory
public static void registerBeanDefinition(
BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
throws BeanDefinitionStoreException {
// Register bean definition under primary name.
String beanName = definitionHolder.getBeanName();
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
// Register aliases for bean name, if any.
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
for (String alias : aliases) {
registry.registerAlias(beanName, alias);
}
}
}
// org.springframework.beans.factory.support.DefaultListableBeanFactory#registerBeanDefinition
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
Assert.hasText(beanName, "Bean name must not be empty");
Assert.notNull(beanDefinition, "BeanDefinition must not be null");
if (beanDefinition instanceof AbstractBeanDefinition) {
try {
((AbstractBeanDefinition) beanDefinition).validate();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Validation of bean definition failed", ex);
}
}
BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
if (existingDefinition != null) {
if (!isAllowBeanDefinitionOverriding()) {
throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
}
else if (existingDefinition.getRole() < beanDefinition.getRole()) {
// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
if (logger.isInfoEnabled()) {
logger.info("Overriding user-defined bean definition for bean '" + beanName +
"' with a framework-generated bean definition: replacing [" +
existingDefinition + "] with [" + beanDefinition + "]");
}
}
else if (!beanDefinition.equals(existingDefinition)) {
if (logger.isDebugEnabled()) {
logger.debug("Overriding bean definition for bean '" + beanName +
"' with a different definition: replacing [" + existingDefinition +
"] with [" + beanDefinition + "]");
}
}
else {
if (logger.isTraceEnabled()) {
logger.trace("Overriding bean definition for bean '" + beanName +
"' with an equivalent definition: replacing [" + existingDefinition +
"] with [" + beanDefinition + "]");
}
}
this.beanDefinitionMap.put(beanName, beanDefinition);
}
else {
if (hasBeanCreationStarted()) {
// Cannot modify startup-time collection elements anymore (for stable iteration)
synchronized (this.beanDefinitionMap) {
this.beanDefinitionMap.put(beanName, beanDefinition);
List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
updatedDefinitions.addAll(this.beanDefinitionNames);
updatedDefinitions.add(beanName);
this.beanDefinitionNames = updatedDefinitions;
removeManualSingletonName(beanName);
}
}
else {
// Still in startup registration phase
this.beanDefinitionMap.put(beanName, beanDefinition);
this.beanDefinitionNames.add(beanName);
removeManualSingletonName(beanName);
}
this.frozenBeanDefinitionNames = null;
}
if (existingDefinition != null || containsSingleton(beanName)) {
resetBeanDefinition(beanName);
}
}
Приведенный выше абзац представляет собой процесс, когда DefaultListableBeanFactory вставляет BeanDefinition в карту.
стратегическое резюме
В процессе получения метода getFreshBeanFactory загрузите и проанализируйте BeanDefinition, инкапсулируйте BeanDefinition в BeanDefinitionHolder и, наконец, зарегистрируйте BeanDefinition на карте с помощью DefaultListableBeanFactory.
немного старого железа
3.getBean
хх и снова делай хх
public <T> T getBean(String name, @Nullable Class<T> requiredType, @Nullable Object... args)
throws BeansException {
return doGetBean(name, requiredType, args, false);
}
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
// 1.移除&开头字符获取FactoryBean本身 2.如果是别名将其转换为具体实例名
final String beanName = transformedBeanName(name);
Object bean;
// 获取早期缓存,是否实例化过等价于<=>map.get(beanName) map结构<beanName,bean>
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
if (logger.isTraceEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
}
else {
logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
}
}
// 不为空就直接返回
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
// BeanFactory不缓存Prototype类型的bean,处理不了该类型bean的循环依赖问题
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
// Check if bean definition exists in this factory.
BeanFactory parentBeanFactory = getParentBeanFactory();
// 从父容器查找bean实例
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// Not found -> check parent.
String nameToLookup = originalBeanName(name);
if (parentBeanFactory instanceof AbstractBeanFactory) {
return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
nameToLookup, requiredType, args, typeCheckOnly);
}
// 根据有无参数进入对应的getBean重载方法
else if (args != null) {
// Delegation to parent with explicit args.
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
else if (requiredType != null) {
// No args -> delegate to standard getBean method.
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
else {
return (T) parentBeanFactory.getBean(nameToLookup);
}
}
if (!typeCheckOnly) {
markBeanAsCreated(beanName);
}
try {
// 合并父子BeanDefinition
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
// 检查是否有依赖的bean
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dep : dependsOn) {
// 循环依赖校验
if (isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
// 注册依赖的bean信息
registerDependentBean(dep, beanName);
try {
// 加载依赖的bean
getBean(dep);
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
}
}
}
// 创建bean实例
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
});
// 如果bean是FactoryBean类型,则调用工厂方法获取真正的bean实例,否则直接返回bean实例
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
// 创建prototype类型的bean
else if (mbd.isPrototype()) {
// It's a prototype -> create a new instance.
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
// 创建其他类型的bean
else {
String scopeName = mbd.getScope();
final Scope scope = this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
}
try {
Object scopedInstance = scope.get(beanName, () -> {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
});
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
throw new BeanCreationException(beanName,
"Scope '" + scopeName + "' is not active for the current thread; consider " +
"defining a scoped proxy for this bean if you intend to refer to it from a singleton",
ex);
}
}
}
catch (BeansException ex) {
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
}
// 检查是否需要进行类型转换,需要则转换并且返回
if (requiredType != null && !requiredType.isInstance(bean)) {
try {
T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
if (convertedBean == null) {
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
return convertedBean;
}
catch (TypeMismatchException ex) {
if (logger.isTraceEnabled()) {
logger.trace("Failed to convert bean '" + name + "' to required type '" +
ClassUtils.getQualifiedName(requiredType) + "'", ex);
}
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
}
return (T) bean;
}
Сходим основную логику выше
1. Преобразование beanName
2. Получить бин из кеша
3. Если экземпляр не пустой и конструкция с пустыми параметрами, вызовите getObjectForBeanInstance и немедленно вернитесь.
-
4. Если условие 3 не выполнено, найдите компонент, выполнив поиск BeanFactory родительского контейнера.
Соответствующий bean-компонент не найден при непосредственном возврате в родительский контейнер
5. Если компонент существует, объедините BeanDefinition родитель-потомок.
6. Обработка зависимых bean-компонентов, регистрация и создание
7. Процесс FactoryBean (тот же процесс, что и 4)
8. Если требуется преобразование типов, преобразуйте окончательный возвращаемый компонент
3.1 Преобразование beanName
protected String transformedBeanName(String name) {
return canonicalName(BeanFactoryUtils.transformedBeanName(name));
}
// 剔除&打头 方便获取factoryBean自身而不是其具体实现的对象
public static String transformedBeanName(String name) {
Assert.notNull(name, "'name' must not be null");
if (!name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) {
return name;
}
return transformedBeanNameCache.computeIfAbsent(name, beanName -> {
do {
beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length());
}
while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX));
return beanName;
});
}
// 别名转换 因为map不支持<aliasName,Bean> 存储方式
public String canonicalName(String name) {
String canonicalName = name;
// Handle aliasing...
String resolvedName;
do {
resolvedName = this.aliasMap.get(canonicalName);
if (resolvedName != null) {
canonicalName = resolvedName;
}
}
while (resolvedName != null);
return canonicalName;
}
Что касается использования &, то это упоминается в официальном документе.Заинтересованные студенты могут пойти и посмотреть
When you need to ask a container for an actual FactoryBean instance itself instead of the bean it produces, preface the bean’s id with the ampersand symbol (&) when calling the getBean() method of the ApplicationContext. So, for a given FactoryBean with an id of myBean, invoking getBean("myBean") on the container returns the product of the FactoryBean, whereas invoking getBean("&myBean") returns the FactoryBean instance itself.
3.2 Экземпляр получения кэша
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
// 主要是为了防止重复依赖
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
// 当某些方法需要提前初始化的时候会调用addSingletionFactory 方法将对应的singletonFactory存储在singletonFactories
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
// 记录在缓存中,earlySingletonObjects 和 singletonFactories互斥
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
/** Cache of singleton objects: bean name to bean instance. */
// 直接可以使用的对象
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
/** Cache of singleton factories: bean name to ObjectFactory. */
// 用于存放bean工厂,bean工厂所产生的bean是还未完成初始化的bean,bean工厂所生成的对象最终会被缓存到 earlySingletonObjects中
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
// 早期的对象引用(还在初始化中的bean)
/** Cache of early singleton objects: bean name to bean instance. */
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
Этот код включает в себя обработку циклических зависимостей, которые будут объяснены в отдельной статье позже.
3.3 getObjectForBeanInstance возвращает
protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
// 是否以&开头,是的话就获取FactoryBean实例
if (BeanFactoryUtils.isFactoryDereference(name)) {
if (beanInstance instanceof NullBean) {
return beanInstance;
}
// 不是FactoryBean类型,报错
if (!(beanInstance instanceof FactoryBean)) {
throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
}
if (mbd != null) {
mbd.isFactoryBean = true;
}
return beanInstance;
}
// name不是以&开头并且beanInstance不是FactoryBean,说明当前bean是一个普通bean,返回
if (!(beanInstance instanceof FactoryBean)) {
return beanInstance;
}
Object object = null;
if (mbd != null) {
mbd.isFactoryBean = true;
}
else {
// 从缓存获取
object = getCachedObjectForFactoryBean(beanName);
}
if (object == null) {
// Return bean instance from factory.
FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
// Caches object obtained from FactoryBean if it is a singleton.
if (mbd == null && containsBeanDefinition(beanName)) {
// 合并beanDefinition
mbd = getMergedLocalBeanDefinition(beanName);
}
boolean synthetic = (mbd != null && mbd.isSynthetic());
// 从FactoryBean里获取返回
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}
// =========================
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
if (factory.isSingleton() && containsSingleton(beanName)) {
synchronized (getSingletonMutex()) {
Object object = this.factoryBeanObjectCache.get(beanName);
if (object == null) {
// 真正调用了factory.getObject()的地方
object = doGetObjectFromFactoryBean(factory, beanName);
Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
if (alreadyThere != null) {
object = alreadyThere;
}
else {
// 是否应用后置处理器
if (shouldPostProcess) {
if (isSingletonCurrentlyInCreation(beanName)) {
// Temporarily return non-post-processed object, not storing it yet..
return object;
}
beforeSingletonCreation(beanName);
try {
// 执行后置处理器
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName,
"Post-processing of FactoryBean's singleton object failed", ex);
}
finally {
afterSingletonCreation(beanName);
}
}
if (containsSingleton(beanName)) {
// FactoryBean所创建的实例会被缓存在factoryBeanObjectCache中,供后续调用使用
this.factoryBeanObjectCache.put(beanName, object);
}
}
}
return object;
}
}
// 获取非单例类型的实例
else {
// 工厂类获取
Object object = doGetObjectFromFactoryBean(factory, beanName);
// 同上面的 是否需要进行后置处理
if (shouldPostProcess) {
try {
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
}
}
return object;
}
}
// =========================
private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName)
throws BeanCreationException {
Object object;
try {
// 安全校验
if (System.getSecurityManager() != null) {
// ...省略...
}
else {
// 工厂方法生成实例
object = factory.getObject();
}
}
// ...省略...
if (object == null) {
if (isSingletonCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(
beanName, "FactoryBean which is currently in creation returned null from getObject");
}
object = new NullBean();
}
return object;
}
Взгляните на приведенные выше шаги, код очень длинный, а логика очень понятная.
- Проверить, начинается ли тип FactoryBean с &, если да, то получить, если нет, то сообщить об ошибке
- Убедитесь, что параметр beanInstance не является FactoryBean, что указывает на то, что текущий компонент является обычным компонентом и возвращается напрямую.
- Получить FactoryBean из кеша
- Для FactoryBean типа singleton, если он не сработал, экземпляр будет сгенерирован из FactoryBean.getObject() и кэширован.
- Для FactoryBeans неодноэлементных типов создавайте новые экземпляры напрямую без кэширования.
- Определите, следует ли выполнять соответствующий постпроцессор в соответствии с shouldPostProcess.
3.4 Найдите bean-компоненты, найдя BeanFactory родительского контейнера
// 获取父BeanFactory
BeanFactory parentBeanFactory = getParentBeanFactory();
// 校验是否不存在该bean
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// Not found -> check parent.
// 当前xml没找到beanName 对应的信息去parentBeanFactory找
String nameToLookup = originalBeanName(name);
if (parentBeanFactory instanceof AbstractBeanFactory) {
return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
nameToLookup, requiredType, args, typeCheckOnly);
}
else if (args != null) {
// Delegation to parent with explicit args.
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
else if (requiredType != null) {
// No args -> delegate to standard getBean method.
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
else {
return (T) parentBeanFactory.getBean(nameToLookup);
}
}
3.5 Если bean-компонент существует, объедините BeanDefinition родитель-потомок
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
protected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) throws BeansException {
// Quick check on the concurrent map first, with minimal locking.
RootBeanDefinition mbd = this.mergedBeanDefinitions.get(beanName);
if (mbd != null && !mbd.stale) {
return mbd;
}
return getMergedBeanDefinition(beanName, getBeanDefinition(beanName));
}
protected RootBeanDefinition getMergedBeanDefinition(
String beanName, BeanDefinition bd, @Nullable BeanDefinition containingBd)
throws BeanDefinitionStoreException {
synchronized (this.mergedBeanDefinitions) {
RootBeanDefinition mbd = null;
RootBeanDefinition previous = null;
// Check with full lock now in order to enforce the same merged instance.
if (containingBd == null) {
mbd = this.mergedBeanDefinitions.get(beanName);
}
if (mbd == null || mbd.stale) {
previous = mbd;
mbd = null;
// BeanDefinition升级RootBeanDefinition
if (bd.getParentName() == null) {
// Use copy of given root bean definition.
if (bd instanceof RootBeanDefinition) {
mbd = ((RootBeanDefinition) bd).cloneBeanDefinition();
}
else {
mbd = new RootBeanDefinition(bd);
}
}
else {
// Child bean definition: needs to be merged with parent.
BeanDefinition pbd;
try {
String parentBeanName = transformedBeanName(bd.getParentName());
// 校验父beanName是否与子类beanName相同,相同parentBeanName肯定在map里
if (!beanName.equals(parentBeanName)) {
// 使用parentBeanName进行与parent的parent合并,以此类推
pbd = getMergedBeanDefinition(parentBeanName);
}
else {
// 校验是不是ConfigurableBeanFactory类型 不是就报错
BeanFactory parent = getParentBeanFactory();
if (parent instanceof ConfigurableBeanFactory) {
pbd = ((ConfigurableBeanFactory) parent).getMergedBeanDefinition(parentBeanName);
}
else {
throw new NoSuchBeanDefinitionException(parentBeanName,
"Parent name '" + parentBeanName + "' is equal to bean name '" + beanName +
"': cannot be resolved without an AbstractBeanFactory parent");
}
}
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanDefinitionStoreException(bd.getResourceDescription(), beanName,
"Could not resolve parent bean definition '" + bd.getParentName() + "'", ex);
}
// 深拷贝的形式 通过父BeanDefinition配置进行合并的BeanDefinition创建
mbd = new RootBeanDefinition(pbd);
// 用子BeanDefinition覆盖父BeanDefinition属性
mbd.overrideFrom(bd);
}
// 配置默认为单例如果未指定
if (!StringUtils.hasLength(mbd.getScope())) {
mbd.setScope(RootBeanDefinition.SCOPE_SINGLETON);
}
if (containingBd != null && !containingBd.isSingleton() && mbd.isSingleton()) {
mbd.setScope(containingBd.getScope());
}
// Cache the merged bean definition for the time being
// (it might still get re-merged later on in order to pick up metadata changes)
if (containingBd == null && isCacheBeanMetadata()) {
// 缓存合并后的definition
this.mergedBeanDefinitions.put(beanName, mbd);
}
}
if (previous != null) {
copyRelevantMergedBeanDefinitionCaches(previous, mbd);
}
return mbd;
}
}
- BeanDefinition обновляет RootBeanDefinition
- Проверьте, совпадает ли родительский beanName с beanName подкласса, и снова объедините различия.
- Проверьте, относится ли он к типу ConfigurableBeanFactory, иначе сообщит об ошибке
- Сделав так много, его необходимо кэшировать для быстрого и удобного использования.
3.6 Обработка зависимых bean-компонентов, регистрация и создание
// Guarantee initialization of beans that the current bean depends on.
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
// 递归实例化依赖
for (String dep : dependsOn) {
// 校验是否循环依赖,是就抛出异常
if (isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
// 注册依赖
registerDependentBean(dep, beanName);
try {
getBean(dep);
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
}
}
}
/**
* Register a dependent bean for the given bean,
* to be destroyed before the given bean is destroyed.
* @param beanName the name of the bean
* @param dependentBeanName the name of the dependent bean
*/
public void registerDependentBean(String beanName, String dependentBeanName) {
// 别名转换 因为map不支持<aliasName,Bean> 存储方式
String canonicalName = canonicalName(beanName);
synchronized (this.dependentBeanMap) {
Set<String> dependentBeans =
this.dependentBeanMap.computeIfAbsent(canonicalName, k -> new LinkedHashSet<>(8));
if (!dependentBeans.add(dependentBeanName)) {
return;
}
}
// set结构进行去重
synchronized (this.dependenciesForBeanMap) {
Set<String> dependenciesForBean =
this.dependenciesForBeanMap.computeIfAbsent(dependentBeanName, k -> new LinkedHashSet<>(8));
dependenciesForBean.add(canonicalName);
}
}
3.7 Обработка FactoryBean (тот же процесс, что и в 4) опущена
3.8 Если требуется преобразование типов, преобразуйте окончательный возвращаемый компонент
Процесс написания кода хорошо понятен, и я не буду здесь углубляться в его изучение.
резюме
Параграф getBean относительно длинный, этот процесс в основном отвечает за создание экземпляров bean-компонентов, помещает их в кеш и, наконец, возвращает к использованию.
Техническое резюме
- Из анализа исходного кода принципа IOC следует, что стиль именования методов xx&doXx стоит практиковать в работе.
- Процедура логического извлечения достойна упоминания
Расширенное чтение
END
Если вам это нравится, вы можете подключить его три раза одним щелчком мыши.Если у вас есть какие-либо вопросы, пожалуйста, оставьте комментарий в области сообщений.
оригинальный мерзавец