欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Spring注解驱动开发 第二节包扫描等相关功能

程序员文章站 2022-07-08 14:42:31
...

Spring注解驱动开发 第二节包扫描等相关功能

在配置类中写入如**解就可以把指定包下的类注入到Spring。

@Configuration
@ComponentScan("com.meng")
public class MainConfig {
    @Bean("person")
    public Person person(){
        return  new Person("张三","23");
    }
}

@Configuration注解上一节中说明了,表示这是一个注解类,@ComponentScan注解就表示将com.meng包下的所有标注@Controller,@Service,@Repository等注解的类全部注入到Spring容器中。

@Controller
public class BookController {}
@Service
public class BookService {}
@Repository
public class BookDao {}

打印结果:

四月 22, 2019 11:29:33 上午 org.springframework.context.annotation.AnnotationConfigApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@2f410acf: startup date [Mon Apr 22 11:29:33 GMT+08:00 2019]; root of context hierarchy
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
mainConfig
bookController
bookDao
bookService
person

Process finished with exit code 0

可以看出上面一些springframework的都是在启动spring容器时spring自己注入的组件,看其他的mainConfig、bookController、bookDao、bookSerivce、person都是我们自己注入到Spring容器中的组件。

spring在指定在扫描包时还可以指定排除哪些类注入到spring容器中,代码如下

@ComponentScan(value = "com.meng",excludeFilters = {
    @ComponentScan.Filter(
                   type = FilterType.ANNOTATION,classes = {
                            Controller.class,Service.class
                    }
    )

上边这段代码在配置类中,表示扫描的包范围在com.meng中,排除过滤器指定的类型是注解类型,整理一下,Filter下type指定过滤类型为注解类型,classes属性可以传入数组,它表示要过滤组件的具体类型,上面过滤的是控制器类型与服务类型。

 @Retention(RetentionPolicy.RUNTIME)
    @Target({})
    public @interface Filter {
        FilterType type() default FilterType.ANNOTATION;

        @AliasFor("classes")
        Class<?>[] value() default {};

        @AliasFor("value")
        Class<?>[] classes() default {};

        String[] pattern() default {};
    }

从源码中可以看出classes属性时可以传入数组的。上面就是排除哪些类注入到Spring容器。同时也可以用只包含哪些类注入spring容器。

只包含哪些类注入spring容器的方式

@Configuration
@ComponentScan(value = "com.meng",//excludeFilters = {
//    @ComponentScan.Filter(
//                    type = FilterType.ANNOTATION,classes = {
//                            Controller.class,Service.class
//                    }
//    )
      includeFilters = {
        @ComponentScan.Filter(
                type = FilterType.ANNOTATION,classes={Controller.class}
        )
      },useDefaultFilters = false
)
public class MainConfig {
    @Bean("person")
    public Person person(){
        return  new Person("张三","23");
    }
}

从上图可以看出,excludeFilters是排除,而includeFilters是只包含的意思。所以上图的意思是过滤类型是注解类型,具体的注解是只包含控制器的类型,但需要特别注意的是(注意!注意!注意!)重要的事情说三遍,一定要加useDefaultFilters,他表示spring容器注入的默认规则,spring容器注入的默认规则是true,要改成false,刚才的只包含过滤器才能生效。
打印结果:

四月 22, 2019 1:49:28 下午 org.springframework.context.annotation.AnnotationConfigApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@2f410acf: startup date [Mon Apr 22 13:49:28 GMT+08:00 2019]; root of context hierarchy
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
mainConfig
bookController
person

Process finished with exit code 0

从上图中可以看出,只有bookController被注入到spring容器中。

配置多个@ComponentScan

如果配置多个的话就要用到ComponentScans,它可以配置多个ComponentScan

@Configuration
@ComponentScan(value = "com.meng",//excludeFilters = {
//    @ComponentScan.Filter(
//                    type = FilterType.ANNOTATION,classes = {
//                            Controller.class,Service.class
//                    }
//    )
      includeFilters = {
        @ComponentScan.Filter(
                type = FilterType.ANNOTATION,classes={Controller.class}
        )
      },useDefaultFilters = false
)
@ComponentScans(
        value={
                @ComponentScan(value = "com.meng",
                        excludeFilters = {
                                @ComponentScan.Filter(
                                        type = FilterType.ANNOTATION,classes={Controller.class}
                                )
                        },useDefaultFilters = false
                ),
                @ComponentScan(value = "com.meng",
                        excludeFilters = {
                                @ComponentScan.Filter(
                                        type = FilterType.ANNOTATION,classes={Controller.class}
                                )
                        },useDefaultFilters = false
                )
        }
)
public class MainConfig {
    @Bean("person")
    public Person person(){
        return  new Person("张三","23");
    }
}

其中,@ComponentScans有一个value属性,可以接收一个数组,这个数组中就可以有多个@CompanentScan注解。

注解注入spring容器过滤规则

 /**
         * 过滤规则
         * FilterType.ANNOTATION           按注解类型过滤
         * FilterType.ASSIGNABLE_TYPE      按实际的类类型进行过滤
         * FilterType.REGEX                按正则表达式进行过滤
         * FilterType.ASPECTJ              按ASPECTJ进行过滤
         * FilterType.CUSTOM               自定义过滤
        */
      includeFilters = {
        @ComponentScan.Filter(
                type = FilterType.CUSTOM,classes={MyTypeFilter.class}
        ),
      },useDefaultFilters = false

上面的代码列出了注解方式的全部注入规则,由于注解过滤规则我们已经测试过,所以不再进行测试,现在实验一下按实际类型过滤,在配置类中改成如下代码

includeFilters = {
        @ComponentScan.Filter(
                type = FilterType.ASSIGNABLE_TYPE,classes={BookService.class}
        ),
      },useDefaultFilters = false

我们把过滤规则改为按实际类型过滤,classes上写入实际的类型,查看打印结果:


org.springframework.context.event.internalEventListenerFactory
mainConfig
bookService
person

Process finished with exit code 0

可以看到bookService被注入到spring容器中。再次测试一下自定义注入容器。

自定义注入spring容器

public class MyTypeFilter implements TypeFilter {

    //metadataReader 可以获取到当前扫描的这个类的信息
    //metadataReaderFactory 可以获取其他的所有类信息
    public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
        //获取当前注解的所有信息
        AnnotationMetadata metadata = metadataReader.getAnnotationMetadata();
        //获取当前类的所有信息
        ClassMetadata classMetadata = metadataReader.getClassMetadata();
        //获取当前类路径
        Resource resource = metadataReader.getResource();
        //System.out.println("当前的类路径为:"+resource.getURL());
        return false;
    }
}

要实现自定义容器注入,要实现一个spring的接口,TypeFilter,实现方法match,其中有两个参数MetadataReader ,MetadataReaderFactory ,第一个表示正在扫描的类信息,第二个表示其他全部的类信息。方法的返回值是布尔类型,根据自己的规则,返回true表示注入到spring容器,false表示不注入到spring容器。我们进行如下规则的定义,注入容器。

public class MyTypeFilter implements TypeFilter {

    //metadataReader 可以获取到当前扫描的这个类的信息
    //metadataReaderFactory 可以获取其他的所有类信息
    public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
        //获取当前注解的所有信息
        AnnotationMetadata metadata = metadataReader.getAnnotationMetadata();
        //获取当前类的所有信息
        ClassMetadata classMetadata = metadataReader.getClassMetadata();
        //获取当前类路径
        Resource resource = metadataReader.getResource();
        //System.out.println("当前的类路径为:"+resource.getURL());
        if(classMetadata.getClassName().contains("er")){
            return true;
        }
        return false;
    }
}

表示当前扫描的类名称如果包含er,就注入到spring容器,

includeFilters = {
        @ComponentScan.Filter(
                type = FilterType.CUSTOM,classes={MyTypeFilter.class}
        ),
      },useDefaultFilters = false

改为自定义规则过滤,classes传入自定义的过滤规则类。查看打印结果:

mainConfig
bookController
myTypeFilter
person
bookService

Process finished with exit code 0

由此结果得知,类名包含er的全部被注入进来,由于bookDao没有er,所以没有被注入。

相关标签: Spring注解开发