@Import三种用法
1、引入普通类
2、引入ImportSelector的实现类
3、引入ImportBeanDefinitionRegister的实现类
以下以方式三为例:
配置类实现 ImportBeanDefinitionRegistrar 接口,可以自定义往容器中注册想注入的Bean。
该接口相比与 ImportSelector 接口的主要区别在于,ImportSelector接口是返回一个类,无法对这个类做操作, ImportBeanDefinitionRegistrar 是可以自己注入 BeanDefinition,添加属性等。
public class MyImportBeanRegistrar implements ImportBeanDefinitionRegistrar {
/**
* @param importingClassMetadata 当前类的注解信息
* @param registry 注册类,registerBeanDefinition()可以注册bean
*/
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
}
}
案例:自定义注解,将使用我们自定义注解并满足条件的类注入到spring容器中
自定义注解
参考博客:https://blog.csdn.net/dongzhanglong/article/details/120130237
@Target:注解的作用目标
@Target(ElementType.TYPE)——接口、类、枚举、注解
@Target(ElementType.FIELD)——字段、枚举的常量
@Target(ElementType.METHOD)——方法
@Target(ElementType.PARAMETER)——方法参数
@Target(ElementType.CONSTRUCTOR) ——构造函数
@Target(ElementType.LOCAL_VARIABLE)——局部变量
@Target(ElementType.ANNOTATION_TYPE)——注解
@Target(ElementType.PACKAGE)——包,用于记录java文件的package信息
自定义包扫描注解
参考博客:https://blog.csdn.net/qq_16504067/article/details/120201048
// RetentionPolicy.RUNTIME 表示注解信息在运行时保留,在运行时可以通过反射获取注解信息,实现一些操作
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
public @interface MapperScan {
/**
* 扫描的包名
*/
String[] basePackages() default {};
/**
* 扫描的类名
*/
Class<?>[] basePackageClasses() default {};
}
自定义学生配置注解
//该注解可以应用于类、接口(包括注解类型)、枚举
@Target(ElementType.TYPE)
//被注解的元素包含在生成的Java文档中
@Documented
//该注解的生命周期,由JVM 加载,包含在类文件中,在运行时可以被获取到
@Retention(RetentionPolicy.RUNTIME)
public @interface StudentConfig {
String name() default "luxifa";
int age();
}
BeanDefinition子类实现介绍
参考博客:https://blog.csdn.net/c_c_f/article/details/119861188
对于bean定义只需要关注AbstractBeanDefinition和AnnotatedBeanDefinition就行。不要太注重与细节。
AbstractBeanDefinition:对BeanDefinition接口进行实现,并进行了扩展。
RootBeanDefinition、GenericBeanDefinition、ChildBeanDefinition是其子类。
AnnotatedBeanDefinition:注解类型的Bean定义。并扩展了注解相关的接口。
public interface AnnotatedBeanDefinition extends BeanDefinition {
/**
* 获取注解的元数据
*/
AnnotationMetadata getMetadata();
/*
* 获取工厂方法的元数据
*/
@Nullable
MethodMetadata getFactoryMethodMetadata();
}
定义ImportBeanDefinitionRegister的实现类
参考博客:https://blog.csdn.net/qq_16504067/article/details/120201048
public class MyImportBean implements ImportBeanDefinitionRegistrar {
/**
* @param importingClassMetadata 当前类的注解信息
* @param registry 注册类,registerBeanDefinition()可以注册bean
*/
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
// 获取要扫描的包路径
//聚合扫描的路径
Set<String> basePackages = getBasePackages(importingClassMetadata);
//获取扫描器
ClassPathBeanDefinitionScanner scanner = getScanner(registry);
//扫描并注册bd
for (String basePackage : basePackages) {
//获取com.luxifa包下,使用StudentConfig注解的bean,该处值为com.luxifa.Test
Set<BeanDefinition> candidateComponents = scanner.findCandidateComponents(basePackage);
for (BeanDefinition beanDefinition : candidateComponents) {
//注册BD
// ..可添加写过滤条件,比如StudentConfig注解中age小于35才让注入springbean中
// 思路:判断bean定义是否为被注解的bean定义,是的话,转为被注解的bean定义,然后获取该被注解的bean定义中包含注解的所有信息,然后根据注解所在的类得到类加载器,根据类加载器得到我们的StudentConfig注解,然后判断StudentConfig注解上的age的值
String beanClassName = beanDefinition.getBeanClassName();
// 此处也可以自定义bean,然后注册
registry.registerBeanDefinition(beanClassName, beanDefinition);
}
}
private ClassPathScanningCandidateComponentProvider getScanner(BeanDefinitionRegistry registry) {
//不使用默认的过滤器
// true:默认TypeFilter生效,这种模式会查询出许多不符合你要求的class名
// false:关闭默认TypeFilter
// 参考博客:https://blog.csdn.net/qq_16504067/article/details/116642356
ClassPathBeanDefinitionScannerscanner = new ClassPathBeanDefinitionScanner(registry, false);
// 扫描我们自定义的注解
scanner.addIncludeFilter(new AnnotationTypeFilter(StudentConfig.class));
return scanner;
}
/**
* 获取扫描组件的包路径
*/
protected Set<String> getBasePackages(AnnotationMetadata importingClassMetadata) {
Map<String, Object> attributes = importingClassMetadata
.getAnnotationAttributes(MapperScan.class.getCanonicalName());
Set<String> basePackages = new HashSet<>();
for (String pkg : (String[]) attributes.get("basePackages")) {
if (StringUtils.hasText(pkg)) {
basePackages.add(pkg);
}
}
for (Class<?> clazz : (Class<?>[]) attributes.get("basePackageClasses")) {
basePackages.add(ClassUtils.getPackageName(clazz));
}
if (basePackages.isEmpty()) {
basePackages.add(
ClassUtils.getPackageName(importingClassMetadata.getClassName()));
}
return basePackages;
}
}
自定义配置类中引入MyImportBeanRegistrar对象
package com.xx.example;
@Configuration
@Import(MyImportBean.class)
@MapperScan(basePackages={"com.luxifa"})
public class MyAutoConfiguration {
}
将自定义的配置类MyAutoConfiguration 放到spring.factories文件中文章来源:https://uudwc.com/A/599nJ
#spring.factories 文件内容:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.xx.example.MyAutoConfiguration
Demo服务中,Test.java类使用自定义StudentConfig注解
参考博客:https://blog.csdn.net/weixin_53233197/article/details/128402888文章来源地址https://uudwc.com/A/599nJ
package com.luxifa;
@StudentConfig(name="degula",age=25)
public class Test {
}