IoC容器篇(八)——基于注解的容器配置

目录

基于注解的容器配置

1.@Required

2.@Autowired

3.通过@Primary调控基于注解的自动注解

4.通过修饰语调控基于注解的自动注解

学习源:Spring官方文档


基于注解的容器配置

基于注解的配置方法提供了大量的声明用以使配置简洁,但是配置分散难以管理。

基于xml的配置方法在不触及与重编译源代码的情况下,装配组件。

通过使用JavaConfig,可以使得注解配置在没有侵入性的情况下使用,并且不会触及到组件源代码。

注解注入会在xml注入之前发生,因此后者配置将会重载前者。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

    <context:annotation-config/>

</beans>

note:启用基于注解的配置。

ps:<context:annotation-config/>会在它所有定义的应用上下文中的beans上的注解。

ps:如果在WebApplicationContext设置<context:annotation-config/>,它只会检查控制器上的@Autowired beans。

1.@Required

public class SimpleMovieLister {

    private MovieFinder movieFinder;

    @Required
    public void setMovieFinder(MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }

    // ...
}

ps:此注解表示,被影响的bean的属性必需在配置阶段通过bean定义中的显式属性值或自动装配被填充。

2.@Autowired

@Autowired用于byType自动注入依赖。

使用@Autowired进行依赖注入时,需要确保目标组件的类型与注入点的类型一致。

@Autowired、@Inject、@Resource与@Value这些注解的处理是基于BeanPostProcessor的实现达成的。所以,BeanPostProcessor与BeanFactoryPostProcessor类型不能使用这些注解,只能显式在xml或@Bean方法配置。

public class Exampel {

    private Foo foo;
    
    @Autowired
    public Example(Foo foo) {
        this.foo = foo;
    }
}

note:@Autowired用于构造器。

public class Exampel {

    private Foo foo;
    
    @Autowired
    public void setFoo(Foo foo) {
        this.foo = foo;
    }
}

note:@Autowired用于setter。

public class Exampel {

    private Foo foo;
    
    private Exa exa;
    
    @Autowired
    public void prepare(Foo foo, Exa exa) {
        this.foo = foo;
        this.exa = exa;
    }
}

note:@Autowired用于任意名称任意数量参数的方法。

public class Exampel {

    private Foo foo;
    
    @Autowired
    private Exa exa;
    
    @Autowired
    public void prepare(Foo foo) {
        this.foo = foo;
    }
}

note:@Autowired混合用于域以及构造器。

public class Example{
    
    @Autowired
    private Foo[] foos;
}

note:将ApplicationContext的中的所有Foo类型的bean,全部注入数组foos中。

public class Example{
    

    private Set<Foo> foos;

    @Autowired
    public void setFoos(Set<Foo> foos){
        this.foos = foos;
    }
}

note:将ApplicationContext的中的所有Foo类型的bean,全部注入set集合foos中。

ps:可以通过@Order注解的值或@Priority注解指定注入数组或list的bean的顺序,如果不指定,默认使用bean的注册顺序。

ps:@Order可以用于@Bean注解的方法上,@Priority只能用于class层次。

public class Example {

    private Map<String, Foo> fooMap;
    
    @Autowired
    public void setFooMap(Map<String, Foo> fooMap) {
        this.fooMap = fooMap
    }
}

note:将ApplicationContext中的所有Foo类型的bean作为value,而bean的名称作为key,全部注入fooMap中。

public class Example {

    private Foo foo;

    @Autowired(required = false)
    public void setFoo(Foo foo) {
        this.foo = foo;
    }
}

note:将自动注入设置为,自动注入时允许ApplicationContext中不存在类型为Foo的bean时,即不会因为没有候选bean,就抛出异常。

ps:@Autowired默认为required,即自动注入时不允许没有候选bean。

ps:当多个构造器都被注解为@Autowired时,Spring自动将满足最多参数的构造器设置为required。

public class Example {

    @Autowired
    public void setFoo(Optional<Foo> foo) {

    }
}

note:使用java.util.Optional,令指定依赖foo设置为non-required。

public class Example {

    @Autowired
    public void setFoo(@Nullable Foo foo) {

    }
}

note:使用javax.annotation.Nullable使得依赖foo设置为non-required。

public class Example {
    
    @Autowired
    private ApplicationContext context;

}

note:将ApplicationContext注入Example之中。

ps:Spring会自动解析注入well-known接口,eg:ApplicationContext、Environment、ResourceLoad、ApplicationEventPublisher、MessageSoure。

ps:这些接口的扩展也会被解析注入。eg:ConfigurableApplicationContext、ResourcePatternResolver。

3.通过@Primary调控基于注解的自动注解

byType的自动装配可能会出现同一类型出现多个候选bean的状况,通常通过加强对选择过程的控制来处理这一状况。

@Configuration
public class ExampleConfig{
    
    @Bean
    @Primary
    public Foo firstFoo(){ return new Foo(); }

    
    @Bean
    public Foo secondFoo() { return new Foo(); }
}
public class Example {

    @Autowired
    private Foo foo;
}

note:firstFoo()返回的bean会被装配进Example中的foo属性。

ps:@Primary与基于xml配置的bean元素的primary="true"属性配置相同。

4.通过修饰语调控基于注解的自动注解

public class Example{
    
    @Autowired
    @Qualifier("foo")
    private Foo foo;

}

note:将标记为foo的bean注入Example的foo属性。

public class Example{

    private Foo foo;
    private Exa exa;

    @Autowired
    public void prepare(@Qualifier("foo")Foo foo, Exa exa) {
        this.foo = foo;
        this.exa = exa;
    }
}

note:将标记为foo的bea注入Example的prepare方法的foo参数。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

    <context:annotation-config/>

    <bean class="examples.Foo">
        <qualifier value="foo>
    </bean>

    <bean class="examples.Foo">
        <qualifier value="opt"/>
    </bean>

    <bean id="example" class="examples.Example"/>

</beans>

ps:bean 名称为默认的修饰语值。

ps:使用自动装配向集合、list中注入多个依赖时,可以将需要注入的众多依赖使用qualifier的值筛选出来。

ps:如果在使用自动装配时,没有指定@Qualifer或@Primary,并且存在多个候选bean,Spring会针对目标bean匹配注入点名称,将存在的同名bean注入。

ps:@Resource用于byName注入。

ps:容器数组类型的bean可以通过@Autowired直接作为依赖注入依赖为容器数组类型的bean之中。

ps:@Autowired允许自我注入,但在存在其他候选bean时,优先使用其他bean。自我注入只是最后的手段。

ps:可以使用@Resource进行自我注入。

ps:@Resource只支持域与只有一个参数的setter方法。

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

    String value();
}
public class MovieRecommender {

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

    private MovieCatalog comedyCatalog;

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

    // ...
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

    <context:annotation-config/>

    <bean class="example.SimpleMovieCatalog">
        <qualifier type="Genre" value="Action"/>
        <!-- inject any dependencies required by this bean -->
    </bean>

    <bean class="example.SimpleMovieCatalog">
        <qualifier type="example.Genre" value="Comedy"/>
        <!-- inject any dependencies required by this bean -->
    </bean>

    <bean id="movieRecommender" class="example.MovieRecommender"/>

</beans>

note:自定义一个可以注解域域方法参数的Qualifier注解,名为Genre。

ps:在xml配置元数据中标识使用的自定义@Qualifier注解时,可以使用完整修饰语类名,也可以短类名,只要不会引起冲突。

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

}
public class MovieRecommender {

    @Autowired
    @Offline
    private MovieCatalog offlineCatalog;

    // ...
}

note:定义一个不需要参数的@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 version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

    <context:annotation-config/>

    <bean class="example.SimpleMovieCatalog">
        <qualifier type="MovieQualifier">
            <attribute key="format" value="VHS"/>
            <attribute key="genre" value="Action"/>
        </qualifier>
        <!-- inject any dependencies required by this bean -->
    </bean>

    <bean class="example.SimpleMovieCatalog">
        <qualifier type="MovieQualifier">
            <attribute key="format" value="VHS"/>
            <attribute key="genre" value="Comedy"/>
        </qualifier>
        <!-- inject any dependencies required by this bean -->
    </bean>

    <bean class="example.SimpleMovieCatalog">
        <meta key="format" value="DVD"/>
        <meta key="genre" value="Action"/>
        <!-- inject any dependencies required by this bean -->
    </bean>

    <bean class="example.SimpleMovieCatalog">
        <meta key="format" value="BLURAY"/>
        <meta key="genre" value="Comedy"/>
        <!-- inject any dependencies required by this bean -->
    </bean>

</beans>

note:定义一个需要多个命名的属性的@Qualifier注解@MovieQualifier。

ps:子定义的多属性@Qualifier在匹配时,需要将所有的属性全部匹配。

ps:<qualifier/>元素在匹配时占有优先地位,如果<qualifier/>元素无法匹配到所需的bean时,开始使用<meta>进行匹配。
 


学习源:Spring官方文档

猜你喜欢

转载自blog.csdn.net/qq_32165041/article/details/82502294