项目实训 15 学习Spring(9)

339 阅读8分钟

1.10:Classpath扫描和托管组件:

上一节(基于注解的容器配置)演示了如何通过源级注解提供许多配置元数据。但是,即使在这些示例中,“基本” bean 定义也已在 XML 文件中明确定义,而注解仅驱动依赖项注入。

通过扫描 Classpath 来隐式检测候选组件的选项。候选组件是与过滤条件匹配的类,并在容器中注册了相应的 Bean 定义。(即用此类型注解来注册bean)

1.10.1:@Conponent和其他构造型注解:

Spring 提供了构造型注解:@Component,@Service和@Controller。 @Component是任何 SpringManagement 的组件的通用构造型。

@Repository,@Service和@Controller是@Component的特化,(@configuration也是)用于更具体的用例(分别在持久层,服务层和表示层中)。

1.10.2:使用元注解和组合注解:

Spring 提供的许多注解都可以在您自己的代码中用作元 注解。元注解是可以应用于另一个注解的 注解。例如,提到的earlier的@Service注解 使用@Component进行元 注解,如以下示例所示:

image.png

(1) Component导致@Service的处理方式与@Component相同。

您还可以结合使用元注解来创建“组合 注解”。例如,Spring MVC 的@RestController注解 由@Controller和@ResponseBody组成。

此外,组合注解可以选择从元注解中重新声明属性,以允许自定义。例如,Spring 的@SessionScope注解 将作用域名称硬编码为session,但仍允许自定义proxyMode。以下清单显示了SessionScope注解的定义:

image.png

然后,您可以使用@SessionScope而不用声明proxyMode,如下所示:

image.png

您还可以覆盖proxyMode的值,如以下示例所示:

image.png

1.10.3.:自动检测类并注册 Bean 定义:

Spring 可以自动检测构造型类,并向ApplicationContext注册相应的BeanDefinition实例。例如,以下两个类别有资格进行这种自动检测:

image.png

要自动检测这些类并注册相应的 bean,需要将@ComponentScan添加到@Configuration类中,其中basePackages属性是两个类的公共父包。

image.png

@ComponentScan注解表示了扫描结构注解的范围,一般放在最顶层的类上,即调用了main程序的入口。

如果使用XML:

image.png

context:component-scan的使用隐式启用context:annotation-config的功能。使用context:component-scan时通常不需要包含context:annotation-config元素。

此外,当您使用 component-scan 元素时,AutowiredAnnotationBeanPostProcessor和CommonAnnotationBeanPostProcessor都隐式包含在内。

1.10.4:使用过滤器自定义扫描:

默认情况下,唯一检测到的候选组件是用@Component,@Repository,@Service,@Controller注解 的类或本身用@Component注解 的定制 注解。但是,您可以通过应用自定义过滤器来修改和扩展此行为。将它们添加为@ComponentScan注解的includeFilters(包含)或excludeFilters(剔除)参数(或component-scan元素的include-filter或exclude-filter子元素)。

每个过滤器元素都需要type和expression属性。如下:

image.png

以下示例显示了忽略所有@Repository注解并增加了匹配与正则表达式一致的名称的注解(.表示任意字符*表示任意数量字符)(仍会匹配默认注解):

image.png

以下为等效的 XML:

image.png

您还可以通过在注解上设置useDefaultFilters=false或通过提供use-default-filters="false"作为元素的属性来禁用默认过滤器。实际上,这将禁用对带有@Component,@Repository,@Service,@Controller或@Configuration注解 的类的自动检测。

1.10.5:在组件中定义Bean元数据:

带有 @Configuration 的注解类表示这个类可以使用 Spring IoC 容器作为 bean 定义的来源。@Bean 注解告诉 Spring,一个带有 @Bean 的注解方法将返回一个对象,该对象应该被注册为在 Spring 应用程序上下文中的 bean。

image.png

上例bean有用Qualifier初始化限定值。

被@bean所注解的方法将会自动装配参数:例:

image.png

image.png

上例容器调用protectedInstance方法创建Bean时将会自动寻找参数依赖项注入,如上spouse将会找TestBean类型的并且限定符为“public”的(即第一个bean)。String country将会自动连接到另一个名为privateInstance的 bean 上age属性的值。Spring Expression Language 元素通过符号#{ }定义属性的值。对于@Value注解,表达式解析器已预先配置为在解析表达式文本时查找 bean 名称。

您还可以声明类型为InjectionPoint(或其更具体的子类:DependencyDescriptor)的工厂方法参数,以访问触发当前 bean 创建的请求注入点。因此,此功能对原型范围的 bean 最有意义。对于其他作用域,factory 方法仅在给定作用域中看到触发创建新 bean 实例的注入点(例如,触发创建惰性单例 bean 的依赖项)。在这种情况下,可以将提供的注入点元数据与语义一起使用。以下示例显示了如何使用InjectionPoint:

image.png

@component中的@Bean方法的处理方式与 Spring @Configuration类中相应方法的处理方式不同。不同之处在于,CGLIB 并未增强@Component类来拦截方法和字段的调用。 CGLIB 代理是调用@Configuration类中@Bean方法中的方法或字段中的字段的方法,用于创建 Bean 元数据引用以协作对象。此类方法不是用普通的 Java 语义调用的,而是通过容器进行的,以提供通常的生命周期 管理 和 Spring bean 的代理,即使通过编程调用@Bean方法引用其他 bean 时也是如此。相反,在普通@Component类内的@Bean方法中调用方法或字段具有标准 Java 语义,而无需特殊的 CGLIB 处理或其他约束。

可以将@Bean方法声明为static,从而允许在不将其包含的配置类创建为实例的情况下调用它们。在定义后处理器 Bean(例如,类型BeanFactoryPostProcessor或BeanPostProcessor)时,这特别有意义,因为此类 Bean 在容器生命周期的早期进行了初始化,并且应避免在那时触发配置的其他部分。

@Configuration类中的常规@Bean方法必须是可重写的(即,不得将它们声明为private或final)。

1.10.6:命名自动检测组件:

在扫描过程中自动检测到某个组件时,其 bean 名称由该扫描器已知的BeanNameGenerator策略生成。默认情况下,任何包含名称value的 Spring 构造型 注解(@Component,@Repository,@Service和@Controller)都会将该名称提供给相应的 bean 定义。

如果这样的注解不包含名称value或任何其他检测到的组件(例如,由自定义过滤器发现的组件),则缺省 bean 名称生成器将返回不首字符使用大写字母的非限定类名称。例如,如果检测到以下组件类,则名称将为myMovieLister和movieFinderImpl:

image.png

如果不想依赖默认的 Bean 命名策略,则可以提供自定义 Bean 命名策略。首先,实现BeanNameGenerator接口,并确保包括默认的 no-arg 构造函数。然后,在配置扫描器(ComponentScan)提供完全限定的类名,如以下示例注解和 Bean 定义所示:

image.png

1.10.7:提供自动检测组件的范围:

通常,与 SpringManagement 的组件一样,自动检测到的组件的默认且最常见的范围是singleton。但是,有时您需要由@Scope注解 指定的其他范围。您可以在注解中提供范围的名称,如以下示例所示:

image.png

可以使用 Spring 的元注解方法来编写自己的作用域 注解:例如,使用@Scope("prototype")进行元注解的自定义 注解,也可以声明自定义范围代理模式。

声明自定义范围代理模式,可以实现ScopeMetadataResolver接口。确保包括默认的无参数构造函数。然后,可以在配置扫描程序时提供完全限定的类名,如以下注解和 Bean 定义示例所示:

image.png

使用某些非单作用域时,可能有必要为作用域对象生成代理。为此,在 component-scan 元素上可以使用 scoped-proxy 属性。三个可能的值是:no,interfaces和targetClass。例如,以下配置产生标准的 JDK 动态代理:

image.png

1.10.8:提供带注解的限定符元数据:

当依靠 Classpath 扫描来自动检测组件时,可以在候选类上为限定符元数据提供类型级别的 注解。

image.png

1.10.9:生成候选组件的索引:

尽管 Classpath 扫描非常快,但可以通过在编译时创建候选静态列表来提高大型应用程序的启动性能。在这种模式下,应用程序的所有模块都必须使用此机制,因为当ApplicationContext检测到这样的索引时,它将自动使用它而不是扫描 Classpath。

要生成索引,请向每个包含组件的模块添加附加依赖关系,这些组件是组件扫描指令的目标。以下示例显示了如何使用 Maven 进行操作:

image.png