Spring之@ComponentScan注解
1. @ComponentScan 注解可配置属性
- value
- basePackages
- basePackageClasses
- nameGenerator
- scopeResolver
- scopedProxy
- resourcePattern
- useDefaultFilters
- includeFilters
- excludeFilters
- lazyInit
2. 相关属性的作用
2.1 代码准备
2.1.1 创建配置类 A、B、C
@Component
public class A {
}@Component
public class B {
}@Component
public class C {
}
2.1.2 创建配置类 AppConfig
@ComponentScan
public class AppConfig {
}
2.1.3 创建启动类 Main
public class Main {public static void main(String[] args) {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);}
}
2.1.4 工程文件结构
2.2 value、basePackages、basePackageClasses
@ComponentScan 注解扫描的 packages
- 配置类是否指定value、basePackages、basePackageClasses
- 是
- value、basePackages 指定的 packages
- basePackageClasses 指定 classes 所在的 packages
- 否
- 扫描该配置类所在的 package
- 是
2.2.1 Spring 内置 bean 的数量
内置 14 个
PS:其中有一个自定义的 bean(AppConfig),这里为了方便说明,把它当成内置的
2.2.2 扫描 com.ys.p1
2.2.2.1 修改配置类 AppConfig
@ComponentScan("com.ys.p1")
public class AppConfig {
}
2.2.2.2 运行 Main 方法,查看运行结果
一共 15 个 beans = 内置(14) + p1(1)
2.2.3 扫描 com.ys.p1、com.ys.p2 及 basePackageClasses 属性设置
2.2.3.1 修改配置类 AppConfig
@ComponentScan(value = {"com.ys.p1", "com.ys.p2"}, basePackageClasses = C.class)
public class AppConfig {
}
2.2.3.2 运行 Main 方法,查看运行结果
一共 17 个 beans = 内置(14) + p1(1) + p2(1) + p3(1)
2.3 nameGenerator
beanName 生成器,默认情况下为类名的驼峰形式
2.3.1 默认情况下的 beanNames
2.3.1 自定义 nameGenerator
2.3.1.1 自定义BeanNameGenerator(MyBeanNameGenerator)
public class MyBeanNameGenerator extends AnnotationBeanNameGenerator {@Overridepublic String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {String beanName = super.generateBeanName(definition, registry);return "my" + beanName;}
}
2.3.1.2 修改配置类 AppConfig
@ComponentScan(value = "com.ys", nameGenerator = MyBeanNameGenerator.class)
public class AppConfig {
}
2.3.1.3 运行 Main 方法,查看运行结果
2.4 scopedProxy
动态代理方式,需要和 @Scope 注解配合使用
- @Scope 是否指定 proxyMode
- 是
- INTERFACES:对 bean 进行 jdk 动态代理
- TARGET_CLASS:对 bean 进行 cglib 动态代理
- NO:不进行动态代理
- 否
- @Scope 是否指定 proxyMode
- 是
- INTERFACES:对 bean 进行 jdk 动态代理
- TARGET_CLASS:对 bean 进行 cglib 动态代理
- NO:不进行动态代理
- 否
- 不进行动态代理
- 是
- @Scope 是否指定 proxyMode
- 是
2.4.1 scopedProxy 功能演示
2.4.1.1 给实体类 A 添加 @Scope 注解
@Component
@Scope
public class A {}
2.4.1.2 修改配置类 AppConfig
@ComponentScan(value = "com.ys", scopedProxy = ScopedProxyMode.INTERFACES)
public class AppConfig {
}
2.4.1.3 运行 Main 方法,查看运行结果(1)
通过运行结果,得出结论:a 是一个 jdk 代理对象
2.4.1.4 修改配置类 AppConfig(将 scopedProxy 改为 TARGET_CLASS)
@ComponentScan(value = "com.ys", scopedProxy = ScopedProxyMode.TARGET_CLASS)
public class AppConfig {
}
2.4.1.5 运行 Main 方法,查看运行结果(2)
通过运行结果,得出结论:a 是一个 cglib 代理对象
2.4.1.6 将实体类 A 的 @Scope 注解的 scopedProxy 属性设置为 INTERFACES
@Component
@Scope(proxyMode = ScopedProxyMode.INTERFACES)
public class A {}
2.4.1.7 运行 Main 方法,查看运行结果(3)
通过运行结果,得出结论:a 是一个 jdk 代理对象,即 @Scope 注解设置的值优先级高于 @ComponentScan 注解设置的值
2.5 scopeResolver
动态代理处理器,如果配置了 scopedProxy,则 scopeResolver 无效
2.5.1 自定义 scopeResolver 手动处理代理逻辑,让扫描的路径都进行 jdk 动态代理
2.5.1.1 自定义scopeResolver JdkScopeMetadataResolver
public class JdkScopeMetadataResolver implements ScopeMetadataResolver {@Overridepublic ScopeMetadata resolveScopeMetadata(BeanDefinition definition) {ScopeMetadata scopeMetadata = new ScopeMetadata();scopeMetadata.setScopedProxyMode(ScopedProxyMode.INTERFACES);return scopeMetadata;}
}
2.5.1.2 修改配置类 AppConfig
@ComponentScan(value = "com.ys", scopeResolver = JdkScopeMetadataResolver.class)
public class AppConfig {
}
2.5.1.3 运行 Main 方法,查看运行结果
通过运行结果,得出结论:扫描的路径的 bean 都被 jdk 动态代理
2.6 resourcePattern
@ComponentScan 注解扫描的资源,需要和 resourcePattern 相匹配,默认值:**/*.class
2.6.1 演示 resourcePattern 作用
2.6.1.1 修改配置类 AppConfig
@ComponentScan(value = "com.ys", resourcePattern = "p1/*.class")
public class AppConfig {
}
2.6.1.2 运行 Main 方法,查看运行结果
通过运行结果,得出结论:只有 p1 文件夹下的实体类 A 才符合条件,所以只存在 a,不存在 b
2.7 useDefaultFilters
默认情况下,如果类上存在 @Component、@ManagedBean、@Named 注解,则会被扫描、解析成 beanDefinition,进而被实例化成 bean。如果值设为 false,即使存在 @Component、@ManagedBean、@Named 注解,也不会被扫描、解析、实例化成 bean
2.7.1 演示 useDefaultFilters 作用
2.7.1.1 修改配置类 AppConfig
@ComponentScan(value = "com.ys", useDefaultFilters = false)
public class AppConfig {
}
2.7.1.2 运行 Main 方法,查看运行结果
通过运行结果,得出结论:即使实体类 A、B、C 类上存在 @Component 注解,也不会被扫描、解析、实例化成 bean
2.8 includeFilters
如果指定了 includeFilters 或 useDefaultFilters 为 true,只要满足任何一个 filter 的 match 方法,就会被扫描、解析、实例化成 bean
2.8.1 演示 includeFilters 作用
2.8.1.1 创建自定义注解 MyComponent
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
public @interface MyComponent {}
2.8.1.2 修改配置类 AppConfig
@ComponentScan(value = "com.ys", includeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = MyComponent.class)})
public class AppConfig {
}
2.8.1.3 将实体类 C 类上的注解替换成 @MyComponent
@MyComponent
public class C {
}
2.8.1.4 运行 Main 方法,查看运行结果
通过运行结果,得出结论:自定义 includeFilters 生效
2.9 excludeFilters
excludeFilters 与 includeFilters 作用相反,不过 excludeFilters 的优先级更高,如果满足 excludeFilters 的 match 方法,则 useDefaultFilters 和 includeFilters 失效
2.10 lazyInit
是否懒加载,默认 false
2.10.1 演示 lazyInit 作用
2.10.1.1 修改配置类 AppConfig
@ComponentScan(value = "com.ys", includeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = MyComponent.class)},lazyInit = true)
public class AppConfig {
}
2.10.1.2 运行 Main 方法,查看运行结果
通过运行结果,得出结论:a 是懒加载的