这种方式是最常用的,也是最推荐使用的。除此之外,还有一种声明方式basePackageClasses,它使用的是类的 Class 字节码:
@Repeatable(ComponentScans.class)public@interfaceComponentScan{@AliasFor("basePackages")String[]value()default{};@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{}; // ...}
它的这个 basePackageClasses 属性,可以传入一组 Class 进去,它代表的意思,是扫描传入的这些 Class 所在包及子包下的所有组件。
@Configuration
@ComponentScan(basePackageClasses = DemoService.class)
public class BasePackageClassConfiguration {
}
@Configuration
@ComponentScan(basePackages = "com.linkedbear.spring.annotation.f_typefilter",
includeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION, value = Animal.class))
public class TypeFilterConfiguration {
}
/**
* Indicates whether automatic detection of classes annotated with {@code @Component}
* {@code @Repository}, {@code @Service}, or {@code @Controller} should be enabled.
*/
boolean useDefaultFilters() default true;
@Configuration
@ComponentScan(basePackages = "com.linkedbear.spring.annotation.f_typefilter",
excludeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION, value = Animal.class))
public class TypeFilterConfiguration {
}
@Configuration
@ComponentScan(basePackages = "com.linkedbear.spring.annotation.f_typefilter",
includeFilters = {@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = Color.class)},
excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, value = Animal.class)})
public class TypeFilterConfiguration {
}
@Configuration
@ComponentScan(basePackages = "com.linkedbear.spring.annotation.f_typefilter",
includeFilters = {
@ComponentScan.Filter(type = FilterType.REGEX, pattern = "com.linkedbear.spring.annotation.f_typefilter.+Demo.+")
},
excludeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION, value = Animal.class),
@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = Color.class)
})
public class TypeFilterConfiguration {
}
@FunctionalInterface
public interface TypeFilter {
/**
* Determine whether this filter matches for the class described by
* the given metadata.
* @param metadataReader the metadata reader for the target class
* @param metadataReaderFactory a factory for obtaining metadata readers
* for other classes (such as superclasses and interfaces)
* @return whether this filter matches
* @throws IOException in case of I/O failure when reading metadata
*/
boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
throws IOException;
}
@Configuration
@ComponentScan(basePackages = "com.linkedbear.spring.annotation.f_typefilter",
includeFilters = {
@ComponentScan.Filter(type = FilterType.REGEX, pattern = "com.linkedbear.spring.annotation.f_typefilter.+Demo.+")
},
excludeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION, value = Animal.class),
@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = Color.class),
@ComponentScan.Filter(type = FilterType.CUSTOM, value = GreenTypeFilter.class)
})
public class TypeFilterConfiguration {
}
/**
* Container annotation that aggregates several {@link ComponentScan} annotations.
*
* <p>Can be used natively, declaring several nested {@link ComponentScan} annotations.
* Can also be used in conjunction with Java 8's support for repeatable annotations,
* where {@link ComponentScan} can simply be declared several times on the same method,
* implicitly generating this container annotation.
*
* @author Juergen Hoeller
* @since 4.3
* @see ComponentScan
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
public @interface ComponentScans {
ComponentScan[] value();
}
/**
* The {@link BeanNameGenerator} class to be used for naming detected components
* within the Spring container.
* <p>The default value of the {@link BeanNameGenerator} interface itself indicates
* that the scanner used to process this {@code @ComponentScan} annotation should
* use its inherited bean name generator, e.g. the default
* {@link AnnotationBeanNameGenerator} or any custom instance supplied to the
* application context at bootstrap time.
* @see AnnotationConfigApplicationContext#setBeanNameGenerator(BeanNameGenerator)
* @see AnnotationBeanNameGenerator
* @see FullyQualifiedAnnotationBeanNameGenerator
*/
Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;
/**
* Strategy interface for generating bean names for bean definitions.
*
* @author Juergen Hoeller
* @since 2.0.3
*/
public interface BeanNameGenerator {
/**
* Generate a bean name for the given bean definition.
* @param definition the bean definition to generate a name for
* @param registry the bean definition registry that the given definition
* is supposed to be registered with
* @return the generated bean name
*/
String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry);
}
public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
if (definition instanceof AnnotatedBeanDefinition) {
String beanName = determineBeanNameFromAnnotation((AnnotatedBeanDefinition) definition);
if (StringUtils.hasText(beanName)) {
// Explicit bean name found.
return beanName;
}
}
// Fallback: generate a unique default bean name.
return buildDefaultBeanName(definition, registry);
}
/**
* Utility method to take a string and convert it to normal Java variable
* name capitalization. This normally means converting the first
* character from upper case to lower case, but in the (unusual) special
* case when there is more than one character and both the first and
* second characters are upper case, we leave it alone.
* <p>
* Thus "FooBah" becomes "fooBah" and "X" becomes "x", but "URL" stays
* as "URL".
*
* @param name The string to be decapitalized.
* @return The decapitalized version of the string.
*/
public static String decapitalize(String name) {
if (name == null || name.length() == 0) {
return name;
}
if (name.length() > 1 && Character.isUpperCase(name.charAt(1)) &&
Character.isUpperCase(name.charAt(0))){
return name;
}
char chars[] = name.toCharArray();
chars[0] = Character.toLowerCase(chars[0]);
return new String(chars);
}