“This is the 10th day of my participation in the Gwen Challenge in November. Check out the details: The Last Gwen Challenge in 2021.”

Resource-CommonAnnotationBeanPP

Two optional values for the Resource annotation:

  • name = “?”
  • type = ? .class

The structure is the same:

  • Find the injection point (@Resource)

    • Here, the findResourceMetadata call to buildMetadata returns an error if it resolves to a static field annotated by @Resource, whereas autowired does not.
@Override public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<? > beanType, String beanName) { super.postProcessMergedBeanDefinition(beanDefinition, beanType, beanName); InjectionMetadata metadata = findResourceMetadata(beanName, beanType, null); metadata.checkConfigMembers(beanDefinition); }Copy the code

The Element implementation class of metadata is ResourceElement:

public ResourceElement(Member member, AnnotatedElement ae, @Nullable PropertyDescriptor pd) { super(member, pd); Resource resource = ae.getAnnotation(Resource.class); // Here is the value of the annotation String resourceName = resource.name(); Class<? > resourceType = resource.type(); This.isdefaultname =! This.isdefaultname =! StringUtils.hasLength(resourceName); if (this.isDefaultName) { resourceName = this.member.getName(); // If the name of the resource has a set, If (this.member instanceof Method && resourcename.startswith ("set") && resourcename.length () > 3) {if (this.member instanceof Method && resourcename.startswith ("set") && resourcename.length () > 3) { resourceName = Introspector.decapitalize(resourceName.substring(3)); } } else if (embeddedValueResolver ! = null) { resourceName = embeddedValueResolver.resolveStringValue(resourceName); } //Object is the default value of type, which checks to see if it matches if (object.class! = resourceType) { checkResourceType(resourceType); } else { // No resource type specified... check field/method. resourceType = getResourceType(); } this.name = (resourceName ! = null ? resourceName : ""); this.lookupType = resourceType; String lookupValue = resource.lookup(); this.mappedName = (StringUtils.hasLength(lookupValue) ? lookupValue : resource.mappedName()); Lazy lazy = ae.getannotation (lazy.class); this.lazyLookup = (lazy ! = null && lazy.value()); }Copy the code
  • Field property injection

    • Inject here is implemented by the parent class
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
   InjectionMetadata metadata = findResourceMetadata(beanName, bean.getClass(), pvs);
   try {
       // Two auto-injected PPS are similar
      metadata.inject(bean, beanName, pvs);
   }
   catch (Throwable ex) {
      throw new BeanCreationException(beanName, "Injection of resource dependencies failed", ex);
   }
   return pvs;
}

		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) {
					throwex.getTargetException(); }}}// Implement getResourceToInject in subclasses:
		protected Object getResourceToInject(Object target, @Nullable String requestingBeanName) {
            // Lazy is used to construct proxy objects, similar to autowired
            // Next up is getResource
			return (this.lazyLookup ? buildLazyResourceProxy(this, requestingBeanName) :
					getResource(this, requestingBeanName));
		}


protected Object getResource(LookupElement element, @Nullable String requestingBeanName)
			throws NoSuchBeanDefinitionException {
		/ / jndi, ejb related
		if (StringUtils.hasLength(element.mappedName)) {
			return this.jndiFactory.getBean(element.mappedName, element.lookupType);
		}
		if (this.alwaysUseJndiLookup) {
			return this.jndiFactory.getBean(element.name, element.lookupType);
		}
		if (this.resourceFactory == null) {
			throw new NoSuchBeanDefinitionException(element.lookupType,
					"No resource factory configured - specify the 'resourceFactory' property");
		}
    // Normal is just straight here
		return autowireResource(this.resourceFactory, element, requestingBeanName);
	}



protected Object autowireResource(BeanFactory factory, LookupElement element, @Nullable String requestingBeanName)
			throws NoSuchBeanDefinitionException {

		Object resource;
		Set<String> autowiredBeanNames;
		String name = element.name;
// Default's BF is of this class
		if (factory instanceof AutowireCapableBeanFactory) {
			AutowireCapableBeanFactory beanFactory = (AutowireCapableBeanFactory) factory;
			DependencyDescriptor descriptor = element.getDependencyDescriptor();
            
            // The core logic for the @resource lookup bean is here
            // isDefaultname is the value of the attribute name
            // Check the bean factory to see if there are any beans, and resolve if there are none
            Before / / fallbackToDefaultTypeMatch, refers to whether can find the corresponding bean by class type
			if (this.fallbackToDefaultTypeMatch && element.isDefaultName && ! factory.containsBean(name)) { autowiredBeanNames =new LinkedHashSet<>();
				resource = beanFactory.resolveDependency(descriptor, requestingBeanName, autowiredBeanNames, null);
				if (resource == null) {
					throw new NoSuchBeanDefinitionException(element.getLookupType(), "No resolvable resource object"); }}// If the bean is included, or if the annotation contains the name of the bean, it can be obtained directly from BF
			else{ resource = beanFactory.resolveBeanByName(name, descriptor); autowiredBeanNames = Collections.singleton(name); }}else {
			resource = factory.getBean(name, element.lookupType);
			autowiredBeanNames = Collections.singleton(name);
		}

		if (factory instanceof ConfigurableBeanFactory) {
			ConfigurableBeanFactory beanFactory = (ConfigurableBeanFactory) factory;
			for (String autowiredBeanName : autowiredBeanNames) {
				if(requestingBeanName ! =null&& beanFactory.containsBean(autowiredBeanName)) { beanFactory.registerDependentBean(autowiredBeanName, requestingBeanName); }}}return resource;
	}
Copy the code

conclusion

Dependency injection IOC selection steps:

@Autowired
private Object resource;
Copy the code
  1. First look for beans by type

  2. Screening:

    • candidate=true?

    • Is it generic?

    • The Qualifier? (@qualifier can modify beans, if any, and the corresponding @autoWired will preferentially select the bean with the same name specified by this annotation if specified by the same name.)

    • Primary does not exist?

    • Priority from small to big?

    • The name

  • Autowire and Resource:
    • autowired:
      • The static variable, autowired, is skipped
      • First by type, then by name
      • Spring provides
    • resource:
      • Static variable resource, an error
      • First by name, then by type
      • Provide the javax.mail