Отсканируйте QR-код ниже или WeChat, чтобы найти официальную учетную запись.
菜鸟飞呀飞
, вы можете подписаться на официальный аккаунт WeChat и прочитать дополнительные статьи об анализе исходного кода Spring и параллельном программировании на Java.
1. Вопросы
В нашей повседневной работе, пока мы занимаемся разработкой Java, мы в основном неотделимы от среды Spring.Одной из основных функций Spring является IOC, который может помочь нам добиться автоматической сборки.По сути, мы используем аннотацию @Autowired каждый раз. день для автоматических свойств сборки, то знаете ли вы принцип Autowired аннотаций? Прежде чем читать эту статью, ответьте на следующие вопросы.
- Как аннотация @Autowired реализует автопроводку?
- При сборке свойства типа B для bean-компонента типа A, если в контейнере Spring есть несколько bean-компонентов типа B, как Spring с этим справляется?
- Что такое автопроводная модель? Какие виды есть? Какое это имеет отношение к аннотации Autowired?
2. Demo
Сначала создайте демонстрационный проект этой статьи в соответствии со следующим примером.
- пом-зависимость
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.8.RELEASE</version>
</dependency>
- Класс конфигурации, который указывает файлы, под которыми сканируются пакеты в классе конфигурации.
@Configuration
@ComponentScan("com.tiantang.study")
public class AppConfig {
}
- Определите два интерфейса службы и классы реализации, а затем внедрите классы реализации UserService в OrderServiceImpl.
public interface UserService {
}
@Service
public class UserServiceImpl implements UserService {
}
public interface OrderService {
void query();
}
@Service
public class OrderServiceImpl implements OrderService {
@Autowired
private UserService userService;
public void query(){
System.out.println(userService);
}
}
- Запустите класс, получите класс OrderService, вызвав метод getBean() в классе запуска, затем вызовите метод query() и распечатайте внедренный объект UserService в методе query().
public class MainApplication {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
OrderService orderService = applicationContext.getBean(OrderService.class);
orderService.query();
}
}
- Запуск метода main() в конечном итоге распечатает объект UserService в методе query().
3. Принцип реализации: AutowiredAnnotationBeanPostProcessor
В приведенной выше демонстрации мы завершили автоматическую сборку OrderServiceImpl и завершили операцию назначения для его атрибута userService, так как же Spring выполняет назначение через @Autowired? Мы знаем, что Spring сначала создаст экземпляр bean-компонента на этапе запуска контейнера, а затем инициализирует bean-компонент. На этапе инициализации назначение атрибутов и другие операции будут завершены вызовом постобработки Bean Аналогично, если вы хотите добиться функции @Autowired, это также необходимо сделать через постпроцессор. Этот постпроцессор называется AutowiredAnnotationBeanPostProcessor. Далее давайте взглянем на исходный код этого класса.
3.1 Когда это было добавлено
- Прежде чем анализировать, как работает AutowiredAnnotationBeanPostProcessor, нам нужно знать, когда он был добавлен в контейнер Spring. В конце концов, вы можете заставить его работать, только если сначала поместите его в контейнер.
- когда мы звоним
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class)
При запуске контейнера он будет вызываться в конструктореthis()
метод, вthis()
метод в конечном итоге вызоветregisterAnnotationConfigProcessors()
В этом методе Spring зарегистрирует в контейнере 7 встроенных компонентов Spring, включая AutowiredAnnotationBeanPostProcessor. Если вы хотите узнать больше о процессе запуска контейнера Spring, вы можете обратиться к другой статье автора:Процесс запуска контейнера из серии исходных кодов Spring
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
BeanDefinitionRegistry registry, @Nullable Object source) {
// 省略部分代码...
Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);
// 注册AutowiredAnnotationBeanPostProcessor,这个bean的后置处理器用来处理@Autowired的注入
if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
}
// 注册CommonAnnotationBeanPostProcessor,用来处理如@Resource等符合JSR-250规范的注解
if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
}
return beanDefs;
}
3.2 Когда это называется
Когда вызывается AutowiredAnnotationBeanPostProcessor?
- В процессе создания компонента Spring в конечном итоге вызовет метод doCreateBean(), а в методе doCreateBean() будет вызван метод populateBean() для заполнения свойств компонента и завершения автоматической сборки. Часть исходного кода метода populateBean() выглядит следующим образом.
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
if (hasInstAwareBpps || needsDepCheck) {
if (pvs == null) {
pvs = mbd.getPropertyValues();
}
PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
if (hasInstAwareBpps) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
// 执行后置处理器,填充属性,完成自动装配
// 在这里会调用到AutowiredAnnotationBeanPostProcessor
pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvs == null) {
return;
}
}
}
}
}
}
- В методе populateBean() вызывается всего два постпроцессора. Первый раз определяет, требуется ли заполнение атрибута. Если заполнение атрибута не требуется, возврат будет выполнен напрямую. Если заполнение атрибута требуется, метод Будет ли он продолжать выполняться вниз, а второй вызов постпроцессора будет сделан позже.В это время будет вызываться метод postProcessPropertyValues() AutowiredAnnotationBeanPostProcessor, и аннотация @Autowired будет анализироваться в этом методе, а затем автоматически сборка будет реализована. (Примечание: в приведенном выше исходном коде публикуется только код, который выполняет постпроцессор один раз, а другой опускается).
- Исходный код метода postProcessorPropertyValues() выглядит следующим образом: в этом методе сначала вызывается метод findAutowiringMetadata() для анализа свойств и методов, аннотированных @Autowired, @Inject и @Value в bean-компоненте. Затем вызовите метод metadata.inject(), чтобы заполнить атрибуты.
public PropertyValues postProcessPropertyValues(
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeanCreationException {
// 解析出bean中带有@Autowired注解、@Inject和@Value注解的属性和方法
// 对于本文的demo而言,在此处就会解析出OrderServiceImpl类上的userService属性
// 至于如何解析的,findAutowiringMetadata()方法比较复杂,这里就不展开了,Spring中提供了很多对注解等元数据信息读取的方法,进行了大量的封装。
// 如果不是自己亲自参与开发Spring的话,很难摸透它封装的那些数据结构。
InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
try {
// 自动装配,实现依赖注入
metadata.inject(bean, beanName, pvs);
}
catch (BeanCreationException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
}
return pvs;
}
3.2.1 findAutowiringMetadata()
- Почему приведенный выше анализ говорит только о том, что метод findAutowiringMetadata() будет анализировать аннотации Autowired, аннотации @Inject и @Value? Это связано с тем, что такая глобальная переменная определена в AutowiredAnnotationBeanPostProcessor:
private final Set<Class<? extends Annotation>> autowiredAnnotationTypes = new LinkedHashSet<>(4);
- Эта глобальная переменная инициализируется в конструкторе AutowiredAnnotationBeanPostProcessor. При инициализации в эту коллекцию наборов добавляются только три элемента: @Autowired, @Inject, @Value. Аннотация @Inject — это аннотация в спецификации JSR-330. При вызове метода findAutowiringMetadata() аннотация будет анализироваться в соответствии с типом элемента в глобальной переменной autowiredAnnotationTypes, поэтому выше сказано только, что метод findAutowiringMetadata() будет анализировать аннотацию Autowired, аннотации @Inject и @Value.
public AutowiredAnnotationBeanPostProcessor() {
// 添加@Autowired
this.autowiredAnnotationTypes.add(Autowired.class);
// 添加@Value
this.autowiredAnnotationTypes.add(Value.class);
try {
// 如果项目中引入了JSR-330相关的jar包,那么就会添加@Inject
this.autowiredAnnotationTypes.add((Class<? extends Annotation>)
ClassUtils.forName("javax.inject.Inject", AutowiredAnnotationBeanPostProcessor.class.getClassLoader()));
}
catch (ClassNotFoundException ex) {
}
}
3.2.2 metadata.inject()
- Для свойств с аннотацией Autowired поле будет проанализировано как тип AutowiredFieldElement после анализа на предыдущем шаге; если метод аннотирован с помощью Autowired, он будет проанализирован как тип AutowiredMethodElement. Все они являются подклассами класса InjectedElement, которые инкапсулируют имя атрибута, тип атрибута и другую информацию. После анализа аннотаций, таких как @Resource и @LookUp, они также будут разобраны на соответствующие подклассы InjectedElement: ResourceElement и LookUpElement, но эти две аннотации анализируются в других постпроцессорах, а не в AutowiredAnnotationBeanPostProcessor F.
- Метод metadata.inject() в конечном итоге вызовет метод inject() класса InjectedElement. Для демонстрации в этой статье соответствующий InjectedElement после анализа свойства userService является классом AutowiredFieldElement, поэтому в это время будет вызываться метод AutowiredFieldFieldElement.inject().
- Ниже приведен исходный код метода AutowiredFieldElement.inject(). К исходному коду добавлены некоторые комментарии.Из исходного кода видно, что основной код
beanFactory.resolveDependency()
.
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
Field field = (Field) this.member;
Object value;
// 判断缓存(第一次注入userService的时候,肯定没有缓存,所以会进入到else里面)
// 当第一次注入完成后,会将userService缓存到cachedFieldValue这个属性中,
// 这样当其他的类同样需要注入userService时,就会从这儿的缓存当中读取了。
if (this.cached) {
value = resolvedCachedArgument(beanName, this.cachedFieldValue);
}
else {
DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
desc.setContainingClass(bean.getClass());
Set<String> autowiredBeanNames = new LinkedHashSet<>(1);
TypeConverter typeConverter = beanFactory.getTypeConverter();
try {
// 通过beanFactory.resolveDependency()方法,来从容器中找到userService属性对应的值。
value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
}
catch (BeansException ex) {
throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
}
// 省略部分代码...
// 省略的这部分代码就是将value进行缓存,缓存到cachedFieldValue属性中
}
if (value != null) {
// 通过Java的反射,为属性进行复制
ReflectionUtils.makeAccessible(field);
field.set(bean, value);
}
}
}
- Метод doResolveDependency() в основном вызывается в методе beanFactory.resolveDependency(). Давайте сосредоточимся на анализе метода doResolveDependency(). Код этого метода очень длинный. Исходный код выглядит следующим образом:
public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
try {
Object shortcut = descriptor.resolveShortcut(this);
if (shortcut != null) {
return shortcut;
}
// 省略部分不重要的代码...
// 属性的类型可能是数组、集合、Map类型,所以这一步是处理数组类型、Collection、Map类型的属性
Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
if (multipleBeans != null) {
return multipleBeans;
}
// 根据需要注入的类型type,从容器中找到有哪些匹配的Bean。
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
// 如果从容器中没有找到,且@Autowired的required属性为true,那么则会抛出异常
if (matchingBeans.isEmpty()) {
if (isRequired(descriptor)) {
raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
}
return null;
}
String autowiredBeanName;
Object instanceCandidate;
// 先根据类型匹配出可以依赖注入的bean的Class,如果匹配出多个,则再根据属性名匹配
if (matchingBeans.size() > 1) {
autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
if (autowiredBeanName == null) {
if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
// 当匹配到多个bean的Class,但是却不知道要选择哪一个注入时,就会抛出异常
return descriptor.resolveNotUnique(type, matchingBeans);
}
else {
// In case of an optional Collection/Map, silently ignore a non-unique case:
// possibly it was meant to be an empty collection of multiple regular beans
// (before 4.3 in particular when we didn't even look for collection beans).
return null;
}
}
instanceCandidate = matchingBeans.get(autowiredBeanName);
}
else {
// We have exactly one match.
// 只匹配到一个,则就使用匹配到这个类型
Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
autowiredBeanName = entry.getKey();
instanceCandidate = entry.getValue();
}
if (autowiredBeanNames != null) {
autowiredBeanNames.add(autowiredBeanName);
}
// 此处instanceCandidate = UserServiceImpl.class
if (instanceCandidate instanceof Class) {
// instanceCandidate是注入属性的类型,这个需要根据Class,通过FactoryBean的getBean()方法,创建该类型的单例bean
instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
}
Object result = instanceCandidate;
if (result instanceof NullBean) {
// 如果没从容器中找到对应的bean,则需要判断属性值是否是必须注入的,
// 即@Autowired(required=false/true),如果为true,则抛异常,这就是经常项目启动时,我们看到的异常
if (isRequired(descriptor)) {
raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
}
result = null;
}
if (!ClassUtils.isAssignableValue(type, result)) {
throw new BeanNotOfRequiredTypeException(autowiredBeanName, type, instanceCandidate.getClass());
}
return result;
}
finally {
ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);
}
}
- В приведенном выше исходном коде мы видим, что вызывается resolveMultipleBeans(). Этот метод используется для работы с массивами, коллекциями и картами в атрибутах. Например, мы внедряем следующее в OrderServiceImpl:
@Autowired
private UserService[] userServiceArray;
@Autowired
private List<UserService> userServiceList;
@Autowired
private Map<String,UserService> userServiceMap;
- В это время метод resolveMultipleBeans() найдет все bean-компоненты типа UserService из контейнера. В методе resolveMultipleBeans() будет вызываться метод findAutowireCandidate() для поиска бина соответствующего типа из контейнера.На самом деле в конечном итоге будет вызван метод getBean(), так что когда объект типа UserService не был создано, оно будет создано. (В Spring, будь то создание bean-компонента или получение bean-компонента, записью является метод getBean(). Если вам нужно узнать больше об этом методе, вы можете прочитать другую статью:Посмотрите на процесс создания Bean через исходный код).
- Часть исходного кода метода resolveMultipleBeans()
private Object resolveMultipleBeans(DependencyDescriptor descriptor, @Nullable String beanName,
@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) {
Class<?> type = descriptor.getDependencyType();
// 处理数组类型
if (type.isArray()) {
// findAutowireCandidates最终会调用getBean()方法
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, componentType,
new MultiElementDescriptor(descriptor));
return result;
}
// 处理集合类型
else if (Collection.class.isAssignableFrom(type) && type.isInterface()) {
// findAutowireCandidates最终会调用getBean()方法
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, elementType,
new MultiElementDescriptor(descriptor));
return result;
}
// 处理Map类型
else if (Map.class == type) {
// findAutowireCandidates最终会调用getBean()方法
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, valueType,
new MultiElementDescriptor(descriptor));
return matchingBeans;
}
else {
return null;
}
}
- Если внедряемое свойство является общим типом (не массив, коллекция, карта), то метод будет продолжать выполняться вниз, и будет вызываться следующая строка кода для поиска компонента в соответствии с типом свойства.
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
- Видно, что снова вызывается метод findAutowireCandidates(), который в итоге вызовет метод getBean(), поэтому он найдет из контейнера бин соответствующего типа, то есть бин типа UserService. Если контейнер не находит bean-компонента соответствующего типа, а атрибут должен быть введен, то есть атрибут required аннотации Autowired имеет значение true, то будет выброшено исключение, которое мы часто видим:
NoSuchBeanDefinitionException
.
// 如果容器汇总没有找到指定类型的bean,那么matchingBeans属性就是空的
if (matchingBeans.isEmpty()) {
if (isRequired(descriptor)) {
// 抛出异常
raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
}
return null;
}
- Размер карты MatchingBeans может быть больше 1, так как из контейнера найдено несколько bean-компонентов одного типа, то есть может быть найдено несколько bean-компонентов типа UserService. несколько бобов должны быть введены.
if (matchingBeans.size() > 1) {
// 判断应该使用哪一个bean
autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
if (autowiredBeanName == null) {
if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
// 当匹配到多个bean的Class,但是却不知道要选择哪一个注入时,就会抛出异常
return descriptor.resolveNotUnique(type, matchingBeans);
}
else {
return null;
}
}
instanceCandidate = matchingBeans.get(autowiredBeanName);
}
- В приведенном выше коде вызывается метод defineAutowireCandidate(), чтобы определить, какой компонент следует использовать. Если метод DefineAutowireCandidate() не может решить, какой из них использовать, DefineAutowireCandidate() вернет null. В это время, если атрибут необходимо внедрить еще раз, то есть required=true @Autowired, то будет выброшено исключение (т.к. required=true означает, что этот атрибут должен быть введен, но программа не знает, какой из них нужен будет введено, поэтому будет ошибка), это исключение также часто встречается:
NoUniqueBeanDefinitionException
.
"expected single matching bean but found " + beanNamesFound.size() + ": " + StringUtils.collectionToCommaDelimitedString(beanNamesFound)
- Итак, как же определяет AutowireCandidate(), какой bean-компонент использовать? Spring сначала найдет bean-компоненты с аннотацией @Primary. Например, Spring находит два bean-компонента типа UserService, UserServiceImpl1 и UserServiceImpl2. Если класс UserServiceImpl1 аннотирован @Primary, то сначала будут использоваться bean-компоненты типа userServiceImpl1. Если аннотации @Primary нет, то будут найдены бины с аннотацией @Priority, и первым будет выбран бин с наивысшим приоритетом. Если @Priority не добавлен, он будет оцениваться в соответствии с именем атрибута и beanName в Spring, например: UserServiceImpl1 и UserServiceImpl2 в контейнере Spring BeanName — это userServiceImpl1 и userServiceImpl2 соответственно. Если имя атрибута типа UserService, которое должно быть внедрено в OrderServiceImpl в это время, — userServiceImpl1, то Spring введет для него одноэлементный объект типа UserServiceImpl1; если имя атрибута — userServiceImpl2, то Spring введет для него UserServiceImpl2. Если имя свойства не равно userServiceImpl1 и userServiceImpl2, то оно вернет null, затем при вызове метода выкинет
NoUniqueBeanDefinitionException
аномальный. 这就是我们平常所说的@Autowired注解是先根据类型注入,当碰到多个相同类型时,就会根据属性名注入。它的实现原理就是在如下代码中实现的。
protected String determineAutowireCandidate(Map<String, Object> candidates, DependencyDescriptor descriptor) {
Class<?> requiredType = descriptor.getDependencyType();
// 根据Primary注解来决定优先注入哪个bean
String primaryCandidate = determinePrimaryCandidate(candidates, requiredType);
if (primaryCandidate != null) {
return primaryCandidate;
}
// 根据@Priority注解的优先级来决定注入哪个bean
String priorityCandidate = determineHighestPriorityCandidate(candidates, requiredType);
if (priorityCandidate != null) {
return priorityCandidate;
}
// 如果既没有指定@Primary,也没有指定@Priority,那么就会根据属性的名称来决定注入哪个bean
// 如果要注入的属性的名称与Bean的beanName相同或者别名相同,那么会就会优先注入这个Bean
for (Map.Entry<String, Object> entry : candidates.entrySet()) {
String candidateName = entry.getKey();
Object beanInstance = entry.getValue();
if ((beanInstance != null && this.resolvableDependencies.containsValue(beanInstance)) ||
matchesBeanName(candidateName, descriptor.getDependencyName())) {
return candidateName;
}
}
// 前面三种情况都没有确定要注入哪个bean,那么就返回null。当返回null时,那么就会再调用该方法出抛出异常。
return null;
}
- Когда matchBeans больше 1 и подтверждается, какой bean-компонент используется для внедрения с помощью метода defineAutowireCandidate(), или когда matchBeans=1, соответствующий bean-компонент будет найден из контейнера в соответствии с определенным beanName, а затем bean-компонент будет быть возвращены, и, наконец, в
AutowiredFeildElement.inject()
В методе инъекция выполняется через отражение для полной автоматической сборки. - На этом этапе AutowiredAnnotationBeanPostProcessor завершил автоматическую сборку с помощью метода postProcessPropertyValues(). Выше приведен принцип реализации аннотации @Autowired.
4. Модели с автоматическим подключением
В начале статьи я задал вопрос: какая модель для автовайринга? Какие виды есть? Какое это имеет отношение к аннотации Autowired? На самом деле эта проблема не имеет ничего общего с сегодняшним главным героем AutowiredAnnotationBeanPostProcessor. Но зачем снова упоминать об этом в этой статье? Это связано с тем, что принцип реализации аннотации @Autowired и модели автопроводки чрезвычайно запутанны.
- В принципе реализации @autowired мы упомянули, что он будет сопоставляться по типу, т.е. по типу, когда тип совпадает несколько, сопоставляется имя свойства, т.е. по имени. Модель автоматической сборки имеет три, то есть значение типа перечисления в классе перечисления AutoWire, имя в классе перечисления также byName, ByType, то два места BYNAME и BYTYPE имеют тот же смысл? (Скажем три, на самом деле не особо точно, как видно из исходников, значение перечисления AutoWire на самом деле соответствует значению константы в классе AutoWireCapableBeanFactory, и есть 5 constitowirecapablebeanfactory: autowire_no, autowire_by_name, Autowire_by_type, autowire_constructor, autowire_autodetect , где autowire_autodetect был заброшен).
public enum Autowire {
NO(AutowireCapableBeanFactory.AUTOWIRE_NO),
BY_NAME(AutowireCapableBeanFactory.AUTOWIRE_BY_NAME),
BY_TYPE(AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE);
}
- Прежде всего, можно четко заявить, что значения этих двух совершенно разные. ByName и byType в аннотации @Autowired можно понимать как технологию для достижения автоматической сборки, которая является средством реализации, которое мы разрабатываем, понимаем и определяем.В Spring Spring не называет этот метод реализации. Значение в перечислении Autowire определяется Spring, который используется для описания модели сборки Bean и используется для присвоения значений свойству autowireMode BeanDefinition. Значение autowireMode для BeanDefinition по умолчанию в Spring — Autowire.NO.
- Во-вторых, модель внедрения Bean можно указать вручную, а принцип реализации @Autowired нельзя изменить лично. Например, он указывается при настройке bean-компонента через XML, как показано в следующем примере:
<bean id="orderService" class="com.tiantang.study.service.impl.OrderServiceImpl" autowire="byName">
</bean>
- Или указывается значением атрибута аннотации @Bean
@Bean(autowire = Autowire.BY_NAME)
public OrderService orderService(){
return new OrderServiceImpl();
}
- Когда мы указываем конкретную модель сборки для bean-компонента, значением атрибута autowiredMode BeanDefinition, соответствующего этому bean-компоненту, будет указанное нами значение, а не Autowire.NO Spring по умолчанию.
- Так какой же смысл указывать модель сборки? Он вступит в игру в методе populateBean(). В коде метода populateBean(), который мы публиковали ранее, были опущены некоторые очень важные коды, и теперь мы опубликуем относительно полный код populateBean():
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
// 判断bean的注入模型是byName,还是byType。
if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME || mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME) {
autowireByName(beanName, mbd, bw, newPvs);
}
// 对于MyBatis而言,Mapper在实例化之后,会填充属性,这个时候,需要找到MapperFactoryBean有哪些属性需要填充
// 在Mapper的BeanDefinition初始化时,默认添加了一个属性,addToConfig
// 在下面的if逻辑中,执行完autowireByType()方法后,会找出另外另个需要填充的属性,分别是sqlSessionFactory和sqlSessionTemplate
if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {
autowireByType(beanName, mbd, bw, newPvs);
}
pvs = newPvs;
}
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
if (hasInstAwareBpps || needsDepCheck) {
if (pvs == null) {
pvs = mbd.getPropertyValues();
}
PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
if (hasInstAwareBpps) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
// 第六次执行后置处理器,填充属性,完成自动装配
pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvs == null) {
return;
}
}
}
}
if (needsDepCheck) {
checkDependencies(beanName, mbd, filteredPds, pvs);
}
}
if (pvs != null) {
// 实现通过byName或者byType类型的属性注入
applyPropertyValues(beanName, mbd, bw, pvs);
}
}
- В приведенном выше исходном коде мы обнаружили, что перед вызовом атрибута автоматической сборки постпроцессора он сначала определяет, какая модель сборки компонента.Если это AUTOWIRE_BY_NAME, то будет вызван метод autowireByName(). метод, атрибут будет найден сначала через метод установки, а затем будет найден бин из контейнера по имени атрибута, и атрибуту будет присвоено значение; если это AUTOWIRE_BY_TYPE, то метод autowireByType() будет вызываться, и метод autowireByType() также будет искаться в соответствии с свойством setter метода first., а затем искать bean-компонент из контейнера в соответствии с типом свойства и присваивать значение его свойству.
- Обратите внимание, что выше упоминалось, что свойства ищутся через методы установки. Spring будет игнорировать многие методы установки при поиске. Например, типы свойств - это базовые типы данных, типы обертки, Дата, Строка, Класс, Локальный и т. д., которые будет игнорироваться Spring.
// 判断bean的注入模型是byName,还是byType。
if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME || mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME) {
autowireByName(beanName, mbd, bw, newPvs);
}
// 对于MyBatis而言,Mapper在实例化之后,会填充属性,这个时候,需要找到MapperFactoryBean有哪些属性需要填充
// 在Mapper的BeanDefinition初始化时,默认添加了一个属性,addToConfig
// 在下面的if逻辑中,执行完autowireByType()方法后,会找出另外另个需要填充的属性,分别是sqlSessionFactory和sqlSessionTemplate
if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {
autowireByType(beanName, mbd, bw, newPvs);
}
pvs = newPvs;
}
- После того, как Spring найдет значение компонента, соответствующее атрибуту и атрибуту, с помощью autowireByName() или autowireByType(), он поместит атрибут и значение атрибута в локальную переменную pvs, а затем вызовет последнюю строку метода populateBean().
applyPropertyValues()
метод, а затем заполните его в Bean. - Здесь также можно обнаружить, что модель инъекции не имеет ничего общего с технологией автопроводки аннотации Autowired. @Autowired должен использовать класс AutowiredAnnotationBeanPostProcessor для реализации сборки, а модель автоматической сборки определяет тип сборки компонента, а затем выполняет различные методы в соответствии с типом сборки и не зависит от класса AutowiredAnnotationBeanPostProcessor.
- Существует классический сценарий применения модели автоматического подключения Autowire.BY_TYPE, представляющий собой интеграцию Spring и MyBatis. Когда Spring и MyBatis интегрированы, каждый Mapper, наконец, соответствует MapperFactroyBean, а модель автоматической сборки MapperFactroyBean — AUTOWIRE_BY_TYPE. Когда MapperFactroyBean собран, он выполнит метод autowireByType() и найдет два свойства, которые соответствуют условиям в соответствии с методом установки.
sqlSessionFactory
,sqlSessionTemplate
, а затем присвойте значения этим двум свойствам. - Когда Spring интегрирует MyBatis, частичный исходный код BeanDefinition, который создает MapperFactoryBean, выглядит следующим образом:
private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) {
GenericBeanDefinition definition;
for (BeanDefinitionHolder holder : beanDefinitions) {
definition = (GenericBeanDefinition) holder.getBeanDefinition();
// 指定MapperFactoryBean的自动装配模型为AUTOWIRE_BY_TYPE
definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
}
}
- Подводя итог, ByName и ByType в модели с автоматическим подключением не имеют того же значения, что и ByName и ByType, собранные с помощью @Autowired, и они не имеют ничего общего друг с другом.
5. Резюме
Прежде чем закончить, давайте ответим на три вопроса в начале статьи. 1) Реализация аннотации @Autowired достигается с помощью метода postProcessPropertyValues() класса постпроцессора AutowiredAnnotationBeanPostProcessor. 2) Во время автосборки, если в контейнере имеется несколько свойств одного типа, аннотация @Autowired сначала будет оценивать в соответствии с типом, затем оценивать в соответствии с аннотациями @Primary и @Priority и, наконец, оценивать в соответствии с тем, имя атрибута равно beanName. , если вы все еще не можете решить, какой bean-компонент внедрить, будет выброшено исключение NoUniqueBeanDefinitionException. 3) ByName и byType в автосборке @Autowired не имеют ничего общего с byName и byTYpe в автосборной модели.Значения двух совершенно разные.Первый является средством реализации технологии,а второй используется для определить значение атрибута autowireMode в типе BeanDefiniton.
- В этой статье в основном анализируется принцип реализации аннотации @Autowired через исходный код, который реализуется постпроцессором AutowiredAnnotationBeanPostProcessor, а затем приводятся конкретные детали реализации о том, как работать с несколькими bean-компонентами одного типа в процессе внедрения @Autowired. анализ.
- Благодаря этой статье мы не только узнали принцип реализации аннотации @Autowired, но также узнали, что аннотация @Autowired также может внедрять для нас свойства типа Map, Array и Collection.
- Затем в этой статье сравнивается взаимосвязь между моделью с автоматическим подключением и @Autowired через модель с автоматическим подключением в Spring, и вводится сценарий использования модели с автоматическим подключением BY_TYPE на примере интеграции Spring и MyBatis, а также проводится простой анализ.
- Наконец, прочитав эту статью, сможете ли вы угадать принцип реализации аннотации @Resource? Если непонятно, можете посмотреть исходный код класса CommonAnnotationBeanPostProcessor.
связанное предложение
- Посмотрите на процесс создания Bean через исходный код
- Процесс запуска контейнера из серии исходных кодов Spring
- Весной самое то! самый! самый! Важный постпроцессор! никто из них! ! !
- @Импорт и @EnableXXX
- Напишите подключаемый модуль, который интегрирует Redis и Spring.
- Почему динамический прокси JDK должен быть реализован на основе интерфейсов, а не на основе наследования?
- FactoryBean — одна из точек расширения Spring.
- Мониторы: краеугольный камень параллельного программирования