当前位置:网站首页>Annotation @autowired source code analysis
Annotation @autowired source code analysis
2022-07-25 23:56:00 【Maaazhi1】
@Autowired Automatic assembly
Without using xml When configuring a file ,@Autowired It is one of the most used annotations , The principle of this annotation is as follows :
@Autowired principle : Start up springIoC when , The container automatically loads a AutowiredAnnotationBeanPostProcessor Post Processors , When the container scans @Autowied、@Resource or @Inject when , Will be in IoC The container automatically finds what it needs bean, And assemble the properties of the object .
In the use of @Autowired when , First, query the container for the corresponding type of bean
If the query result is exactly one , It's time to bean Assemble to @Autowired Specified data (byType)
If the result of the query is more than one , that @Autowired According to the name (byName) Call to find .
If the result of the query is empty , Then an exception will be thrown . Solution , Use @Autowired(required=false)
And about the @Autowired Usage of , I summed up three points :
1. Used on fields
@Autowired When used on a field , Express Spring It will match and assign values to the changed fields , stay Spring Find... In the container (byType), Find the object that can match this field , And then assign a value ; If it is not found, it will explode abnormally , You can specify required=false Allowed field values are null Resolve errors .
2. Use in set On the way
@Autowired When used on a field , Will find change set The field corresponding to the method , Then the process is consistent with it .
3. Used in construction methods
@Autowired When used in construction methods , All fields corresponding to the reconstruction method will be found , Then the process is consistent with the field .
Meta information analysis :
During processing , There is a class called DependencyDescriptor, For example, our dependency descriptor or dependency descriptor , It records that the object we inject is about that field , For example, my field name and the meta information related to its field , That is to say java Launch a field Field , After understanding this part, it will add all the relevant information, including all the information of the class , Help us analyze , Including one of its field types or parameter types in methods
Dependency lookup , Dependency lookup is actually dependency processing
Dependency injection ,@autowired It can be injected into fields and methods ,
This is @Autowired An operation idea of : Analyze who needs to inject ==》 Find the source of the dependency ==》 An object injected .
Now it's still on the source code , Pay attention to the notes
One 、@Autowired Source code , From the source code, we can see that it can be applied to methods 、 Field 、 Annotations etc.
package org.springframework.beans.factory.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {
boolean required() default true;
}Two 、 Annotated implementation class :AutowiredAnnotationBeanPostProcessor, Through its construction method , You can see that it not only supports @Autowired And support @Value annotation .
public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter
implements MergedBeanDefinitionPostProcessor, PriorityOrdered, BeanFactoryAware {
// Omitted code
/**
* Create a new {@code AutowiredAnnotationBeanPostProcessor} for Spring's
* standard {@link Autowired @Autowired} and {@link Value @Value} annotations.
* <p>Also supports JSR-330's {@link javax.inject.Inject @Inject} annotation,
* if available.
*/
@SuppressWarnings("unchecked")
public AutowiredAnnotationBeanPostProcessor() {
this.autowiredAnnotationTypes.add(Autowired.class);
this.autowiredAnnotationTypes.add(Value.class);
try {
this.autowiredAnnotationTypes.add((Class<? extends Annotation>)
ClassUtils.forName("javax.inject.Inject", AutowiredAnnotationBeanPostProcessor.class.getClassLoader()));
logger.trace("JSR-330 'javax.inject.Inject' annotation found and supported for autowiring");
}
catch (ClassNotFoundException ex) {
// JSR-330 API not available - simply skip.
}
}
} 3、 ... and 、 still AutowiredAnnotationBeanPostProcessor, It implements the interface class MergedBeanDefinitionPostProcessor Methods postProcessMergedBeanDefinition, This method is to merge the information of our defined classes , such as : One class integrates other classes , This method will merge the attributes and information of the parent class into the child class . The code is as follows :
@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
// Find meta information of annotations , Into bean The name of 、 type
InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
metadata.checkConfigMembers(beanDefinition);
}
/**
*
* Find annotation meta information
*/
private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {
// Fall back to class name as cache key, for backwards compatibility with custom callers.
// Read cache first
String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
// Quick check on the concurrent map first, with minimal locking.
InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
synchronized (this.injectionMetadataCache) {
metadata = this.injectionMetadataCache.get(cacheKey);
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
if (metadata != null) {
metadata.clear(pvs);
}
// Build the meta information found
metadata = buildAutowiringMetadata(clazz);
this.injectionMetadataCache.put(cacheKey, metadata);
}
}
}
return metadata;
}
// Construct annotation meta information
private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
// Judge whether the annotation type meets the conditions (@AutoWired and @Value)
if (!AnnotationUtils.isCandidateClass(clazz, this.autowiredAnnotationTypes)) {
return InjectionMetadata.EMPTY;
}
List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
Class<?> targetClass = clazz;
do {
final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
// First deal with the annotation field
ReflectionUtils.doWithLocalFields(targetClass, field -> {
// Is it the field you want to find
MergedAnnotation<?> ann = findAutowiredAnnotation(field);
if (ann != null) {
// Static fields do not support @Autowired
if (Modifier.isStatic(field.getModifiers())) {
if (logger.isInfoEnabled()) {
logger.info("Autowired annotation is not supported on static fields: " + field);
}
return;
}
boolean required = determineRequiredStatus(ann);
currElements.add(new AutowiredFieldElement(field, required));
}
});
// Then the annotation method
ReflectionUtils.doWithLocalMethods(targetClass, method -> {
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
return;
}
MergedAnnotation<?> ann = findAutowiredAnnotation(bridgedMethod);
if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
//@Autowired Static methods are not supported
if (Modifier.isStatic(method.getModifiers())) {
if (logger.isInfoEnabled()) {
logger.info("Autowired annotation is not supported on static methods: " + method);
}
return;
}
if (method.getParameterCount() == 0) {
if (logger.isInfoEnabled()) {
logger.info("Autowired annotation should only be used on methods with parameters: " +
method);
}
}
boolean required = determineRequiredStatus(ann);
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
currElements.add(new AutowiredMethodElement(method, required, pd));
}
});
elements.addAll(0, currElements);
targetClass = targetClass.getSuperclass();
}
while (targetClass != null && targetClass != Object.class);
return InjectionMetadata.forElements(elements, clazz);
}
/**
* Class representing injection information about an annotated field.
*/
private class AutowiredFieldElement extends InjectionMetadata.InjectedElement {
private final boolean required;
private volatile boolean cached = false;
@Nullable
private volatile Object cachedFieldValue;
public AutowiredFieldElement(Field field, boolean required) {
super(field, null);
this.required = required;
}
@Override
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
Field field = (Field) this.member;
Object value;
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);
Assert.state(beanFactory != null, "No BeanFactory available");
TypeConverter typeConverter = beanFactory.getTypeConverter();
try {
value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
}
catch (BeansException ex) {
throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
}
synchronized (this) {
if (!this.cached) {
if (value != null || this.required) {
this.cachedFieldValue = desc;
registerDependentBeans(beanName, autowiredBeanNames);
if (autowiredBeanNames.size() == 1) {
String autowiredBeanName = autowiredBeanNames.iterator().next();
if (beanFactory.containsBean(autowiredBeanName) &&
beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
this.cachedFieldValue = new ShortcutDependencyDescriptor(
desc, autowiredBeanName, field.getType());
}
}
}
else {
this.cachedFieldValue = null;
}
this.cached = true;
}
}
}
if (value != null) {
ReflectionUtils.makeAccessible(field);
field.set(bean, value);
}
}
}
/**
* Class representing injection information about an annotated method.
*/
private class AutowiredMethodElement extends InjectionMetadata.InjectedElement {
private final boolean required;
private volatile boolean cached = false;
@Nullable
private volatile Object[] cachedMethodArguments;
public AutowiredMethodElement(Method method, boolean required, @Nullable PropertyDescriptor pd) {
super(method, pd);
this.required = required;
}
@Override
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
if (checkPropertySkipping(pvs)) {
return;
}
Method method = (Method) this.member;
Object[] arguments;
if (this.cached) {
// Shortcut for avoiding synchronization...
arguments = resolveCachedArguments(beanName);
}
else {
int argumentCount = method.getParameterCount();
arguments = new Object[argumentCount];
DependencyDescriptor[] descriptors = new DependencyDescriptor[argumentCount];
Set<String> autowiredBeans = new LinkedHashSet<>(argumentCount);
Assert.state(beanFactory != null, "No BeanFactory available");
TypeConverter typeConverter = beanFactory.getTypeConverter();
for (int i = 0; i < arguments.length; i++) {
MethodParameter methodParam = new MethodParameter(method, i);
DependencyDescriptor currDesc = new DependencyDescriptor(methodParam, this.required);
currDesc.setContainingClass(bean.getClass());
descriptors[i] = currDesc;
try {
Object arg = beanFactory.resolveDependency(currDesc, beanName, autowiredBeans, typeConverter);
if (arg == null && !this.required) {
arguments = null;
break;
}
arguments[i] = arg;
}
catch (BeansException ex) {
throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(methodParam), ex);
}
}
synchronized (this) {
if (!this.cached) {
if (arguments != null) {
DependencyDescriptor[] cachedMethodArguments = Arrays.copyOf(descriptors, arguments.length);
registerDependentBeans(beanName, autowiredBeans);
if (autowiredBeans.size() == argumentCount) {
Iterator<String> it = autowiredBeans.iterator();
Class<?>[] paramTypes = method.getParameterTypes();
for (int i = 0; i < paramTypes.length; i++) {
String autowiredBeanName = it.next();
if (beanFactory.containsBean(autowiredBeanName) &&
beanFactory.isTypeMatch(autowiredBeanName, paramTypes[i])) {
cachedMethodArguments[i] = new ShortcutDependencyDescriptor(
descriptors[i], autowiredBeanName, paramTypes[i]);
}
}
}
this.cachedMethodArguments = cachedMethodArguments;
}
else {
this.cachedMethodArguments = null;
}
this.cached = true;
}
}
}
if (arguments != null) {
try {
ReflectionUtils.makeAccessible(method);
method.invoke(bean, arguments);
}
catch (InvocationTargetException ex) {
throw ex.getTargetException();
}
}
}
@Nullable
private Object[] resolveCachedArguments(@Nullable String beanName) {
Object[] cachedMethodArguments = this.cachedMethodArguments;
if (cachedMethodArguments == null) {
return null;
}
Object[] arguments = new Object[cachedMethodArguments.length];
for (int i = 0; i < arguments.length; i++) {
arguments[i] = resolvedCachedArgument(beanName, cachedMethodArguments[i]);
}
return arguments;
}
}
This method finds all meta information that needs annotation injection and parses it , This process is also a dependency lookup process . As for how the injection process is called , Next, look at this method :
// Property processing , Meta information search 、 analysis 、 Inject
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
// Meta information search 、 analysis , It has been analyzed in the previous step
InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
try {
// For injection
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;
}
public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
Collection<InjectedElement> checkedElements = this.checkedElements;
Collection<InjectedElement> elementsToIterate =
(checkedElements != null ? checkedElements : this.injectedElements);
if (!elementsToIterate.isEmpty()) {
for (InjectedElement element : elementsToIterate) {
if (logger.isTraceEnabled()) {
logger.trace("Processing injected element of bean '" + beanName + "': " + element);
}
// Inject
element.inject(target, beanName, pvs);
}
}
}
/**
* Either this or {@link #getResourceToInject} needs to be overridden.
*/
protected void inject(Object target, @Nullable String requestingBeanName, @Nullable PropertyValues pvs)
throws Throwable {
// Field injection
if (this.isField) {
Field field = (Field) this.member;
// Set the field permission to be accessible
ReflectionUtils.makeAccessible(field);
field.set(target, getResourceToInject(target, requestingBeanName));
}
else {// Methods to inject
if (checkPropertySkipping(pvs)) {
return;
}
try {
Method method = (Method) this.member;
// Set the method permission to be accessible
ReflectionUtils.makeAccessible(method);
method.invoke(target, getResourceToInject(target, requestingBeanName));
}
catch (InvocationTargetException ex) {
throw ex.getTargetException();
}
}
}
After the above analysis ,@Autowired annotation , Through the first postProcessMergedBeanDefinition Method ->findAutowiringMetadata Methods analyze and find meta information , And write class information through reflection , Through again inject Method to inject .
边栏推荐
- 三板斧!助你成为优秀软件工程师
- 统计之歌 歌词
- SQLZOO——Nobel Quiz
- 意向不到的Dubug妙招
- ShardingSphere数据分片
- [ManageEngine] servicedesk plus won the 2022 safety model engineering data safety award
- Firewall command simple operation
- S4/hana ME21N create Po output control message button missing solution (switch EDI output mode brf+ to Nast mode)
- How does JS judge whether the current date is within a certain range
- Program environment and pretreatment
猜你喜欢

Redis extended data type (jump table /bitmaps/hyperloglog/geospatial)
![[testing technology automated testing pytest] basic summary of pytest](/img/30/7c632cd6ad93c9294745dda7642f17.png)
[testing technology automated testing pytest] basic summary of pytest

行为型模式之观察者模式

Redis basic data type (string/list/set/hash/zset)
![[JUC] concurrent keyword volatile](/img/80/2f1b33f1e8c87fd4f8806eafb83139.png)
[JUC] concurrent keyword volatile

疫情之下的好消息

LeetCode 0919. 完全二叉树插入器:完全二叉树的数组表示

The process of finding free screen recording software - I didn't expect win10 to come with this function

SIGIR‘22 推荐系统论文之图网络篇

Docker installation redis-5.0.12 (remote access)
随机推荐
结对编程实践心得
C language (high level) program environment and preprocessing
意向不到的Dubug妙招
Exercise (1) create a set C1 to store the elements "one", "two", "three"“
指针函数的demo
Interview focus - TCP protocol of transport layer
ABAP 代码中读取会计科目的字段状态(隐藏、可选、必输)
typescript ts 基础知识之类
在应用中使用 Jetpack 库
智牛股--09
Array merge method: concat()
Storage of data in memory
Find the cause of program dead cycle through debugging
Taobao Search case
Several ways of writing strings in reverse order
Programmer interview Golden Classic 4.12 summation path
MySQL的DDL、DML和DQL的基本语法
[nodejs] nodejs create a simple server
Bubble sort idea and Implementation
疫情之下的好消息