在前面的大部分例子我们使用XML去指明配置数据去定义在Spring容器中的每一个BeanDefinition。上一节我们展示了如何在
代码层注解的方式来提供大量的配置信息。即使在这些例子中,但是,基础的Bean定义显示定义在XML文件中,与此同时注解
只是驱动了依赖注入。这节提供了一个选择去通过扫描classpath的方式来发现候选的组件Bean。候选的组件匹配了过滤器条
件的那些类并且有一个一致的Bean定义注册在容器中。这个就可以免除了使用XML去展示Bean注册,取而代之的是你可以使用
注解,Aspect类型表达式或者你自定义的过滤器条件去选择注册在容器中的有Bean定义的类。
注意:从Spring3.0开始,许多通过Spring JavaConfig工厂提供的功能是核心Spring框架的部分。这个允许你去定义Bean
使用java而不是使用传统的XML文件。来看下 @Configuration, @Bean, @Import,和 @DependsOn注解的例子,以及如
何使用这些功能。
@Component 和 更多的被沿用的注解
@Repository注解标记那些满足持久层(DAO)的角色的类。Spring 提供了更多的沿用的注解:@Component, @Service, 和
@Controller。@Component是一个对所有的Spring管理的组件的泛型的沿用。 @Repository, @Service,和 @Controller是@Component
的具体化。例如,相对应的在持久层,service层和表示层相。因此,你可以注解你的的组件类使用@Component注解,但是通过
@Repository, @Service, 或者@Controller 你的类在通过共建或者和切面相联系时或更加适配些。@Repository, @Service,和
@Controller 也可能携带额外的寓意在将来的Spring框架的发布版本中。因此,如果你在为你的service层的@Componentor或者 @Service
之间选择时,@Service是一个更好的选择。类似的是,正如上面所说的那样, @Repository已经支持作为一个标记在你持久层是一个
原子一事务。
元注解(Meta-annotatioins)
许多通过Spring提供的注解能够在你的代码中用作元注解。一个元注解就是一个简单地 注解,只不过它可以用在另外的一个注解上面。
例如,上面提到@Service注解就是一个一个拥有@Component主机的元注解:
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component // Spring will see this and treat @Service in the same way as @Component
public @interfaceService {
// ....
}
元注解能够组合在一起来创建组合注解。例如,Spring MVC的@RestController注解就是@Controller和@ResponseBody组合。
带有要给value(),元注解类型可以重新声明属性允许用户自定义。这个在想只是暴露源注解属性的一个子集时是很有用的。例如,下面就是
一个定义了session作用的自定义@Scope注解,但是它仍然允许自定义proxyMode。
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Scope("session")
public @interfaceSessionScope {
ScopedProxyMode proxyMode() defaultScopedProxyMode.DEFAULT
}
自动发现类并且注册Bean定义
Spring 能够自动发现模式化的类并且使用ApplicationContext中注册相关的BeanDefination。例如,下面的类就能够被自动发现:
@Service
public classSimpleMovieLister {
privateMovieFinder movieFinder;
@Autowired
publicSimpleMovieLister(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
}
@Repository
public classJpaMovieFinder implementsMovieFinder {
// implementation elided for clarity
}
为了自动发现这些类,并且注册相应的Bean,你需要在XML中包括下面的元素,base-package元素师两个类的父包。
<?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:annotation-config>。
注意:classpath包的扫描需要相一致的目录路径在classpath中。当你使用ANT构建 JARS时,确保你使用文件时不只
是选择 JAR 任务的方式。
还有,AutowiredAnnotationBeanPostProcessor和CommonAnnotationBeanPostProcessor在你使用组件扫描元素的时候就被包括进来了。这
意味着这两个组件自动发现和装配在一起,而不用任何XML中的Bean的配置数据信息。
注意:你可以不适用CommonAnnotationBeanPostProcessorare和AutowiredAnnotationBeanPostProcessor的注册通过
annotation-config的属性值FALSE。
使用过滤器自定义扫描
默认情况下,使用@Component, @Repository, @Service, @Controller或者一个自定义的注解标注的类只发现候选的组件。
但是,你可以修改和扩展这个行为通过应用自定义的过滤器。每一个过滤去元素需要type和expression属性。下面的表格表示
了可选的过滤器:
过滤器类型 |
例子表达式 |
描述 |
annotation(默认情况下) |
org.example.SomeAnnotation |
在目标遵纪按在类型级别使用注解 |
assignable |
一个目标组件可以分配的类 |
aspectj |
org.example..*Service+ |
一个通过目标组件匹配的AspectJ类型的表达式 |
regex |
org\.example\.Default.* |
一个通过目标组件类名匹配的正则表达式 |
custom |
org.example.MyTypeFilter |
实现了org.springframework.core.type .TypeFilter接口的自定义实现 |
下面的例子表明了基于XML的配置忽略了所有的@Repository注解并且使用stub repositories代替。
<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>
注意:你可以通过提供 use-default-filters="false"作为<component-scan/>元素的属性来是默认
的过滤器失效。这个讲影响自动发现注解类@Component, @Repository, @Service, 或者 @Controller。
在组件内部定义Bean 元数据
Spring 组件也可以像容器提供Bean定义元数据。你可以通过用在@Configuration 主机的类的定义Bean元数据
的@Bean注解来做这件事。下面是一个简单例子:
@Component
public classFactoryMethodComponent {
@Bean
@Qualifier("public")
publicTestBean publicInstance() {
return new TestBean("publicInstance");
}
public void doWork() {
// Component method implementation omitted
}
}
这个类是一个在他的doWork()方法中含有应用代码的Spring组件。但是,它也有助于有一个执行方法publicInstance()
的工厂方法的Bean定义。@Bean注解标明了这个工厂方法和其他Bean定义属性,例如,通过@Qulifier注解的限定符的值。
其他的方法级别的注解能够给通过@Scope @Lazy和自定义的限定符注解指明。
注意:除了它的组件初始化的角色,@Lazy注解还可以 放置标记了在@Autowiredor @Inject的注入点。在这个上下文
中,它会产生一个lazy-resolution代理的注入。
自动装配的域和方法通过额外支持正对自动装配的@Bean方法是支持的:
@Component
public classFactoryMethodComponent {
private static inti;
@Bean
@Qualifier("public")
publicTestBean publicInstance() {
return newTestBean("publicInstance");
}
// use of a custom qualifier and autowiring of method parameters
@Bean
protectedTestBean protectedInstance(
@Qualifier("public")TestBean spouse,
@Value("#{privateInstance.age}")String country) {
TestBean tb = newTestBean("protectedInstance", 1);
tb.setSpouse(tb);
tb.setCountry(country);
returntb;
}
@Bean
@Scope(BeanDefinition.SCOPE_SINGLETON)
privateTestBean privateInstance() {
return newTestBean("privateInstance", i++);
}
@Bean
@Scope(value = WebApplicationContext.SCOPE_SESSION, proxyMode =ScopedProxyMode.TARGET_CLASS)
publicTestBean requestScopedInstance() {
return newTestBean("requestScopedInstance", 3);
}
}
这个例子自动装配了String的方法参数 country到名字为privateInstance的其他Bean的属性Age中。一个Spring表达式语言元素
定义了这个属性的值通过符号 #{ }。对于@Value注解,在解析表达式文本的时候一个表达式解析器被提前配置
去查看Bean的名字。
在Spring组件中@Bean方法相比在Spring @Configuration类中的他们副本处理时不一样的。不同之处在于@Component类没有使用CGLIB
增强去拦截方法和域的调用。CGLIB代理通过调用在@Configuration类的@Bean方法来调用方法和域的来创建Bean元数据引用到相关的对象;
这样的方法不会被一般的Java所调用。行成对比的是,在一个@Component类的内部的@Bean方法中调用一个方法或者域是有标准的Java语法的。
命名自动发现的组件
当一个组件在扫描过程中被自动发现了,它的Bean名字是通过扫描器的BeanNameGenerator策略来生成的。默认情况下,任何模式化的注解(
@Component, @Repository, @Service, 和 @Controller)都可以包含一个name的值,这个值将提供给相应的Bean定义的。如果这样的注解
没有包含了一个name的值,默认的Bean 名字生成器返回了不是大写的非限定的类名。例如,下面的两个组件被发现了,他们名字僵尸myMovieLister和
movieFinderImpl:
@Service("myMovieLister")
public classSimpleMovieLister {
// ...
}
@Repository
public classMovieFinderImpl implementsMovieFinder {
// ...
}
注意:如果你不想依赖默认的Bean 名字策略,你可以提供ige自定义的Bean-name策略。首先你需要实现 BeanNameGenerator接口,并且确保
包括一个默认的空的构造函数。然后在配置扫描器的时候提供完整的限定符的类名:
<beans>
<context:component-scan base-package="org.example"
name-generator="org.example.MyNameGenerator"/>
</beans>
作为一般的规则,考虑指明注解的名字因为在任何时候其他的组件可能显示的引用它。在另一方面,自动生成的名字是足够用的在任何时候容器负责装配。
为自动发现的组件提供一个作用域
一般来讲对于Spring管理的组件,默认的和大部分的作用域对于需要自动发现的组件都是单例的。但是,有时候你需要其他的作用域,这个在Spring2.5中
提供一个新的@Scope注解。简单的在注解的内部提供了作用域的名字:
@Scope("prototype")
@Repository
public classMovieFinderImpl implementsMovieFinder {
// ...
}
注意:为了提供一个自动以的作用域策略而不是依赖基于注解的方式,需要实现ScopeMetadataResolver接口,并且确信包括一个空的构造函数。然后
在配置扫描器的时候提供一个完整的限定符的类名:
```xml
<beans>
<context:component-scan base-package="org.example"
scope-resolver="org.example.MyScopeResolver"/>
</beans>
```
当使用确定的非单例的作用域时,为作用域的对象生成代理可能是必要的。为了这个目的,一个scoped-proxy属性就需要了在组件扫描元素中。三种可能的值
是:no,inferfaces 和targetClass.例如,下面的配置将导致标准的JDK动态代理:
<beans>
<context:component-scan base-package="org.example"
scoped-proxy="interfaces"/>
</beans>
使用注解提供限定符元数据
@Qualifier注解是“使用限定符的细粒度的机遇注解的自动装配”部分讲过了。里面有一个例子展示了 @Qualifier注解的使用,并且在解析自动装配候选的时候
自定义限定符注解去提供细粒度的控制。因为这些例子是在基于XML的Bean定义中的,限定符元数据通过使用在XML中的
的子元素qualifier或者meta提供在候选的Bean定义中。当使用classpath扫描来自动发现组件,你可以再候选的类中提供限定符元数据给类型级别的注解。下面就
是这个知识点的上那个例子:
@Component
@Qualifier("Action")
public classActionMovieCatalog implementsMovieCatalog {
// ...
}
@Component
@Genre("Action")
public classActionMovieCatalog implementsMovieCatalog {
// ...
}
@Component
@Offline
public classCachingMovieCatalog implementsMovieCatalog {}
注意:对于大部分的基于注解的可选项,记住注解元数据是和类定义自己绑定的,当XML的使用允许多个相同类型的Bean去igong在他们限定符元数据中的差异,
因为那样的元数据是按实力来提供而不是按类来提供的。
- Spring Framework 学习笔记——核心技术之Spring IOC
Spring Framework 官网文档学习笔记--核心技术之Spring IOC 官方文档 spring-framework-5.3.9 1. Spring Framework 核心技术 1.1 ...
- Spring IoC入门
------------------siwuxie095 Spring IoC 环境搭建 1.先下载相关库文件,下载链接 ...
- 【Java面试】介绍下Spring IoC的工作流程
Hi,我是Mic 一个工作了4年的粉丝,在面试的时候遇到一个这样的问题. "介绍一下Spring IOC的工作流程" 他说回答得不是很好,希望我能帮他梳理一下. 关于这个问题,我们 ...
- Spring核心技术(九)——Spring管理的组件和Classpath扫描
Spring管理的组件和Classpath的扫描 在前文描述中使用到的Spring中的Bean的定义,都是通过指定的XML来配置的.而前文中描述的注解的解析则是在源代码级别来提供配置元数据的.在那些例 ...
- Spring学习笔记之 Spring IOC容器(二) 之注入参数值,自动组件扫描方式,控制Bean实例化方式,使用注解方式
本节主要内容: 1. 给MessageBean注入参数值 2. 测试Spring自动组件扫描方式 3. 如何控制ExampleBean实例化方式 4. 使用注解方式重构Jdb ...
- Spring IOC基础回顾 — 组件扫描和装配
目录 注解形式配置应用IOC 1. 组件自动扫描 2. 组件依赖:为bean添加注解,实现自动注入 3. Spring IOC应用小结 注解形式配置应用IOC 在类定义.方法定义.成员变量定义前使用, ...
- Spring IoC 源码分析 (基于注解) 之 包扫描
在上篇文章Spring IoC 源码分析 (基于注解) 一我们分析到,我们通过AnnotationConfigApplicationContext类传入一个包路径启动Spring之后,会首先初始化包扫 ...
- 谈谈Spring的IoC之注解扫描
问题 IoC是Inversion of Control的缩写,翻译过来即"控制反转".IoC可以说是Spring的灵魂,想要读懂Spring,必先读懂IoC.不过有时候硬着头皮 ...
- Spring IOC(二)beanName 别名管理
Spring IOC(二)beanName 别名管理 Spring 系列目录(https://www.cnblogs.com/binarylei/p/10198698.html) 一.AliasReg ...
随机推荐
- [WebGL入门]四,渲染准备
注意:文章翻译http://wgld.org/,原作者杉本雅広(doxas),文章中假设有我的额外说明,我会加上[lufy:].另外.鄙人webgl研究还不够深入,一些专业词语,假设翻译有误,欢迎大家 ...
- 使用php+swoole对client数据实时更新(二) (转)
上一篇提到了swoole的基本使用,现在通过几行基本的语句来实现比较复杂的逻辑操作: 先说一下业务场景.我们目前的大多数应用都是以服务端+接口+客户端的方式去协调工作的,这样的好处在于不论是处在何种终 ...
- schema for clojure
Schema for Clojure Data Shape Declaration and Validation 1.何为schema schema是描写叙述数据形式的一种clojure数据结构,可用 ...
- php用魔术方法__call实现类函数重载
因为php是弱类型语言,不喜欢c++通过改变函数返回相同的值键入的参数的数目和功能将过载!但在需求函数的实际发展可能过载.开发需求,我们能够通过魔术方法__call()来实现函数重载. class T ...
- Spring AOP在pointcut expression解析表达式 并匹配多个条件
Pointcut 方法是那些需要运行"AOP",由"Pointcut Expression"为了描述叙事. Pointcut以下方法可以通过定义任&&a ...
- 《TCP/IP具体解释》读书笔记(18章)-TCP连接的建立与中止
TCP是一个面向连接的协议.不管哪一方向还有一方发送数据之前.都必须在两方之间建立一条连接.这样的两端间连接的建立与无连接协议UDP不同.UDP向还有一端发送数据报时,无需不论什么预告的握手. 1.建 ...
- iOS6和iOS7适应代码(6) —— NSLocalizedString
我们的应用程序都需要国际化,字符串的重要组成部分.一般来说.我们是通过一个string资源文件来达到这个目的,我们需要支持多国语言,有多少次把这个文档本地化.需要使用的代码NSLocalizedStr ...
- WinForm实现类似QQ停靠,显示隐藏过程添加特效效果
原文:WinForm实现类似QQ停靠,显示隐藏过程添加特效效果 这可能是个老题长谈的问题了,只是在项目中会用到这个效果,所以今天做个记录.大家见了别喷我.在项目中的需求是这样的. 打开程序,在屏幕的右 ...
- 面向对象三大特征之多态——Java笔记(七)
多态: 同一个实体同时具有多种形式 编译时的类型有声明该变量时使用的类型决定,运行时的类型有实际赋值给变量的对象决定 如果编译时类型和运行时类型不同,就出现多态 例: clas ...
- ural 1932 The Secret of Identifier 容斥
主题链接:点击打开链接 stl+容斥 #include <cstdio> #include <cstring> #include <algorithm> #incl ...