四、自动装配

1.@Autowried&@Qualifier和@Primary

@Autowried是Spring2.5定义的自动装配的注解,它可以对类成员变量、方法及构造函数进行标注,完成自动装配的工作。 使用 @Autowired的使用来消除 set ,get方法。@Autowired 标注在方法上表示当前方法的自定义参数从容器中赋值,ioc容器默认赋值时,需要调用无参构造器后,再进行默认赋值,如果当前类只有一个有参的构造器,则@Autwried可以省略,并且该构造器的参数也默认从ioc容器中获取。

我们创建Color接口、以及它的实现类Red和Bule来介绍@Autowried&@Qualifier和@Primary的用法

Color接口

public interface Color {
}

Red实现类

@Component
public class Red implements Color {
    public Red() {
        System.out.println("这是Red的 构造器");

    }
}

Flower类

@Component
public class Flower {
    @Autowired
    private Color color;

    @Override
    public String toString() {
        return "Folwer{" +"color=" + color +'}';
    }
}

配置类 AutowriedConfig

@Configuration
@ComponentScan("com.daxiong.pojo.Autowired")
public class AutowriedConfig {
}

测试类

public class AutowriedConfigTest {
    private AnnotationConfigApplicationContext  annotationConfigApplicationContext = new AnnotationConfigApplicationContext(AutowriedConfig.class);

    @Test
    public void testAutowired1() {
        Flower bean = annotationConfigApplicationContext.getBean(Flower.class);
        System.out.println(bean);
    }
}

此时我们只在Spring容器中注入的一个Color的实现类Red,测试结果

只有red类时

添加Bule类

@Component
public class Bule implements Color {
    public Bule() {
        System.out.println("这是Bule 的 构造器");
    }
}

运行结果:

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'flower': Unsatisfied dependency expressed through field 'color'; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.daxiong.pojo.Autowired.Color' available: expected single matching bean but found 2: bule,red
.....
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.daxiong.pojo.Autowired.Color' available: expected single matching bean but found 2: bule,red

出现No qualifying bean of type ‘com.daxiong.pojo.Autowired.Color’ available的异常,原因是@Autowried是按照类型注入的,我们在Flower中注入的Color对象没有指定类型,Spring容器不知道到底应该注入哪一个对象的原因。解决办法有以下几种方法:

  1. 使用@Qualifier注解,明确的指定注入类型

    @Qualifier(value="red")
    private Color color;

  2. 使用@Primary注解,默认指定的类型

    @Primary
    @Component
    public class Red implements Color {
       public Red() {
           System.out.println("这是Red的 构造器");
    
       }
    }
  3. 修改参数名

    @Component
    public class Flower {
        //修改color的属性名为red
       @Autowired
       private Color red;
    
       @Override
       public String toString() {
           return "Folwer{" +"color=" + red +'}';
       }
    

    运行结果:

    @Qualifier

注意点:

如果在自动装配时。Spring容器中没有注册对应的Bean,就会报错

Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.daxiong.pojo.Autowired.Color' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}

我们也只需要在@Autowried后加上(required=true)即可

2.@Resource&@Inject

@Resource和@Inject分别是在JSR250和JSR330规范中定义的注解,在Spring中也得到了支持使用方法和@Autowried的类似

@Resource默认是按照属性来装配的,没有支持@Primary和reuired

@Inject支持@Primary,但时不支持reuired,需要导入javax.Inject包

3.Aware注入Spring底层组件&原理

自定义组件想要使用Spring容器底层的一些组件比如ApplicationContext,BeanFactory,等等,都可以通过实现XXXAware,在创建对象时,会把调用接口规定的方法把指定的组件装配进去。

实现原理,这些XXXAware接口,都有对应的XXXprocessor来处理

如ApplicationContextAware有ApplicationContextAwareProcessor来处理Spring源码:

 //实现了BeanPostProcessor接口,所以会在组件初始化的识货调用
class ApplicationContextAwareProcessor implements BeanPostProcessor {
  //在组件赋值前调用 
  @Override
   public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {
      AccessControlContext acc = null;
     //判断是否为对应接口类型
      if (System.getSecurityManager() != null &&
            (bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
                  bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
                  bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)) {
         acc = this.applicationContext.getBeanFactory().getAccessControlContext();
      }

      if (acc != null) {
         AccessController.doPrivileged(new PrivilegedAction<Object>() {
            @Override
            public Object run() {
               invokeAwareInterfaces(bean);
               return null;
            }
         }, acc);
      }
      else {
        //进行赋值操作
         invokeAwareInterfaces(bean);
      }

      return bean;
   }

   private void invokeAwareInterfaces(Object bean) {
     //对应的接口进行赋值操作
      if (bean instanceof Aware) {
         if (bean instanceof EnvironmentAware) {
            ((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
         }
         if (bean instanceof EmbeddedValueResolverAware) {
            ((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
         }
         if (bean instanceof ResourceLoaderAware) {
            ((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
         }
         if (bean instanceof ApplicationEventPublisherAware) {
            ((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
         }
         if (bean instanceof MessageSourceAware) {
            ((MessageSourceAware) bean).setMessageSource(this.applicationContext);
         }
         if (bean instanceof ApplicationContextAware) {
            ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
         }
      }
   }
}
Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐