摘录一些Spring文档的内容(二)

2017-08-29  本文已影响0人  回忆之秋

基于注释的容器配置

通过基于注解的配置提供了XML设置的替代方法,该配置依赖于元数据(metadata)来连接组件。

注解

<context:annotation-config/>
只会在同一应用上下文寻找bean定义,所以,在WebApplicationContext中使用<context:annotation-config/>,它只会检查在Controller层标记@Autowired声明的bean而不会到你的Service层中去找(因此Controller和Service都要分别定义<context:annotation-config/>)
注意:<context:annotation-config/>和<context:component-scan>的区别

public class SimpleMovieLister {

    private MovieFinder movieFinder;

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

    // ...

}

注意
如果你用java config形式配置bean的话@Required是不起作用的
https://stackoverflow.com/questions/16769360/how-does-required-annotation-work-with-javaconfig)

So, to summarize: @Required
doesn't work with @Configuration
classes by default. If you need to make sure that all your properties are set, you can just as well do it yourself when you create the bean in the @Bean
methods (By calling some init
method that performs such validations, or just supplying the required properties yourself). And if you really need to make the @Required
annotation work, you'd need to use your own implementation of the RequiredAnnotationBeanPostProcessor
, register it as a bean in the spring context and give up the benefits of context:annotation-config
.

public class MovieRecommender {

    @Autowired
    private MovieCatalog[] movieCatalogs;

    // ...

}

注意
Map类型需要key为String类型才能被注入,key值会对应bean名称。容器会将符合类型的bean都注入到map中,其中key值就是对应的bean名称。

public class MovieRecommender {

    @Autowired
    private ApplicationContext context;

    public MovieRecommender() {
    }

    // ...

}
@Configuration
public class MovieConfiguration {

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

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

    // ...

}
public class MovieRecommender {

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

    // ...

}

@Qualifier也可以标注在单独的构造器参数或方法参数上。

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 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 value="main"/>

        <!-- inject any dependencies required by this bean -->
    </bean>

    <bean class="example.SimpleMovieCatalog">
        <qualifier value="action"/>

        <!-- inject any dependencies required by this bean -->
    </bean>

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

</beans>

限定符也适用于类型化的集合,如上所述,例如 Set<MovieCatalog>。在这种情况下,根据声明的限定符的所有匹配的bean将作为集合进行注入。这意味着限定词不一定是唯一的; 它们只是构成过滤标准。例如,您可以MovieCatalog使用相同的限定符值“action” 定义多个bean,所有这些bean都将注入到Set<MovieCatalog>注释中@Qualifier("action")。

注意
如果你打算按名称注入Bean,不要用@Autowired,请使用@Resource(JSR-250定义的)

public class MovieRecommender {

    @Resource
    private CustomerPreferenceDao customerPreferenceDao;

    @Resource
    private ApplicationContext context;

    public MovieRecommender() {
    }

    // ...

}


以上几个注解,我都做了相应的练习去验证https://github.com/wingofthestar/SpringLearn

位于site.yourdiary.anno目录下


目录.png

@Controller、@Service、@Repository、@Component
@Component是标志着任何被Spring管理的组件(Bean)
@Repository, @Service, @Controller是对于@Component更具体的特定用例的组件。

你可以用 @Component注解组件类,但如果用@Repository,@Service或者@Controller ,你的类有可能能更好地被工具处理,或与切面进行关联。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component // Spring will see this and treat @Service in the same way as @Component
public @interface Service {

    // ....
}

元注解可以组合成组合注解,就比如在SpringMVC中@RestController就是由@Controller和@ResponseBody组合而成的。

@Service
public class SimpleMovieLister {

    private MovieFinder movieFinder;

    @Autowired
    public SimpleMovieLister(MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }

}
@Repository
public class JpaMovieFinder implements MovieFinder {
    // implementation elided for clarity
}

为了自动检测这些类,并且注册相应的Bean,你需要添加在@Configuration类上标注@ComponentScan,并且标记basePackages属性为这两个类的父包。(也可以用逗号、分号、空格分隔的列出每个class的父包)。

java config写法

@Configuration
@ComponentScan(basePackages = "org.example")
public class AppConfig  {
    ...
}

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:component-scan base-package="org.example"/>

</beans>

注意
<context:component-scan>启用(包含)了<context:annotation-config>的功能,所以使用了<context:component-scan>就不需要再添加<context:component-scan>

Furthermore, the AutowiredAnnotationBeanPostProcessor and CommonAnnotationBeanPostProcessor are both included implicitly when you use the component-scan element. That means that the two components are autodetected and wired together - all without any bean configuration metadata provided in XML.

AutowiredAnnotationBeanPostProcessor和CommonAnnotationBeanPostProcessor也同时被自动检测到并注册

使用过滤器自定义扫描(路径)

过滤器类型.png

下面的例子展示了configuration忽略了所有@Repository注解,并用"stub" respositories

@Configuration
@ComponentScan(basePackages = "org.example",
        includeFilters = @Filter(type = FilterType.REGEX, pattern = ".*Stub.*Repository"),
        excludeFilters = @Filter(Repository.class))
public class AppConfig {
    ...
}
<beans>
    <context:component-scan base-package="org.example">
        <context:include-filter type="regex"
                expression=".*Stub.*Repository"/>
        <context:exclude-filter type="annotation"
                expression="org.springframework.stereotype.Repository"/>
    </context:component-scan>
</beans>

使用JSR-330标准注解

从Spring 3.0开始,提供对JSR-330标准注释(依赖注入)的支持。这些注释以与Spring注释相同的方式进行扫描。你只需要在你的classpath中有相关的jar。

可以在maven的pom.xml中添加

<dependency>
    <groupId>javax.inject</groupId>
    <artifactId>javax.inject</artifactId>
    <version>1</version>
</dependency>
import javax.inject.Inject;
import javax.inject.Named;

public class SimpleMovieLister {

    private MovieFinder movieFinder;

    @Inject
    public void setMovieFinder(@Named("main") MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }

    // ...
}
import javax.inject.Inject;
import javax.inject.Named;

@Named("movieListener") // @ManagedBean("movieListener") could be used as well
public class SimpleMovieLister {

    private MovieFinder movieFinder;

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

    // ...
}

当使用@Named或@ManagedBean时可以使用与使用Spring注解完全相同的组件扫描

@Configuration
@ComponentScan(basePackages = "org.example")
public class AppConfig  {
    ...
}
Spring注解与JSR-330 标准注解的对比.png
上一篇 下一篇

猜你喜欢

热点阅读