Spring5参考指南:组件扫描

简介: Spring5参考指南:组件扫描

文章目录



组件扫描


上一篇文章我们讲到了annotation-config配置,它主要用于bean内部的属性注入。而bean本身则需要通过配置的方式来定义。如果想使用配置的方式来定义bean,则可以使用component-scan,如下:


<context:component-scan base-package="com.flydean"/>


component-scan会扫描类路径里面的注解注解,包括(@Component, @Repository, @Service,@Controller, @RestController, @ControllerAdvice, 和@Configuration ), 当然component-scan默认包含了annotation-config,我们可以直接在这些配置bean中使用上篇文章讲到的注解。


@Component


@Component表示该bean是一个组件,@Component是任何Spring管理的组件的通用原型。@Repository、@Service和@Controller是@Component针对更具体的用例(分别在持久性、服务和表示层中)的特殊注解。因此,您可以用@Component注解组件类,但是,通过用@Repository、@Service或@Controller注解它们,您的类更具有语义性。通常更适合在AOP中做进一步的业务逻辑处理。


元注解和组合注解


所谓元注解就是可以用在其他注解中的注解。 像之前提到的@Component就是@Service的元注解。如下:


@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component 
public @interface Service {
    // ....
}


@Component会导致@Service和@Component一样被对待。


当然你也可以组合使用元注解,或者自定义元注解。例如,Spring的@SessionScope注解将作用域名称硬编码为session,但仍允许自定义proxyMode。以下列表显示了


sessionScope注解的定义:


@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Scope(WebApplicationContext.SCOPE_SESSION)
public @Interface SessionScope {
    /**
     * Alias for {@link Scope#proxyMode}.
     * <p>Defaults to {@link ScopedProxyMode#TARGET_CLASS}.
     */
    @AliasFor(annotation = Scope.class)
    ScopedProxyMode proxyMode() default ScopedProxyMode.TARGET_CLASS;
}


你可以不定义@SessionScope里面的proxyMode, 如下:


@Service
@SessionScope
public class SessionScopedService {
    // ...
}


你也可以重写proxyMode,如下:


@Service
@SessionScope(proxyMode = ScopedProxyMode.INTERFACES)
public class SessionScopedUserService implements UserService {
    // ...
}


#@ComponentScan和filters


上面我们讲到,要是要使用组件扫描,需要在XML配置context:component-scan, 其实也可以使用注解的形式,如下所示:


@Configuration
@ComponentScan(basePackages = "com.flydean.beans")
public class AppConfig {
}


@ComponentScan可以配置一些filters用来过滤不需要的组件。如下所示:


@Configuration
@ComponentScan(basePackages = "com.flydean.beans",
        includeFilters = @ComponentScan.Filter(type = FilterType.REGEX, pattern = ".*Stub.*Repository"),
        excludeFilters = @ComponentScan.Filter(BeanA.class))
public class BeanAConfig {
}


下表是支持的filter类型和例子:


Filter type 表达式例子 描述
annotation(默认) org.example.SomeAnnotation type基本的目标组件
assignable org.example.SomeClass 目标组件可分配给(扩展或实现)的类(或接口)。
aspectj org.example…*Service+ 匹配目标组件的AspectJ类型
regex org\.example\.Default.* 匹配目标主键内名的正则表达式
custom org.example.MyTypeFilter org.springframework.core.type .TypeFilter的自定义实现


组件内部定义Bean元数据


Spring组件还可以为容器提供bean定义元数据。您可以使用用于在@Configuration annotated类中定义bean元数据的相同@Bean注解来实现这一点。以下示例显示了如何执行此操作:


@Component
public class FactoryMethodComponent {
    @Bean
    @Qualifier("public")
    public BeanA publicInstance() {
        return new BeanA();
    }
    public void doWork() {
        // Component method implementation omitted
    }
}


InjectionPoint


从SpringFramework4.3开始,还可以声明InjectionPoint类型的工厂方法参数,来创建Bean。


注意,这只适用于bean实例的实际创建,而不适用于现有实例的注入。因此,这个特性对于原型范围的bean最有意义。


@Component
public class InjectPointFactoryMethodComponent {
    @Bean
    @Scope("prototype")
    public BeanA prototypeInstance(InjectionPoint injectionPoint) {
        return new BeanA("prototypeInstance for " + injectionPoint.getMember());
    }
}


常规Spring组件中的@Bean方法的处理方式与Spring@Configuration类中的对应方法不同。不同的是,@Component类没有用cglib来增强以截获方法和字段的调用。cglib代理是调用@Configuration classes中通过@Bean methods内的方法或字段创建对协作对象的bean元数据引用的方法。


你可以将@Bean方法声明为静态方法,允许在不将其包含的配置类创建为实例的情况下调用它们。在定义post-processor bean(例如,BeanFactoryPostProcessor或BeanPostProcessor类型)时,这是特别有意义的,因为这样的bean在容器生命周期的早期就被初始化,应该避免在此时触发配置的其他部分。


由于技术限制,对static @Bean方法的调用永远不会被容器截获,即使是在@Configuration类(如本节前面所述)中也是如此:cglib子类只能重写非静态方法。因此,直接调用另一个@Bean方法相当于标准Java的new方法,导致从工厂方法本身直接返回一个独立的实例。


要注意: @Configuration类中的常规@Bean方法必须是可重写的,也就是说,它们不能声明为私有或最终的。


为自动检测组件命名


默认情况下,可以提供value属性给@Component、@Repository、@Service和@Controller),从而为Bean命名。


如果这样的注解不包含value,则默认bean名称生成器将返回小写的非限定类名。例如,如果检测到以下组件类,则名称为myMovieLister和movieFinderImpl:


@Service("myMovieLister")
public class SimpleMovieLister {
    // ...
}


@Repository
public class MovieFinderImpl implements MovieFinder {
    // ...
}


如果您不想依赖默认的bean命名策略,可以提供一个自定义的bean命名策略。首先,实现BeanNameGenerator接口,并确保包含一个默认的无参数构造函数。然后,在配置扫描器时提供完全限定的类名,如下面的示例注解和bean定义所示:


public class MyNameGenerator implements BeanNameGenerator {
    @Override
    public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
        return null;
    }
}


@Configuration
@ComponentScan(basePackages = "com.flydean", nameGenerator = MyNameGenerator.class)
public class BeanNameConfig {
}


为自动检测的组件提供作用域


与一般的Spring管理组件一样,自动检测组件的默认和最常见的作用域是singleton。但是,有时您需要一个可以由@Scope注解指定的不同范围。可以在注解中提供作用域的名称,如下示例所示:


@Scope("prototype")
@Component("beanA")
public class BeanA {
    public BeanA(){
    }
    public BeanA(String name){
    }
}


自定义范围解析


要为范围解析提供自定义策略,而不是依赖基于注解的方法,可以实现ScopeMetadataResolver接口。如下所示:


public class MyScopeResolver implements ScopeMetadataResolver {
    @Override
    public ScopeMetadata resolveScopeMetadata(BeanDefinition definition) {
        return null;
    }
}


@Configuration
@ComponentScan(basePackages = "com.flydean", scopeResolver = MyScopeResolver.class)
public class BeanScopeResolverConfig {
}


scoped-proxy


当使用某些非单例作用域时,可能需要为作用域对象生成代理。为此,组件扫描元素上可以有一个scoped-proxy 属性。三个可能的值是:no、interfaces和targetClass。例如,以下配置将生成标准JDK动态代理:


@Configuration
@ComponentScan(basePackages = "com.flydean", scopedProxy = ScopedProxyMode.INTERFACES)
public class ScopedProxyConfig {
}


生成候选组件的索引


虽然类路径扫描速度非常快,但是可以通过在编译时创建一个静态候选列表来提高大型应用程序的启动性能。


要生成索引,需要每个模块添加一个附加依赖项,该模块包含作为组件扫描指令目标的组件。下面的示例说明如何使用Maven:


<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context-indexer</artifactId>
        <version>5.1.8.RELEASE</version>
        <optional>true</optional>
    </dependency>
</dependencies>


这个过程生成一个包含在JAR文件中的META-INF/spring.components文件。


当在类路径上找到META-INF/Spring.components时,索引将自动启用。如果某个索引部分可用于某些库(或用例),但无法为整个应用程序生成,则可以通过将spring.index.ignore设置为true(作为系统属性或类路径根目录下的spring.properties文件)来回滚到常规类路径安排(就像根本没有索引一样)。


相关文章
|
6月前
|
Java 应用服务中间件 Nacos
Spring Cloud 常用各个组件详解及实现原理(附加源码+实现逻辑图)
Spring Cloud 常用各个组件详解及实现原理(附加源码+实现逻辑图)
119 0
|
6月前
|
XML Java 数据格式
spring基础之常用组件
spring基础之常用组件
|
6月前
|
Java Spring 容器
【Java】Spring如何扫描自定义的注解?
【Java】Spring如何扫描自定义的注解?
154 0
|
6月前
|
负载均衡 Java 开发者
【分布式】Spring Cloud 组件综述
【1月更文挑战第25天】【分布式】Spring Cloud 组件综述
|
6月前
|
Dubbo Java 应用服务中间件
微服务框架(十六)Spring Boot及Dubbo zipkin 链路追踪组件埋点
此系列文章将会描述Java框架Spring Boot、服务治理框架Dubbo、应用容器引擎Docker,及使用Spring Boot集成Dubbo、Mybatis等开源框架,其中穿插着Spring Boot中日志切面等技术的实现,然后通过gitlab-CI以持续集成为Docker镜像。 本文第一部分为调用链、OpenTracing、Zipkin和Jeager的简述;第二部分为Spring Boot及Dubbo zipkin 链路追踪组件埋点
|
12天前
|
负载均衡 算法 Java
除了 Ribbon,Spring Cloud 中还有哪些负载均衡组件?
这些负载均衡组件各有特点,在不同的场景和需求下,可以根据项目的具体情况选择合适的负载均衡组件来实现高效、稳定的服务调用。
31 5
|
2月前
|
XML 缓存 Java
spring源码剖析-spring-beans(内部核心组件,BeanDefinition的注册,BeanWapper创建)
spring源码剖析-spring-beans(内部核心组件,BeanDefinition的注册,BeanWapper创建)
49 10
|
2月前
|
XML 存储 Java
spring源码刨析-spring-beans(内部核心组件,beanDefinition加载过程)
spring源码刨析-spring-beans(内部核心组件,beanDefinition加载过程)
|
3月前
|
人工智能 自然语言处理 Java
Spring AI,Spring团队开发的新组件,Java工程师快来一起体验吧
文章介绍了Spring AI,这是Spring团队开发的新组件,旨在为Java开发者提供易于集成的人工智能API,包括机器学习、自然语言处理和图像识别等功能,并通过实际代码示例展示了如何快速集成和使用这些AI技术。
Spring AI,Spring团队开发的新组件,Java工程师快来一起体验吧
|
3月前
|
Java Spring
Spring的AOP组件详解
该文章主要介绍了Spring AOP(面向切面编程)组件的实现原理,包括Spring AOP的基础概念、动态代理模式、AOP组件的实现以及Spring选择JDK动态代理或CGLIB动态代理的依据。
Spring的AOP组件详解