@Import三种用法
1、引入普通类
2、引入ImportSelector的实现类
3、引入ImportBeanDefinitionRegister的实现类
以下以方式三为例:
配置类实现 ImportBeanDefinitionRegistrar 接口,可以自定义往容器中注册想注入的Bean。
该接口相比与 ImportSelector 接口的主要区别在于,ImportSelector接口是返回一个类,无法对这个类做操作, ImportBeanDefinitionRegistrar 是可以自己注入 BeanDefinition,添加属性等。
public class MyImportBeanRegistrar implements ImportBeanDefinitionRegistrar {/*** @param importingClassMetadata 当前类的注解信息* @param registry 注册类,registerBeanDefinition()可以注册bean*/@Overridepublic 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();/** 获取工厂方法的元数据*/@NullableMethodMetadata getFactoryMethodMetadata();
}
定义ImportBeanDefinitionRegister的实现类
参考博客:https://blog.csdn.net/qq_16504067/article/details/120201048
public class MyImportBean implements ImportBeanDefinitionRegistrar {/*** @param importingClassMetadata 当前类的注解信息* @param registry 注册类,registerBeanDefinition()可以注册bean*/@Overridepublic void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {// 获取要扫描的包路径//聚合扫描的路径Set<String> basePackages = getBasePackages(importingClassMetadata);//获取扫描器ClassPathBeanDefinitionScanner scanner = getScanner(registry);//扫描并注册bdfor (String basePackage : basePackages) {//获取com.luxifa包下,使用StudentConfig注解的bean,该处值为com.luxifa.TestSet<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/116642356ClassPathBeanDefinitionScannerscanner = 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文件中
#spring.factories 文件内容:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.xx.example.MyAutoConfiguration
Demo服务中,Test.java类使用自定义StudentConfig注解
参考博客:https://blog.csdn.net/weixin_53233197/article/details/128402888
package com.luxifa;@StudentConfig(name="degula",age=25)
public class Test {}