Spring 核心(IOC)- 类路径扫描和组件管理

    技术2022-07-12  67

    目录

    类路径扫描和组件管理1. 使用@Components2. 使用包扫描过滤器3. 使用注解配置Bean作用域4. JSR-330标准注解5. 包扫描效率问题*

    类路径扫描和组件管理

    通过注解实现bean在容器中的注册。

    要使用这方面的注解,首先得先开启包扫描,用于指定哪个包进行自动检测。

    XML配置:

    <context:component-scan base-package="org.example"/>

    基于Java的容器配置:

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

    在base-package属性中你可以用逗号、空格和分号分隔开多个包。

    <context:component-scan/>标签隐式的启用了<context:annotation-config />功能,所以可以省略。

    当然,你也可以通过**<context:component-scan annotation-config=“false”/>**来禁用AutowiredAnnotationBeanPostProcessor、AutowiredAnnotationBeanPostProcessor。

    1. 使用@Components

    通过@Components注解实现bean注册。如果你不指定其限定符属性,默认情况下,采用类名首字母小写作为限定符,指定限定符则用@Qualifier注解。

    @Components//或@Service public class UserServie {//默认限定符:userServie // ... } @Components @Qualifier("userServie")//指定限定符 public class UserServie { // ... }

    如果,你并不希望采用Spring默认组件命名策略,可以自定义组件命名策略,通过实现BeanNameGenerator接口并有一个默认的无参构造方法,然后在包扫描中配置即可。

    XML配置:

    <context:component-scan name-generator="org.example.MyNameGenerator" />

    基于Java的容器配置:

    @Configuration @ComponentScan(nameGenerator = MyNameGenerator.class) public class AppConfig { // ... }

    在Spring Framework 5.2.3中,通过使用FullyQualifiedAnnotationBeanNameGenerator类可以实现完全限定类名的组件命名策略。

    此外,在web开发中,你还可以用@Repository, @Service, and @Controller来注册Bean,它们用于更具体的组件(分别为持久层、业务层和表示层)的专用化。通过查看注解源码可以发现它们都拥有@Components元注解。

    当然,你可以通过组合一系列注解实现复合注解,如SpringMVC中@RestController就实现了@Controller和@ResponseBody的复合。

    2. 使用包扫描过滤器

    通过在包扫描中配置includeFilters、excludeFilters你可以在扫描中加入或排除指定组件,其中type属性用于指定过滤器类型,expression属性指定表达式。

    XML配置:

    <context:component-scan base-package="..." > <context:exclude-filter type=".." expression=".."/> <context:include-filter type=".." expression=".."/> </context:component-scan>

    基于Java的注解配置:

    @Configuration @ComponentScan( includeFilters = @Filter(type = FilterType.REGEX, pattern = ".*Stub.*Repository"), excludeFilters = @Filter(Repository.class)) public class AppConfig { ... }

    过滤器类型如下表:

    类型表达式示例描述annotation(默认)org.example.SomeAnnotation根据注解进行过滤assignableorg.example.SomeClass根据类型(或接口)进行过滤aspectjorg.example…*Service+根据AspectJ类型表达式进行过滤regexorg.example.Default.*根据正则表达式进行过滤customorg.example.MyTypeFilter根据定制的过滤器进行过滤(定制过滤器要实现TypeFilter接口)

    在使用这些过滤器的时候,你还可以在包扫描中配置 useDefaultFilters=false(或XML配置的use-default-filters=“false”)来实现禁止默认过滤器,这将有效的禁止默认注解(如@Component、@Configuration)的自动检测。

    3. 使用注解配置Bean作用域

    通过@Scope注解可以实现配置作用域。该注解仅在具体的Bean类或@Bean方法上使用,与XML配置相反,它并没有作用域继承的概念。

    @Scope("prototype") @Repository public class ExampleImpl implements Example { // ... }

    同样的,也可通过@scopedProxy 注解配置作用域代理。

    XML配置:

    <beans> <context:component-scan base-package="org.example" scoped-proxy="interfaces"/> </beans>

    注解配置:

    @Configuration @ComponentScan(basePackages = "org.example", scopedProxy = ScopedProxyMode.INTERFACES)//或ScopedProxyMode.TARGET_CLASS public class AppConfig { // ... }
    4. JSR-330标准注解

    你可以使用JSR-330标准的注解代替一些Spring注解,首先得加入依赖关系。

    <dependency> <groupId>javax.inject</groupId> <artifactId>javax.inject</artifactId> <version>1</version> </dependency> @Inject代替@Autowired

    与@Autowired一样,可以通过@Inject对字段、方法和构造参数进行注入(@Inject无required属性)。甚至可以使用@Nullable允许为空。

    @Named代替@Qualifier

    若在使用@Inject时需要进一步对限定符进行匹配,可以使用@Named

    @Named/@ManagedBean代替@Component

    可以使用@Named或@ManagedBean(两者不可组合)标识组件,并且依然可以被@ComponentScan扫描到

    5. 包扫描效率问题*

    在大型应用中,你可以通过创建索引来提高包扫描效率。

    首先你需要引入相关依赖。

    <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-indexer</artifactId> <version>5.3.0-SNAPSHOT</version> <optional>true</optional> </dependency>

    之后,在你需要索引的Bean上添加@Indexed即可。

    该依赖会在构建时创建一个在jar包中的META-INF/spring.components文件,当Spring找到此路径文件时,会自动开启索引。

    需要注意的是,在多模块开发时,如果A模块开启索引,B模块不开启索引,则会出B模块bean无法被找到的错误。

    Processed: 0.012, SQL: 9