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

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,所以没有被注入。

猜你喜欢

转载自blog.csdn.net/William_HoF/article/details/89449124