注解@Autowired源码解析
@Autowired自动装配
在不使用xml配置文件时,@Autowired是我们使用最多的注解之一,关于该注解的原理如下:
@Autowired原理:在启动springIoC时,容器自动装载了一个AutowiredAnnotationBeanPostProcessor后置处理器,当容器扫描到@Autowied、@Resource或@Inject时,就会在IoC容器自动查找需要的bean,并装配给该对象的属性。
在使用@Autowired时,首先在容器中查询对应类型的bean
如果查询结果刚好为一个,就将该bean装配给@Autowired指定的数据(byType)
如果查询的结果不止一个,那么@Autowired会根据名(byName)称来查找。
如果查询的结果为空,那么会抛出异常。解决方法时,使用@Autowired(required=false)
而关于@Autowired的用法,我总结了一下三点:
1.用在字段上
@Autowired用在字段上时,表示Spring会对改字段进行匹配赋值,在Spring容器中查找(byType),找到能匹配到该字段的对象,然后进行赋值;如果未找到就爆出异常,可以指定required=false允许字段值为null解决报错。
2.用在set方法上
@Autowired用在字段上时,会找到改set方法对应的字段,然后其过程与其一致。
3.用在构造方法上
@Autowired用在构造方法上时,会找到改构造方法对应的所有字段,然后其过程与字段一致。
元信息解析:
在处理过程中,有一个类叫DependencyDescriptor,比如说我们的依赖描述器或者依赖描述符,那个里面就记录了我们注入的对象是关于那个字段,比如说我的字段名称以及它的字段相关的元信息,就是我们说java发射一个field字段,这个部分了解完之后它就会把相关的信息包括类所有的信息全部加入进来,帮助我们去分析,包括它的一个字段类型或者方法里面参数类型等等
依赖查找,依赖查找其实就是依赖处理
依赖注入,@autowired可以注入在字段和方法里面,
这个就是@Autowired的一个操作思路:解析谁要进行注入==》查找依赖的来源==》注入的一个对象。
现在还是上源码,注意看注释部分
一、@Autowired的源码,通过源码可以看到他可以应用在方法、字段、注解等
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;
}
二、注解的实现类:AutowiredAnnotationBeanPostProcessor,通过它的构造方法,可以看到它不仅支持@Autowired还支持@Value注解。
public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapterimplements MergedBeanDefinitionPostProcessor, PriorityOrdered, BeanFactoryAware { //省略部分代码/*** Create a new {@code AutowiredAnnotationBeanPostProcessor} for Spring's* standard {@link Autowired @Autowired} and {@link Value @Value} annotations.* 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.}}
}
三、还是AutowiredAnnotationBeanPostProcessor,它实现了接口类MergedBeanDefinitionPostProcessor的方法postProcessMergedBeanDefinition,这个方法是合并我们定义类的信息,比如:一个类集成了其它类,这个方法会把父类属性和信息合并到子类中。代码如下:
@Overridepublic void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class> beanType, String beanName) {//查找注解的元信息,传入了bean的名称、类型InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);metadata.checkConfigMembers(beanDefinition);}/****查找注解元信息*/private InjectionMetadata findAutowiringMetadata(String beanName, Class> clazz, @Nullable PropertyValues pvs) {// Fall back to class name as cache key, for backwards compatibility with custom callers.//先读缓存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);}//把查找出来的元信息进行构建metadata = buildAutowiringMetadata(clazz);this.injectionMetadataCache.put(cacheKey, metadata);}}}return metadata;}//构建注解元信息
private InjectionMetadata buildAutowiringMetadata(final Class> clazz) {//判断是否符合条件注解类型(@AutoWired和@Value)if (!AnnotationUtils.isCandidateClass(clazz, this.autowiredAnnotationTypes)) {return InjectionMetadata.EMPTY;}List elements = new ArrayList<>();Class> targetClass = clazz;do {final List currElements = new ArrayList<>();//先处理注解字段ReflectionUtils.doWithLocalFields(targetClass, field -> {//是不是要找的字段MergedAnnotation> ann = findAutowiredAnnotation(field);if (ann != null) {//静态字段不支持@Autowiredif (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));}});//再处理注解方法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不支持静态方法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;@Nullableprivate volatile Object cachedFieldValue;public AutowiredFieldElement(Field field, boolean required) {super(field, null);this.required = required;}@Overrideprotected 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 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;@Nullableprivate volatile Object[] cachedMethodArguments;public AutowiredMethodElement(Method method, boolean required, @Nullable PropertyDescriptor pd) {super(method, pd);this.required = required;}@Overrideprotected 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 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 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();}}}@Nullableprivate 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;}}
这个方法找到了所有需要注解注入的元信息并进行解析,这个过程也是一个依赖查找过程。至于注入的过程是怎么调用的呐,接下来看这个方法:
//属性处理过程,元信息查找、解析、注入@Overridepublic PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {//元信息查找、解析,在上一步已经分析过了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;}public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {Collection checkedElements = this.checkedElements;Collection 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);}//注入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 {//字段注入if (this.isField) {Field field = (Field) this.member;//设置字段权限为可以访问权限ReflectionUtils.makeAccessible(field);field.set(target, getResourceToInject(target, requestingBeanName));}else {//方法注入if (checkPropertySkipping(pvs)) {return;}try {Method method = (Method) this.member;//设置方法权限为可以访问权限ReflectionUtils.makeAccessible(method);method.invoke(target, getResourceToInject(target, requestingBeanName));}catch (InvocationTargetException ex) {throw ex.getTargetException();}}}
经过上述分析,@Autowired注解,先通过postProcessMergedBeanDefinition方法->findAutowiringMetadata方法分析查找元信息,并且经过反射写入类信息,再次通过inject方法进行注入。
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
