Автор: Брат Сяофу
Блог:bugstack.cn
Осаждайте, делитесь, растите и позвольте себе и другим что-то получить! 😄
Введение
你提出问题,就要给出解决方案!
В последнее время некоторые фанаты сообщают, что постоянно сталкиваются с препятствиями в общении с начальством и чувствуют, что их не понимают. В большинстве случаев он может говорить о том, что говорит: «Я не понял вашей точки зрения», «Этот проект, который вы хотите сделать, не имеет ценности для бизнеса», «Если вы задаете проблему, вы должны дать ответ». решение», и так далее, и тому подобное.
Учитывая, что конкретную ситуацию необходимо анализировать в каждом конкретном случае, мы не обязательно сможем определить, кто является проблемой, что приводит к различиям в каждом разговоре. Может случиться так, что у лидера есть трудности и перспективы лидера, а может быть, у сотрудников есть понимание и идеи сотрудников, поэтому в конце концов нет консенсуса.
Но когда дело доходит до руководства командой, эффективное общение очень важно. Типа: Если ты прав, зачем я с тобой спорю? Вместо того, чтобы подавлять возникающие противоречия, лучше открыть чат, у кого больше перспективы и сердца, у того больше эмпатии.
Если острая критика полностью исчезнет, мягкая критика станет жесткой.
Если также не допускается легкая критика, молчание будет считаться скрытой мотивацией.
Если молчание больше не допускается, было бы преступлением хвалить недостаточное усилие.
Если позволить существовать только одному голосу, то единственный существующий голос — это ложь.
2. Вопросы для интервью
谢飞机,小记!
, мне всегда кажется, что Весне не на что смотреть, как интервьюер может просить цветы?
интервьюер: Какова роль transformBeanName в Spring getBean?
спасибо, самолет: Я не знаю, смысл этого слова, кажется, в том, чтобы изменить имя боба.
интервьюер: Итак, если ваш bean-компонент имеет псевдоним, что должен сделать Spring, когда он получит bean-компонент?
спасибо, самолет:Этот!
интервьюер: Что делать, если используется зависимость?
спасибо, самолет: Ах, я никогда не использовал зависимости, я не знал!
интервьюер: Когда вы отлаживаете код, вы когда-нибудь видели & перед BeanName, почему оно появляется?
спасибо, самолет: Я не заслуживаю знать! Прощай!
3. Процесс приобретения бобов
Для партнеров, которые плохо знакомы с исходным кодом Spring, они могут быть очень озадачены тем, как получить так много процессов для bean-компонента?
- Могут быть Beans, которые могут иметь псевдонимы, могут иметь зависимости или могут быть обернуты BeanFactory, поэтому будет transformBeanName для обработки этих дифференцированных поведений.
- Существует ли круговая зависимость, существует ли родительская фабрика, является ли это синглтоном или прототипом, является ли это отложенной загрузкой или предварительной загрузкой, находится ли она в буфере, поэтому существуют различные суждения о комбинации для выполнения разных процессов.
- Раннее раскрытие объектов, кэш L3 и четкая пост-маркировка — все оптимизации направлены на то, чтобы сделать получение всего компонента более эффективным.
так, он становился все более и более сложным, чтобы адаптироваться к различным потребностям. Углубленное изучение этой части знаний, безусловно, не только для того, чтобы справиться с восьминогим эссе, но и для того, чтобы рассмотреть, существует ли общеизвестный процесс при столкновении со сложными проблемами в повседневном использовании Spring, который может быстро определить местонахождение проблемы. проблема, и требования таких требований.Может ли схема технической реализации играть определенную руководящую роль в будущей разработке приложений, потому что это конкретная реализация схемы проектирования.
1. Основная блок-схема getBean
- Вся картина — это методы и операции классов и основных процессов, задействованных в процессе getBean. Если вы можете полностью понять всю картину, то вы можете в основном понять весь процесс getBean.
- Это изображение может быть нечетким из-за сжатия сети, вы можете передатьОбратите внимание на публичный аккаунт:стек червоточины,Отвечать:
图稿
,Получать.
следующий, мы по очереди перечислим ключевые коды для получения экземпляров bean-компонентов для анализа Читатели и партнеры также могут вместе просмотреть блок-схему, что облегчит ее понимание.
2. Где getBean начинает читать исходный код
@Test
public void test_getBean() {
BeanFactory beanFactory = new ClassPathXmlApplicationContext("spring-config.xml");
UserDao userDao = beanFactory.getBean("userDao", UserDao.class);
logger.info("获取 Bean:{}", userDao);
}
- При разработке повседневного приложения для Spring он в основном основан на аннотациях, и использовать его самостоятельно практически невозможно.
beanFactory.getBean
способ получить экземпляр Bean. - Поэтому, когда вы учитесь, если вы не можете найти запись для просмотра исходного кода getBean, и неудобно отлаживать и знакомиться с исходным кодом, вы можете написать такой класс модульного теста и нажать на getBean, чтобы читайте исходный код.
3. Глобальный предварительный просмотр исходного кода getBean
Местоположение источника: AbstractBeanFactory -> getBean() -> doGetBean()
@Override
public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
// getBean 就像你的领导其实没做啥,都在 doGetBean 里
return doGetBean(name, requiredType, null, false);
}
protected <T> T doGetBean(final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
throws BeansException {
// 处理别名BeanName、处理带&符的工厂BeanName
final String beanName = transformedBeanName(name);
Object bean;
// 先尝试从缓存中获取Bean实例,这个位置就是三级缓存解决循环依赖的方法
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
if (logger.isDebugEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
}
else {
logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
}
}
// 1. 如果 sharedInstance 是普通的 Bean 实例,则下面的方法会直接返回
// 2. 如果 sharedInstance 是工厂Bean类型,则需要获取 getObject 方法,可以参考关于 FactoryBean 的实现类
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
// 循环依赖有三种,setter注入、多实例和构造函数,Spring 只能解决 setter 注入,所以这里是 Prototype 则会抛出异常
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
// 1. 父 bean 工厂存在
// 2. 当前 bean 不存在于当前bean工厂,则到父工厂查找 bean 实例
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// 获取 name 对应的 beanName,如果 name 是以 & 开头,则返回 & + beanName
String nameToLookup = originalBeanName(name);
// 根据 args 参数是否为空,调用不同的父容器方法获取 bean 实例
if (args != null) {
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
else {
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
}
// 1. typeCheckOnly,用于判断调用 getBean 方法时,是否仅是做类型检查
// 2. 如果不是只做类型检查,就会调用 markBeanAsCreated 进行记录
if (!typeCheckOnly) {
markBeanAsCreated(beanName);
}
try {
// 从容器 getMergedLocalBeanDefinition 获取 beanName 对应的 GenericBeanDefinition,转换为 RootBeanDefinition
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
// 检查当前创建的 bean 定义是否为抽象 bean 定义
checkMergedBeanDefinition(mbd, beanName, args);
// 处理使用了 depends-on 注解的依赖创建 bean 实例
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dep : dependsOn) {
// 监测是否存在 depends-on 循环依赖,若存在则会抛出异常
if (isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
// 注册依赖记录
registerDependentBean(dep, beanName);
try {
// 加载 depends-on 依赖(dep 是 depends-on 缩写)
getBean(dep);
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
}
}
}
// 创建单例 bean 实例
if (mbd.isSingleton()) {
// 把 beanName 和 new ObjectFactory 匿名内部类传入回调
sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
try {
// 创建 bean
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// 创建失败则销毁
destroySingleton(beanName);
throw ex;
}
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
// 创建其他类型的 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);
}
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, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
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 && bean != null && !requiredType.isInstance(bean)) {
try {
return getTypeConverter().convertIfNecessary(bean, requiredType);
}
catch (TypeMismatchException ex) {
if (logger.isDebugEnabled()) {
logger.debug("Failed to convert bean '" + name + "' to required type '" +
ClassUtils.getQualifiedName(requiredType) + "'", ex);
}
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
}
// 返回 Bean
return (T) bean;
}
Таким образом, это в основном основной метод обработки, используемый в процессе getBean, который в основном включает в себя;
- convertBeanName, обрабатывает псевдоним BeanName и factory BeanName со знаком &.
- getSingleton, сначала попробуйте получить экземпляр Bean из кэша, эта позиция является методом для кэша третьего уровня для решения циклической зависимости.
- getObjectForBeanInstance, если sharedInstance является обычным экземпляром Bean, следующий метод вернет результат напрямую. Кроме того, sharedInstance — это тип фабричного компонента, вам нужно получить метод getObject, вы можете обратиться к классу реализации FactoryBean.
- isPrototypeCurrentlyInCreation, существует три вида циклических зависимостей: инъекция сеттера, мультиэкземпляр и конструктор, Spring может решить только инъекцию сеттера, поэтому здесь Prototype выдаст исключение.
- getParentBeanFactory, если родительская фабрика компонентов существует, а текущий компонент не существует в текущей фабрике компонентов, перейдите к родительской фабрике, чтобы найти экземпляр компонента.
- originalBeanName, получить beanName, соответствующее имени, если имя начинается с &, вернуть & + beanName
- args != null, в зависимости от того, является ли параметр args пустым, вызовите различные методы родительского контейнера, чтобы получить экземпляр компонента
- !typeCheckOnly, typeCheckOnly используется для определения того, вызывается ли метод getBean только для проверки типа, если нет, для записи будет вызываться markBeanAsCreated.
- mbd.getDependsOn, который обрабатывает создание экземпляров компонентов из зависимостей, аннотированных с помощью зависимостей.
- является зависимым, определяет, существует ли циклическая зависимость, зависящая от, если она существует, будет выдано исключение
- registerDependentBean, регистрировать записи зависимостей
- getBean(dep), загрузка зависит от зависимостей (dep — это аббревиатура от слова «зависит от»)
- mbd.isSingleton(), который создает экземпляр одноэлементного компонента.
- mbd.isPrototype() для создания других типов экземпляров компонентов.
- return (T) bean, возвращает экземпляр Bean
4. операция преобразования beanName
Обработка и символы: transformedBeanName() -> BeanFactoryUtils.transformedBeanName(name)
public static String transformedBeanName(String name) {
Assert.notNull(name, "'name' must not be null");
String beanName = name;
while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) {
beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length());
}
return beanName;
}
- Объекты, созданные с помощью FactoryBean, будут использовать getBean(FACTORY_BEAN_PREFIX + beanName) для добавления & к beanName при инициализации DefaultListableBeanFactory.
(String FACTORY_BEAN_PREFIX = "&")
- Здесь используется цикл while для постепенного удаления &, пока первым перехватываемым символом является символ &, цикл будет продолжать перехватываться.
&&&userService -> &&userService -> &userService -> userService
Преобразование псевдонима: convertBeanName() -> canonicalName
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;
}
<bean id="userService" class="org.itstack.interview.UserService"/>
<alias name="userService" alias="userService-alias01"/>
<alias name="userService-alias01" alias="userService-alias02"/>
- Прежде всего, Spring не использует псевдоним в качестве ключа в Map для хранения bean-компонентов, поэтому вам нужно найти соответствующее исходное имя, когда вы встретите все псевдонимы для получения bean-компонентов.Если вы знаете об этом, если вы не сталкиваетесь с такими проблемами, вы будете знать, с чего начать.
- Цикл do...while будет продолжать искать имя, соответствующее псевдониму, подобно цепочке, до тех пор, пока у текущего имени не будет псевдонима, он вернет соответствующее имя BeanName.
5. зависит от зависит от бобов
AbstractBeanFactory -> isDependent(beanName, dep) -> DefaultSingletonBeanRegistry
protected boolean isDependent(String beanName, String dependentBeanName) {
synchronized (this.dependentBeanMap) {
return isDependent(beanName, dependentBeanName, null);
}
<bean id="userService" class="org.itstack.interview.UserService" depends-on="userDao"/>
<bean id="userDao" class="org.itstack.interview.UserDao"/>
- isDependent обрабатывает определения bean-компонентов, сконфигурированные с зависимостями.
private boolean isDependent(String beanName, String dependentBeanName, Set<String> alread
if (alreadySeen != null && alreadySeen.contains(beanName)) {
return false;
}
String canonicalName = canonicalName(beanName);
Set<String> dependentBeans = this.dependentBeanMap.get(canonicalName);
if (dependentBeans == null) {
return false;
}
if (dependentBeans.contains(dependentBeanName)) {
return true;
}
for (String transitiveDependency : dependentBeans) {
if (alreadySeen == null) {
alreadySeen = new HashSet<String>();
}
alreadySeen.add(beanName);
if (isDependent(transitiveDependency, dependentBeanName, alreadySeen)) {
return true;
}
}
return false;
}
- ужеSeen != null, отслеживать уже зависимые компоненты
- canonicalName, настроить псевдоним процесса, найти исходное имя BeanName
- Установить dependBeans, получить набор зависимых бинов
- Цикл for рекурсивно обнаруживает зависимые bean-компоненты и добавляет их в уже увиденные.
AbstractBeanFactory -> registerDependentBean(dep, beanName) -> DefaultSingletonBeanRegistry
public void registerDependentBean(String beanName, String dependentBeanName) {
String canonicalName = canonicalName(beanName);
synchronized (this.dependentBeanMap) {
Set<String> dependentBeans = this.dependentBeanMap.get(canonicalName);
if (dependentBeans == null) {
dependentBeans = new LinkedHashSet<String>(8);
this.dependentBeanMap.put(canonicalName, dependentBeans);
}
dependentBeans.add(dependentBeanName);
}
synchronized (this.dependenciesForBeanMap) {
Set<String> dependenciesForBean = this.dependenciesForBeanMap.get(dependentBeanName
if (dependenciesForBean == null) {
dependenciesForBean = new LinkedHashSet<String>(8);
this.dependenciesForBeanMap.put(dependentBeanName, dependenciesForBean);
}
dependenciesForBean.add(canonicalName);
}
}
- canonicalName(beanName), получить исходное имя beanName
- синхронизированный (this.dependentBeanMap), добавьте
в dependBeanMap - синхронизировано (this.dependenciesForBeanMap), добавьте
в зависимостиForBeanMap
Наконец: getBean(dep), вы можете получить Bean, который зависит от
6. Обработка отдельных экземпляров компонентов
AbstractBeanFactory -> mbd.isSingleton()
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
destroySingleton(beanName);
throw ex;
}
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
- Эта часть предназначена для создания экземпляра bean-компонента с одним экземпляром с использованием анонимного внутреннего класса beanName и singletonFactory для передачи в ожидающем обратном вызове.
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(beanName, "'beanName' must not be null");
synchronized (this.singletonObjects) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
if (this.singletonsCurrentlyInDestruction) {
throw new BeanCreationNotAllowedException(beanName,
"Singleton bean creation not allowed while singletons of this factory are in destruction " +
"(Do not request a bean from a BeanFactory in a destroy method implementation!)");
}
if (logger.isDebugEnabled()) {
logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
}
beforeSingletonCreation(beanName);
boolean newSingleton = false;
boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
if (recordSuppressedExceptions) {
this.suppressedExceptions = new LinkedHashSet<Exception>();
}
try {
singletonObject = singletonFactory.getObject();
newSingleton = true;
}
catch (IllegalStateException ex) {
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
throw ex;
}
}
catch (BeanCreationException ex) {
if (recordSuppressedExceptions) {
for (Exception suppressedException : this.suppressedExceptions) {
ex.addRelatedCause(suppressedException);
}
}
throw ex;
}
finally {
if (recordSuppressedExceptions) {
this.suppressedExceptions = null;
}
afterSingletonCreation(beanName);
}
if (newSingleton) {
addSingleton(beanName, singletonObject);
}
}
return (singletonObject != NULL_OBJECT ? singletonObject : null);
}
}
- this.singletonObjects.get(beanName), сначала попробуйте получить объект из пула кеша, если нет, продолжайте выполнение
- beforeSingletonCreation(beanName), отметьте текущий bean-компонент для создания, если есть циклическая зависимость, введенная конструктором, будет сообщено об ошибке
- singletonObject = singletonFactory.getObject(), процесс создания бина заключается в вызове метода createBean()
- afterSingletonCreation(beanName), окончательно удалите тег из коллекции
- addSingleton(beanName, singletonObject), вновь созданный объект будет добавлен в коллекцию кеша
7. Получить экземпляр компонента из кеша
doCreateBean -> if (earlySingletonExposure) -> getSingleton(beanName, false)
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 从 singletonObjects 获取实例,singletonObjects 中缓存的实例都是完全实例化好的 bean,可以直接使用
Object singletonObject = this.singletonObjects.get(beanName);
// 如果 singletonObject 为空,则没有创建或创建中
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
// 加锁
synchronized (this.singletonObjects) {
// 单例缓存池中,没有当前beanName
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
// 加入到三级缓存,暴漏早期对象用于解决三级缓存
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return (singletonObject != NULL_OBJECT ? singletonObject : null);
}
- На самом деле, этот фрагмент кода в основном использует кеш третьего уровня для решения циклической зависимости установки инъекций, и отдельная глава будет указана позже, чтобы выполнить соответствующую экспериментальную проверку циклической зависимости.
- singletonObjects, используемые для хранения инициализированных экземпляров компонентов.
- EarlySingletonObjects, используемые для хранения bean-компонентов при инициализации, для разрешения циклических зависимостей.
- singletonFactories, используемый для хранения фабрики компонентов, бин, сгенерированный фабрикой бинов, не завершил инициализацию бина.
8. Получите экземпляр компонента в FactoryBean
AbstractBeanFactory -> getObjectForBeanInstance(sharedInstance, name, beanName, null)
protected Object getObjectForBeanInstance(Object beanInstance, String name, String beanName, RootBeanDefinition mbd) {
// 如果 beanName 以 & 开头,但 beanInstance 却不是 FactoryBean,则会抛出异常
if (BeanFactoryUtils.isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) {
throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
}
// 这里判断就是这个 bean 是不是 FactoryBean,不是就直接返回了
if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
return beanInstance;
}
Object object = null;
if (mbd == null) {
// 如果 mbd 为空,则从缓存加载 bean(FactoryBean 生成的单例 bean 实例会缓存到 factoryBeanObjectCache 集合中,方便使用)
object = getCachedObjectForFactoryBean(beanName);
}
if (object == null) {
// 到这,beanInstance 是 FactoryBean 类型,所以就强转了
FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
// mbd 为空且判断 containsBeanDefinition 是否包含 beanName
if (mbd == null && containsBeanDefinition(beanName)) {
// 合并 BeanDefinition
mbd = getMergedLocalBeanDefinition(beanName);
}
boolean synthetic = (mbd != null && mbd.isSynthetic());
// 调用 getObjectFromFactoryBean 获取实例
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}
- (!(beanInstance instanceof FactoryBean), решение здесь заключается в том, является ли этот компонент FactoryBean или нет, или он вернется напрямую
- Если mbd пуст, загрузите bean-компонент из кэша (экземпляр singleton bean-компонента, сгенерированный FactoryBean, для удобства будет кэширован в коллекции factoryBeanObjectCache)
- Вызовите getObjectFromFactoryBean, чтобы получить экземпляр, который будет включать в себя часть обработки синглетонов и не-синглетонов, и, наконец, вернет соответствующий экземпляр Bean factory.getObject();
В-четвертых, тестовый пример
1. Псевдонимы
<bean id="userService" class="org.itstack.interview.UserService"/>
<!-- 起个别名 -->
<alias name="userService" alias="userService-alias01"/>
<!-- 别名的别名 -->
<alias name="userService-alias01" alias="userService-alias02"/>
@Test
public void test_alias() {
BeanFactory beanFactory = new ClassPathXmlApplicationContext("spring-config-alias.xml");
UserService userService = beanFactory.getBean("userService-alias02", UserService.class);
logger.info("获取 Bean 通过别名:{}", userService);
}
- При модульном тестировании getBean вы увидите, что он постепенно обрабатывает псевдоним и, наконец, получает исходное имя BeanName.
2. Зависимость
<bean id="userService" class="org.itstack.interview.UserService" depends-on="userDao"/>
<bean id="userDao" class="org.itstack.interview.UserDao"/>
@Test
public void test_depends_on() {
BeanFactory beanFactory = new ClassPathXmlApplicationContext("spring-config-depends-on.xml");
UserService userService = beanFactory.getBean(UserService.class, "userService");
logger.info("获取 Bean:{}", userService.getUserDao());
}
- Когда дело доходит до зависимостей, он перейдет к dependOn != null и получит зависимый экземпляр Bean.
3. BeanFactory
<bean id="userDao" class="org.itstack.interview.MyFactoryBean"/>
@Test
public void test_factory_bean() {
BeanFactory beanFactory = new ClassPathXmlApplicationContext("spring-config-factory-bean.xml");
UserDao userDao = beanFactory.getBean("userDao", UserDao.class);
logger.info("获取 Bean:{}", userDao);
}
- Классы, реализующие FactoryBean, должны будут реализовать метод getObject, и все такие компоненты в конечном итоге получат getObject.
V. Резюме
- На этом этапе базовый процесс получения бина в Spring IOC в основном был представлен.Вся глава показывает, что процесс получения бина также очень сложен и включает в себя множество ветвящихся процессов. Причина, по которой существует так много процессов, заключается в том, что мы представили ранее, потому что получение bean-компонента Spring должно соответствовать многим ситуациям.
- В процессе обучения вы можете сначала разобраться в соответствии с блок-схемой GetBean, а затем проанализировать исходный код в соответствии с шагами.Этот процесс займет у вас почти 1-2 дня, но после того, как весь процесс будет изучен, вы будете в основном не новичок в GetBean.
- Обучение — это почти медленный процесс, похожий на ходьбу по лабиринту.Хотя иногда встречаются неправильные пути, эти неправильные пути также являются частью обучения знаниям. В обучении программированию важны не только результаты, важнее сам процесс, а способ обучения более осмысленный.