目录
上篇我们通过一个配置类MainConfig往IOC中注册了一个bean,那我么可以控制哪些组件不注册到IOC中呢?
指定扫描规则
@ComponentScan 注解类给我们提供了一以下的功能:
package org.springframework.context.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.core.annotation.AliasFor;
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Repeatable(ComponentScans.class)
public @interface ComponentScan {
@AliasFor("basePackages")
String[] value() default {};
@AliasFor("value")
String[] basePackages() default {};
Class<?>[] basePackageClasses() default {};
Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;
Class<? extends ScopeMetadataResolver> scopeResolver() default AnnotationScopeMetadataResolver.class;
ScopedProxyMode scopedProxy() default ScopedProxyMode.DEFAULT;
//下面这行代码影响代码格式,这里先注释掉了
//String resourcePattern() default "**/*.class";
boolean useDefaultFilters() default true;
ComponentScan.Filter[] includeFilters() default {};
ComponentScan.Filter[] excludeFilters() default {};
boolean lazyInit() default false;
@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 {};
}
}
excludeFilters:需要排除哪些组件,有以下几种过滤规则,由内部类的Filter注解可知,默认的就是ANNOTATION
includeFilters:只包含哪些组件。
public enum FilterType {
ANNOTATION, //按照注解
ASSIGNABLE_TYPE, //按照类型
ASPECTJ, //不常用
REGEX, //不常用
CUSTOM; //自定义
private FilterType() {
}
}
我们分别使用@Controller、@Repository、@Service分别创建PersonController、PersonDao、PersonService
使用 FilterType.ANNOTATION
按照注解
测试不注册Controller注解的组件
package com.cjian.config;
import com.cjian.bean.Person;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Controller;
/**
* @description:
* @author: CJ
* @time: 2020/10/28 9:32
*/
@Configuration //告诉spring这是一个配置类
//指定要扫描的包,以及不扫描哪些组件
@ComponentScan(value = "com.cjian",excludeFilters = {@ComponentScan.Filter(type= FilterType.ANNOTATION,classes = Controller.class)})
public class MainConfig {
//给容器中注册一个bean,类型未返回值的名字,id默认为方法名
@Bean("person")
public Person person01(){
return new Person("cjian", 27);
}
}
输出:
includeFilters 的使用
/*
* Copyright (c) Huawei Technologies Co., Ltd. 2019-2020. All rights reserved.
*/
package com.cjian.config;
import com.cjian.bean.Person;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Service;
/**
* @description:
* @author: CJ
* @time: 2020/10/28 9:32
*/
@Configuration //告诉spring这是一个配置类
//指定要扫描的包,以及不扫描哪些组件
@ComponentScan(value = "com.cjian",
excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Controller.class)},
includeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Service.class)},
useDefaultFilters = false)
public class MainConfig {
//给容器中注册一个bean,类型未返回值的名字,id默认为方法名
@Bean("person")
public Person person01() {
return new Person("cjian", 27);
}
}
注意使用 includeFilters (只扫描)时,得将 useDefaultFilters 设置为false
输出:
还可以使用@ComponentScans
/*
* Copyright (c) Huawei Technologies Co., Ltd. 2019-2020. All rights reserved.
*/
package com.cjian.config;
import com.cjian.bean.Person;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScans;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Service;
/**
* @description:
* @author: CJ
* @time: 2020/10/28 9:32
*/
@Configuration //告诉spring这是一个配置类
//指定要扫描的包,以及不扫描哪些组件
@ComponentScans(value={
@ComponentScan(value = "com.cjian",
excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Controller.class)},
includeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Service.class)},
useDefaultFilters = false)
})
public class MainConfig {
//给容器中注册一个bean,类型未返回值的名字,id默认为方法名
@Bean("person")
public Person person01() {
return new Person("cjian", 27);
}
}
使用 FilterType.ASSIGNABLE_TYPE
按照给定的类型
/*
* Copyright (c) Huawei Technologies Co., Ltd. 2019-2020. All rights reserved.
*/
package com.cjian.config;
import com.cjian.bean.Person;
import com.cjian.dao.PersonDao;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScans;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Service;
/**
* @description:
* @author: CJ
* @time: 2020/10/28 9:32
*/
@Configuration //告诉spring这是一个配置类
//指定要扫描的包,以及只扫描哪些组件
@ComponentScans(value = {
@ComponentScan(value = "com.cjian",
includeFilters = {//只注册Service 和 PersonDao(包含该类的子类或者实现类)
@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Service.class),
@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = PersonDao.class)
}, useDefaultFilters = false)
})
public class MainConfig {
//给容器中注册一个bean,类型未返回值的名字,id默认为方法名
@Bean("person")
public Person person01() {
return new Person("cjian", 27);
}
}
输出:
自定义过滤规则
使用 FilterType.CUSTOM
得实现 TypeFilter 接口
/*
* Copyright (c) Huawei Technologies Co., Ltd. 2019-2020. All rights reserved.
*/
package com.cjian.typefilter;
import org.springframework.core.io.Resource;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.ClassMetadata;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.filter.TypeFilter;
import java.io.IOException;
/**
* @description:
* @author: CJ
* @time: 2020/10/28 16:57
*/
public class MyTypeFilter implements TypeFilter {
/*
* MetadataReader metadataReader:读取到的当前正在扫描的类的信息
* MetadataReaderFactory metadataReaderFactory:可以获取到其他任何类的信息
* */
@Override
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
throws IOException {
//获取当前扫描的类的注解信息
AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
//获取当前扫描的类的信息,如累的类型,实现了什么接口等
ClassMetadata classMetadata = metadataReader.getClassMetadata();
//获取当前类的资源(类的路径)
Resource resource = metadataReader.getResource();
String className = classMetadata.getClassName();
System.out.println("---->"+className);
/*if(className.contains("er")){
return true;
}*/
return false;
}
}
此时输出:
mainConfig 和person是定义配置类,所以会注册到IOC中,当我们放开上面的注释代码块后,输出如下
---->com.cjian.Test
---->com.cjian.bean.Person
---->com.cjian.controller.PersonController
---->com.cjian.dao.PersonDao
---->com.cjian.service.PersonService
---->com.cjian.typefilter.MyTypeFilter
Person{name='cjian', age=27}
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
mainConfig
person
personController
personDao
personService
myTypeFilter
会扫描com.cjian下的所有类