The IoC Container 1.9.3-1.9.8

1.9.3. Fine-tuning Annotation-based Autowiring with @Primary

在有多个装配候选人的情况下,如果是基于类型进行装配,会出现歧义,可以用@Primary指定相应的bean定义,表示优先使用该候选人进行自动装配。
如下,使用@Primary注解firstMovieCatalog,表示优先使用该bean定义:

@Configuration
public class MovieConfiguration {

    @Bean
    @Primary
    public MovieCatalog firstMovieCatalog() { ... }

    @Bean
    public MovieCatalog secondMovieCatalog() { ... }

    // ...
}

下面代码在上面配置的作用下,movieCatalog会使用firstMovieCatalog进行自动装配:

public class MovieRecommender {

    @Autowired
    private MovieCatalog movieCatalog;

    // ...
}

以上注解配置对应的xml配置如下:




    
    

    
        
    

    
        
    

    


1.9.4. Fine-tuning Annotation-based Autowiring with Qualifiers

@Qualifier注解可以更精确的控制自动装配的对象。下面的示例表示movieCatalog会自动装配Qualifier注解值为main的对象:

public class MovieRecommender {

    @Autowired
    @Qualifier("main")
    private MovieCatalog movieCatalog;

    // ...
}

如果构造函数实例化可以像下面这样定义:

public class MovieRecommender {

    private MovieCatalog movieCatalog;

    private CustomerPreferenceDao customerPreferenceDao;

    @Autowired
    public void prepare(@Qualifier("main")MovieCatalog movieCatalog,
            CustomerPreferenceDao customerPreferenceDao) {
        this.movieCatalog = movieCatalog;
        this.customerPreferenceDao = customerPreferenceDao;
    }

    // ...
}

被装配的对象在xml中这样定义:




    

    
         

        
    

    
         

        
    

    


相当于在被装配对象和自动装配处都指定qualifier的value,如果value值可以两方可以对应上,那么就选择这个bean进行装配,上述例子中,movieCatalog自动装配的就是SimpleMovieCatalog1。

基于注解的配置方式如下:

package examples;

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

@Component
@Qualifier("main")
public class SimpleMovieCatalog1 implements MovieCatalog {
}

如果在自动装配字段上使用@Qualifier注解,但是不提供@Qualifier注解的value值,Spring会默认使用bean name作为value的值(然而,Spring默认就是按照bean name进行匹配的,所以如果用户想按照bean name匹配,则不需要用到@Qualifier注解)。实际上,@Qualifier注解在寻找装配对象的候选人时,依然是按照类型来匹配,也就意味着,可以多个bean拥有相同的Qualifier的value,这种情况下,可以用来装配集合类型,比如Set,所有具有相同Qualifier值的MovieCatalog对象都会被放入Set,进行对象的自动装配。
自动装配注解配置:

    @Autowired
    @Qualifier("action")
    private Set movieCatalogSet;

候选人的注解配置:

package examples;

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

@Configuration
public class MovieConfiguration {

    @Bean
    @Primary
    @Qualifier("action")
    public MovieCatalog firstMovieCatalog() {
        return new MovieCatalog() {
            @Override
            public int hashCode() {
                return super.hashCode();
            }
        };
    }

    @Bean
    @Qualifier("action")
    public MovieCatalog secondMovieCatalog() {
        return new MovieCatalog() {
            @Override
            public int hashCode() {
                return super.hashCode();
            }
        };
    }

    @Bean
    @Qualifier("action")
    public MovieCatalog qualiferMovieCatalog() {
        return new MovieCatalog() {
            @Override
            public int hashCode() {
                return super.hashCode();
            }
        };
    }
}

在自动装配完成后,movieCatalogSet中将包含上面三个@Qualifier("action")注解的MovieCatalog对象。

@Autowired和@Resource注解的使用场景:

@Autowired applies to fields, constructors, and multi-argument methods, allowing for narrowing through qualifier annotations at the parameter level. By contrast, @Resource is supported only for fields and bean property setter methods with a single argument. As a consequence, you should stick with qualifiers if your injection target is a constructor or a multi-argument method.

Spring还支持自定义@Qualifier注解:

@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface Genre {

    String value();
}

用法跟@Qualifier注解相同:

public class MovieRecommender {

    @Autowired
    @Genre("Action")
    private MovieCatalog actionCatalog;

    private MovieCatalog comedyCatalog;

    @Autowired
    public void setComedyCatalog(@Genre("Comedy") MovieCatalog comedyCatalog) {
        this.comedyCatalog = comedyCatalog;
    }

    // ...
}

xml配置中将候选人的qualifier type设置成Genre或者类的完全限定名,value还跟之前的意义相同:




    

    
        
        
    

    
        
        
    

    


在某些情况下,不带value值的自定义注解就足够用了,那么直接如下定义即可:

@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface Offline {

}
public class MovieRecommender {

    @Autowired
    @Offline 
    private MovieCatalog offlineCatalog;

    // ...
}

     
    

Spring还支持自定义@Qualifier注解时新增属性:

@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface MovieQualifier {

    String genre();

    Format format();
}
public enum Format {
    VHS, DVD, BLURAY
}

这样可以做更加细粒度的控制:

public class MovieRecommender {

    @Autowired
    @MovieQualifier(format=Format.VHS, genre="Action")
    private MovieCatalog actionVhsCatalog;

    @Autowired
    @MovieQualifier(format=Format.VHS, genre="Comedy")
    private MovieCatalog comedyVhsCatalog;

    @Autowired
    @MovieQualifier(format=Format.DVD, genre="Action")
    private MovieCatalog actionDvdCatalog;

    @Autowired
    @MovieQualifier(format=Format.BLURAY, genre="Comedy")
    private MovieCatalog comedyBluRayCatalog;

    // ...
}

xml配置候选人时,有两种配置方式(qualifier和meta两种):




    

    
        
            
            
        
        
    

    
        
            
            
        
        
    

    
        
        
        
    

    
        
        
        
    


1.9.5. Using Generics as Autowiring Qualifiers

使用泛型作为自动装配候选人:

public interface Store {

}
@Configuration
public class MyConfiguration {

    @Bean
    public StringStore stringStore() {
        return new StringStore();
    }

    @Bean
    public IntegerStore integerStore() {
        return new IntegerStore();
    }
}
@Component
public class StringStore implements Store {
    
}
@Component
public class IntegerStore implements Store {
    
}

通过@Autowire实现泛型的自动装配:

    @Autowired
    private Store s1; //  qualifier, injects the stringStore bean

    @Autowired
    private Store s2; //  qualifier, injects the integerStore bean

1.9.6. Using CustomAutowireConfigurer

之前通过继承@Qualifier注解实现自定义@Qualifier注解,本节提供一种方式,在不继承@Qualifier注解的情况下,同样可以自定义qualifier annotation type。通过以下方式注册任意注解后,该注解就可以支持qualifier annotation type:


    
        
            examples.CustomQualifier
        
    

The AutowireCandidateResolver determines autowire candidates by(AutowireCandidateResolver决定装配对象的流程):

  • The autowire-candidate value of each bean definition
  • Any default-autowire-candidates patterns available on the element
  • The presence of @Qualifier annotations and any custom annotations registered with the CustomAutowireConfigurer

1.9.7. Injection with @Resource

@Resource是JSR-250支持的注解,可以用来注解字段或者setter方法。Spring也支持@Resource注解。

public class SimpleMovieLister {

    private MovieFinder movieFinder;

    @Resource(name="myMovieFinder") 
    public void setMovieFinder(MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }
}

@Resource注解的属性是name,name指定bean的名称,所以@Resource是autowire by name的,如果不指定name,默认从setter方法或者字段推导出相应的name。
推导规则如下:

If no name is explicitly specified, the default name is derived from the field name or setter method. In case of a field, it takes the field name. In case of a setter method, it takes the bean property name.

大多数情况下,@Resource和@Autowired功能类似:

public class MovieRecommender {

    @Resource
    private CustomerPreferenceDao customerPreferenceDao;

    @Resource
    private ApplicationContext context; 

    public MovieRecommender() {
    }

    // ...
}

1.9.8. Using @PostConstruct and @PreDestroy

javax.annotation.PostConstruct 和javax.annotation.PreDestroy也是JSR-250的标准。Spring同样支持这两个注解。

public class CachingMovieLister {

    @PostConstruct
    public void populateMovieCache() {
        // populates the movie cache upon initialization...
    }

    @PreDestroy
    public void clearMovieCache() {
        // clears the movie cache upon destruction...
    }
}

@PostConstruct,@PreDestroy和@Resource都是由CommonAnnotationBeanPostProcessor处理的

@PostConstruct,@PreDestroy和@Resource注解在JAVA9之后已经删除,如果需要引用,需要到maven下载第三方包

你可能感兴趣的:(The IoC Container 1.9.3-1.9.8)