微信公众号:程序yuan
关注可了解更多的资源。问题或建议,请公众号留言;
2.@ComponentScan
1.使用xml配置包扫描的方式
<!--包扫描,只要标注了@Controller/@Service/@Repository/@Component就可以被扫描到-->
<context:component-scan base-package="com.ooyhao"></context:component-scan>
定义相应的Controller,service,dao层,并用相应的注解进行标注。
2.使用注解方式进行包扫描
//配置类==配置文件
@ComponentScan(value = {"com.ooyhao"})//可以定义多个。
@Configuration //告诉Spring这是一个配置类
public class MainConfig {
// 给容器中注册一个Bean,类型就是返回值的类型,id默认是用方法名作为id、
@Bean("person")
public Person person01(){
return new Person("李四",20);
}
}
注意:
xml方式,<context:component-scan></context:component-scan>是配置在beans.xml文件中的,所以只需要在MainConfig类上用@ComponentScan(value/basePackages="")来进行扫描。(value与basePackages作用一致)。
可以定义多个:(部分源码)
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Repeatable(ComponentScans.class)
public @interface ComponentScan {
/**
* Alias for {@link #basePackages}.
* <p>Allows for more concise annotation declarations if no other attributes
* are needed — for example, {@code @ComponentScan("org.my.pkg")}
* instead of {@code @ComponentScan(basePackages = "org.my.pkg")}.
*/
@AliasFor("basePackages")
String[] value() default {};
/**
* Base packages to scan for annotated components.
* <p>{@link #value} is an alias for (and mutually exclusive with) this
* attribute.
* <p>Use {@link #basePackageClasses} for a type-safe alternative to
* String-based package names.
*/
@AliasFor("value")
String[] basePackages() default {};
/**
* Type-safe alternative to {@link #basePackages} for specifying the packages
* to scan for annotated components. The package of each class specified will be scanned.
* <p>Consider creating a special no-op marker class or interface in each package
* that serves no purpose other than being referenced by this attribute.
*/
Class<?>[] basePackageClasses() default {};
测试代码:
@Test
public void testComponent(){
AnnotationConfigApplicationContext context = new
AnnotationConfigApplicationContext(MainConfig.class);
String[] names = context.getBeanDefinitionNames();
for(String name:names){
System.out.println(name);
}
}
结果:
3.@Component的扫描规则
1.FilterType的源码(取值):
public enum FilterType {
ANNOTATION, //按照注解的方式
ASSIGNABLE_TYPE, //按照给定的类型
ASPECTJ, //按照ASPECTJ表达式
REGEX, //按照正则表达式
CUSTOM //自定义
}
2.@Componenet的源码
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Repeatable(ComponentScans.class) //可以重复,说明可以写多个ComponentScan
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 ClassPathScanningCandidateComponentProvider.DEFAULT_RESOURCE_PATTERN;
boolean useDefaultFilters() default true;
Filter[] includeFilters() default {};
Filter[] excludeFilters() default {};
boolean lazyInit() default false;
@Retention(RetentionPolicy.RUNTIME)
@Target({})
@interface Filter {
FilterType type() default FilterType.ANNOTATION;
@AliasFor("classes")
Class<?>[] value() default {};
@AliasFor("value")
Class<?>[] classes() default {};
String[] pattern() default {};
}
}
3.MainConfig.java(排除)
//配置类==配置文件
@ComponentScan(value = {"com.ooyhao"},excludeFilters = {
@Filter(type = FilterType.ANNOTATION,value = {Controller.class}),
@Filter(type = FilterType.ASSIGNABLE_TYPE,value = {BookService.class})
})
@Configuration //告诉Spring这是一个配置类
public class MainConfig {
// 给容器中注册一个Bean,类型就是返回值的类型,id默认是用方法名作为id、
@Bean("person")
public Person person01(){
return new Person("李四",20);
}
}
(排除了@Controller标注的,以及BookService类型的)
4.MainConfig.java(包含)
xml方式:
<!--包扫描,只要标注了@Controller/@Service/@Repository/@Component就可以被扫描到-->
<context:component-scan base-package="com.ooyhao" use-default-filters="false"></context:component-scan>
<!--需要使用use-default-filters来禁用默认的扫描规则-->
注解方式:
//配置类==配置文件
/*@ComponentScan(value = {"com.ooyhao"},excludeFilters = {
@Filter(type = FilterType.ANNOTATION,value = {Controller.class}),
@Filter(type = FilterType.ASSIGNABLE_TYPE,value = {BookService.class})
})*/
@ComponentScan(basePackages = "com.ooyhao",includeFilters = {
@Filter(type = FilterType.ANNOTATION,value = {Controller.class})
},useDefaultFilters = false)
@Configuration //告诉Spring这是一个配置类
public class MainConfig {
(只包含@Controller标注的)
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Repeatable(ComponentScans.class) //可以重复,说明可以写多个ComponentScan
public @interface ComponentScan {
可同时写多个@ComponentScan(JDK1.8)。也可以使用@ComponentScans();
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
public @interface ComponentScans {
ComponentScan[] value();
}
(配置多个@ComponentScan)
@ComponentScan(basePackages = "com.ooyhao",includeFilters = {
@Filter(type = FilterType.ANNOTATION,value = {Controller.class})//(按照注解)
},useDefaultFilters = false)
@ComponentScan(basePackages = "com.ooyhao",includeFilters = {
@Filter(type = FilterType.ANNOTATION,value = {Service.class})//包括子类(按照指定类型)
},useDefaultFilters = false)
@Configuration //告诉Spring这是一个配置类
public class MainConfig {
5.自定义扫描规则
通过实现TypeFilter接口来自定义扫描规则的Filter
public interface TypeFilter {
/**
* @param metadataReader :当前正在扫描的类的信息
* @param metadataReaderFactory :可以获取到其他类的信息
*/
boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
throws IOException;
}
自定义扫描过滤器
public class MyTypeFilter implements TypeFilter{
/**
* @param metadataReader :当前正在扫描的类的信息
* @param 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(annotationMetadata.getAnnotationTypes());//获得注解类型
System.out.println(resource.getURL());//获得资源路径
System.out.println(classMetadata.getClassName());//获得类名
if(classMetadata.getClassName().contains("er")) {
return true;
}
return false;
}
}
在Config.java上配置
@ComponentScan(basePackages = "com.ooyhao",includeFilters = {
/*@Filter(type = FilterType.ANNOTATION,value = {Controller.class}),*/
@Filter(type = FilterType.CUSTOM,value = {MyTypeFilter.class})
},useDefaultFilters = false)
@Configuration //告诉Spring这是一个配置类
public class MainConfig {
总结:
为什么myTypeFilter会被扫描到:
由于我们扫描的基本包是com.ooyhao,所有在这个基本包下面的所有的类都会被扫描到进行过滤,而只有上述结果中的三个是包含"er"的,所有就会被扫描到。