spring-ioc-annotation

####7.9基于注解的容器配置 ####前言:注解配置好还是xml配置好? 二者各有千秋.

  • 注解配置:更短更简洁,缺点:配置分散,不宜管理;需要重新编译.
  • xml配置:不直接与代码交互,易于管理;缺点:冗长
  • 使用基于Java配置,可以更好的糅合双方的优点

在字节码文件里注入组件而不是角括号申明.开发者可以将注解添加在相关的类,方法,属性声明上从来注入依赖组件.使用bean后处理器来糅合注解是spring ioc 容器扩展的通用方式.例如,spring2.0引用了强制要求的@Required注解.值得一提的是,@Autowired注解提供了和7.4.5部分中的"Autowiring collaborators"相同的作用功能,但具有更好的控制和更广的应用.@PostConstruct,@PreDestroy,@Inject,@Named

你可以在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>

已详细注册的后处理器,包括AutowiredAnnotationBeanPostProcessor,CommonAnnotationBeanPostProcessor,PersistenceAnnotationBeanPostProcessor,RequiredAnnotationBeanPostProcessor;

context:annotation-config/只查找上下文中定义的注解. ####7.9.1 @Required 这个注解使用bean中属性的Setter方法;

	public class SimpleMovieLister {

		private MovieFinder movieFinder;

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

		// ...

	}

这个注解申明其标注的属性必须在配置时间被操作,通过一些指定值或通过自动装配.如果属性没有被操作,spring启动会有明确的失败,以避免之后的空指针异常.使用它可以保障必须引用.

####7.9.2 @Autowired @Inject注解可以替代@Autowired注解. 你可以使用@Inject注解来替代@Autowired注解;

可以在构造器中使用@Autowired注解

	public class MovieRecommender {

		private final CustomerPreferenceDao customerPreferenceDao;

		@Autowired
		public MovieRecommender(CustomerPreferenceDao customerPreferenceDao) {
			this.customerPreferenceDao = customerPreferenceDao;
		}

		// ...

	}

在spring4.3中,bean如果只定义了一个构造器,@Autowired注解没有使用必要.多个构造器才必须这么做.

  • 将@Autorwired注解标记在set方法上
  • 加在任何参数,任何名字的方法上
  • 加载数组类型上.
  • 加在集合类型参数上
  • 可以通过Orderder接口,@Order或@Priority注解来实现Array或list里元素排序
  • Map类型的参数,key是bean的名称,values包含bean的所有期待值

一般而言,如果没有可选的beans,那么注解将会失败,默认的行为是将该注解下的方法,字段,构造器视为必须的依赖,然可以如下改变它.


public class SimpleMovieLister {

    private MovieFinder movieFinder;

    @Autowired(required=false)
    public void setMovieFinder(MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }

    // ...

}

一个类只有一个构造器标志为required,但non-required的构造器可以有很多.这种情况下,为了使每一个候选者都会考虑,spring将会使用最贪婪的构造器(拥有最多的参数),这样依赖都会适配.

@Autowired注解里的Required属性,如果是false,表明如果无法注入,是可以接受的,不是必须的.如果是true,则是必须的,如果无法注入,容器无法启动

你可以用@Autowired来解决一些常用的依赖:Beanfactory,ApplicationContext,Environment,ResourceLoader,ApplicationEventPublisher,MessageSource.这些接口和他们的扩展接口,如ConfigurableApplicationContext,ResourcePatternResolver,都可以自注入.无需安装.

如@Autowired,@Inject,@Resource,@Value注解只能被spring的BeanPostProcessor实现处理,你自己的beanPostProcessor或BeanPostProcessor类型无法处理他们.这些类型必须由xml或spring的带有Bean的方法来注入.

因为自动注入可能会导致混合选项,所有有必要对其选择过程进行控制.一种方式是使用@Primary注解.@Primary表明一个特定的bean在很多同一类型的候选中,必须要选择该bean的实例注入.

@Configuration
public class MovieConfiguration {

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

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

    // ...

}

下文中注入的是名为firstMovieCatalog的bean的实例; public class MovieRecommender {

@Autowired
private MovieCatalog movieCatalog;

// ...

}

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/>

    <bean class="example.SimpleMovieCatalog" primary="true">
        <!-- inject any dependencies required by this bean -->
    </bean>

    <bean class="example.SimpleMovieCatalog">
        <!-- inject any dependencies required by this bean -->
    </bean>

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

</beans>

####7.9.4 Fine-tuning annotation-based autowiring with qualifiers(基于注解的候选者的自动注入的微调) @Qualifier是@Autowired控制的另一个工具.

  • 最简单的例子,Qualifier可以是一个简单的值

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;
		}

		// ...

	}

根据上面的的类定义,将会匹配qualifier的值为'mian'的bean

<?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>	

一般而言,bean的名字会默认是qualifier的值.因此,你可以使用'main'来替代内嵌的限定元素(它会导致相同的匹配结果).然而,尽管你可以使用本公约以名字来制定特定的bean,然@Autowired实际上是类型驱动注入包含语义限制的.这意味着限定符的值,同bean的名字回收,通常只是窄化类型匹配的集合;他们没有从语法上指向一个独一无二的bean的id.好的限制符,如'main','EMEA'或者'persistent',表达了一个特定的不同于bean的id的独立组件,毕竟bean的id会在匿名的bean定义里自动产生;

Qualifiers也适用于类型集合,例如,上文所说的Set<MovieCatalog>.在这种情况下,所有匹配的bean会依据宣布的匹配符注入为一个集合.它表明限制符不是唯一的,他们只是简单的构成过滤条件.例如,你可以定义混合的MovieCatalog的bean以相同的限制符'action'.所有的符合@Qualifier("action")条件的bean将注入到Set<MovieCatalog>集合里.

  • 如果你要倾向于通过名字的注解驱动注入,不推荐@Autowired,即使通过@Qualifier值来指向一个bean是技术可行的.你应该使用@Resource注解,它在语义上通过唯一的名字来定义目标的组件,而他们的申明类型并不会参与匹配.@Atuowired则是另外的语义:通过类型选择候选者之后,才会考虑特定的string的qualifier的值,只有匹配该值的qualifier的bean才能注入.

  • 对于定义成list/map或者数组类型的bean是来说,@Resource是一个好的方案,通过一个唯一的名字指向特定的数组或集合.这意味着,在4.3中,集合或数组类型可以通过spring的@Autowired进行类型匹配.

  • 在4.3中,@Autowired也可以考虑自注入,即引用到正在注入的bean.自注入是一个回退;常规注入仍然有优先级.也就是说,自引用不是常规候选项,因此他没有优先级;相反,他们(自注入)的优先级是最低的.实际上,使用自引用是最后的手段.例如:通过bean的事务代理调用相同bean的其他方法,在此场景下可以考虑将受影响的方法分解到单独的代理bean中.

  • @Autowired适用于字段,构造器,混成参数方法,通过@Qualifier注解来限制参数范围.相反的,@Resource注解支持字段,bean的单参数的set方法.因此,它会严格按照qualifiers来匹配你构造器或混合参数方法的注入目标.

######使用自定义的qualifier; 定义如下:

@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配置文件里如下配置:

<?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>

即在<bean>标签里使用<qualifier>标签,其属性为type,value;

使用无具体值的自定义qualifier;

注解Offline定义如下:

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

}

  • 如下使用注解
public class MovieRecommender {

    @Autowired
    @Offline
    private MovieCatalog offlineCatalog;

    // ...

}
  • 用Offline定义一个Bean
<bean class="example.SimpleMovieCatalog">
    <qualifier type="Offline"/>
    <!-- inject any dependencies required by this bean -->
</bean>

你可以自定义一个注解接受命名参数来替代简单的注解,

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

    String genre();

    Format format();

}

Format枚举如下:

public enum Format {
    VHS, DVD, BLURAY
}

这些字段通过自定义匹配符注解来自动注入的包括以下属性的值:genre,format.

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;

    // ...

}

最后,这个bean定义必须包含匹配符的值.这个例子也说明bean的元属性可以用来替代<qualifier>的下级元素.一般情况下,<qualifier/>和它的属性有优先级,但如果没显示的匹配符,那么自动装配机制将会使用meta标签.下面的例子至少有两种bean定义形式;

<?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>

####7.9.5 使用泛型作为自动装配的匹配符 除了@Qualifier注解外,你还可以用java原生类型作为匹配符的一种形式,一般情况下,你需要如此配置:

@Configuration
public class MyConfiguration {

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

    @Bean
    public IntegerStore integerStore() {
        return new IntegerStore();
    }

}

上面的bean实现了泛型接口,比如Store<String>和Store<Integer>,你可以使用@Autowire进行注入,泛型将会作为匹配符:

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

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

泛型匹配符也可以用来注入List,Maps,Arrays

// Inject all Store beans as long as they have an <Integer> generic
// Store<String> beans will not appear in this list
@Autowired
private List<Store<Integer>> s;

###7.9.6 CustomAutowireConfigurer(自定义自动专配配置器) 使用了CustomAutowireConfigurer(本身是一个BeanFactoryPostProcessor组件)之后,即使你的自定义qualifier没有加上@Qualifier注解,你也可以注册你的自定义qualifier;


<bean id="customAutowireConfigurer"
        class="org.springframework.beans.factory.annotation.CustomAutowireConfigurer">
    <property name="customQualifierTypes">
        <set>
            <value>example.CustomQualifier</value>
        </set>
    </property>
</bean>

AutowireCandidateResolver通过以下判断注入条件:

  • 通过每个bean定义里的autowire-candidate值
  • 通过<beans/>标签里的default-autowire-candidates模式
  • 通过显式的@Qualifier注解和任何通过CustomAutowireConfigurer注册的自定义匹配符注解

当一个混合的beans的匹配符作为自动装配候选者,主要的候选者如下确定:假如一个候选者bean定义中设置了primary属性为true,它就会被选中.

@Resource

spring也支持使用@Resource注解来修饰字段或bean的属性设置方法.这是java EE 5和6中的公共模式,例如JSF1.2中的被管理bean或JAX-WS2.0端点.spring也支持该模式.

@Resource 提供了一个name属性,spring默认会拦截bean的名称进行过滤.也就是说,它遵循通过名称语法,就想下面例子所示:


public class SimpleMovieLister {

    private MovieFinder movieFinder;

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

}

如果名字没有且明确指出,那么默认名称将来源于字段名称或set方法.如果是字段,它取字段名称;如果是set方法,它取设置的属性名称.所以以下的例子中将把名字为'movieFinder'的bean注入到这个setter方法里;


public class SimpleMovieLister {

    private MovieFinder movieFinder;

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

}

######注 由@Resource注解提供的名字会通过CommonAnnotationBeanPostProcessor感知而被ApplicationContext处理为bean的名称.如果你明确的注册了SimpleJndiBeanFactory,这些名字会由JNDI进行处理.但是,提醒一下,你最好依赖容器默认行为并少使用spring的JNDI查找能力,这样可以保持间接的水平.

如果@Resource没有指定具体的名称,用法同@Autowired相同,@Resource会进行类型匹配以替代适配符匹配并用来解决一些常用的依赖:beanFactory,ApplicationContext,ResourceLoader,ApplicationEventPublisher,MessageSource接口.

下面的例子中,customerPerferenceDao字段首先查找一个名为customPerferenceDao的bean,如果失败则查看类型是否匹配CusstomerPreferencceDao.这个"context"字段将依据已知的依赖类型ApplicationContext进行注入.


public class MovieRecommender {

    @Resource
    private CustomerPreferenceDao customerPreferenceDao;

    @Resource
    private ApplicationContext context;

    public MovieRecommender() {
    }

    // ...

}

####7.9.8 @PostConstruct and @PreDestroy 构造之后,销毁之前 CommonAnnotationBeanPostProcessor不仅识别@Resourece注解,也识别JSR-250中生命周期注解.在spring2.5中引入的,对这些注解的支持提供了初始化回调和销毁回调时的其他可选项.通过被spring ApplicationContext注册的CommonAnnotationBeanPostProcessor,一个带有一个或多个注解的方法可以在什么周期同一点上被调用,作为spring的生命周期接口方法或显示的申明回调方法.下面的例子中,这些缓存会再初始化之前操作,并在销毁之后清理.

  
public class CachingMovieLister {

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

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

}

转载于:https://my.oschina.net/u/1590027/blog/748584

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值