【Spring註解】四、自動裝配@Autowired&@Resource

四、自動裝配

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);
         }
      }
   }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章