简介
- ImportBeanDefinitionRegistrar类只能通过其他类@Import的方式来加载,通常是启动类或配置类。
- 使用@Import,如果括号中的类是ImportBeanDefinitionRegistrar的实现类,则会调用接口方法,将其中要注册的类注册成bean。
使用自定义注解, 将bean注入到springboot容器中
项目结构
类代码
自定义注解
/**
* 自定义注解, 作用同spring @service注解
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyService {
}
需要被注入的类
/**
* 被注入的类
*/
@MyService
public class UserService {
public void print(){
System.out.println("userService对象注入成功");
}
}
启动类
@SpringBootApplication
@EnableAsync
@EnableScheduling
//在启动类上, 标记@Import注解, MyImportBeanDefinitionRegistrar类是ImportBeanDefinitionRegistrar子类
@Import({MyImportBeanDefinitionRegistrar.class})
public class Application {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(Application.class, args);
UserService bean = context.getBean(UserService.class);
bean.print();
}
}
在启动类上标记@Import注解, 将MyImportBeanDefinitionRegistrar类设置为属性, 项目启动时, 会执行MyImportBeanDefinitionRegistrar类中的registerBeanDefinitions()方法
MyImportBeanDefinitionRegistrar
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
//自定义的扫描类MyClassPathBeanDefinitionScanner, 实现了ClassPathBeanDefinitionScanner接口
// 当前MyClassPathBeanDefinitionScanner已被修改为扫描带有指定注解的类
MyClassPathBeanDefinitionScanner scanner = new MyClassPathBeanDefinitionScanner(registry, false);
// scanner.setResourceLoader(resourceLoader);
scanner.registerFilters();
scanner.doScan("com.hctrl");
}
}
在该类中, 自定义了一个扫描器MyClassPathBeanDefinitionScanner, 通过给扫描器设置扫描的注解, 扫描的路径, 就会将该路径下的标有扫描注解的类进行注入
MyClassPathBeanDefinitionScanner
public class MyClassPathBeanDefinitionScanner extends ClassPathBeanDefinitionScanner {
public MyClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters) {
super(registry, useDefaultFilters);
}
/**
* @addIncludeFilter 将自定义的注解添加到扫描任务中
* @addExcludeFilter 将带有自定义注解的类 ,不加载到容器中
*/
protected void registerFilters () {
/**
* addIncludeFilter 满足任意includeFilters会被加载
* 注入@MyService注解标记的类
*/
addIncludeFilter(new AnnotationTypeFilter(MyService.class));
/**
* addExcludeFilter 同样的满足任意excludeFilters不会被加载
* 可以配置过滤
*/
// addExcludeFilter(new AnnotationTypeFilter(MyService.class));
}
/**
* 重写类扫描包路径加载器,调用父类受保护的扫描方法 doScan
* @param basePackages
* @return
*/
@Override
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
return super.doScan(basePackages);
}
}
在自定义的扫描器中, 配置的扫描路基和注解 MyClassPathBeanDefinitionScanner类继承了spring提供的ClassPathBeanDefinitionScanner类, 顾名思义, 这个类就是用来扫描类, 将类转化为beanDefinition对象的 让我们进入MyImportBeanDefinitionRegistrar类的doScan方法进行源码追踪 ScannedGenericBeanDefinition对象是BeanDefinition接口的子类, 里面包含大量构建bean的属性
private volatile Object beanClass;//bean的类型
private String scope;//bean的作用范围
private boolean abstractFlag;//是否是抽象类
private boolean lazyInit;//是否延迟加载
private int autowireMode; //自动注入模式
private int dependencyCheck;//依赖检查,spring 3.0后弃用
private String[] dependsOn; //表示这个bean,依赖于其它beans先实例化
private boolean autowireCandidate;//设为false,则容器在自动装配时,将不考虑该bean(即这个bean不会作为其它bean自动装配的候选者),但是这个bean还可以自动装配其它bean
private boolean primary;//自动装配出现多个bean时,将它作为首选者
private final Map<String, AutowireCandidateQualifier> qualifiers;//用于记录Qualifier
private boolean nonPublicAccessAllowed;//允许访问非公开的构造器和方法
private boolean lenientConstructorResolution;//是否以宽松的模式解析构造函数,默认为true
private String factoryBeanName;//指定工厂类和工厂方法
private String factoryMethodName;
private ConstructorArgumentValues constructorArgumentValues;//记录构造函数注入属性
private MutablePropertyValues propertyValues;//普通属性集合
private MethodOverrides methodOverrides; //方法重写的持有者
private String initMethodName; //初始化方法
private String destroyMethodName; //销毁方法
private boolean enforceInitMethod; //是否执行初始化方法
private boolean enforceDestroyMethod;//是否执行销毁方法
private boolean synthetic;//是否是用户定义的而不是应用程序本身定义的,创建AOP时为true
private int role;//定义这个bean的使用,application:用户,infrastructure:完全内部使用,与用户无关;support:某些复杂配置的一部分
private String description;//bean的描述
private Resource resource;//这个bean定义的资源。
beanDefinition创建方法
@Component注解类注入原理
ClassPathBeanDefinitionScanner是springboot提供的, 它默认会扫描和启动类同级目录下的所有文件下的类, 如果类上标记了@Component注解(或者@Component是他们元注解, 比如@Service, @Controller等)就会被注入到容器中 源码解析 : 至此, @Component标记的类全部注入完成, 只有就是对beanDefinition对象赋默认值
mybatis 通过ImportBeanDefinitionRegistrar将所有的Mapper对象注入到容器中
前提
创建一个项目, pom.xml包含
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.4</version>
</dependency>
首先查看mybatis的自动装配 进入到MapperScannerConfigurer类中 可以看到, 该类实现了BeanDefinitionRegistryPostProcessor接口, 项目启动时会执行postProcessBeanDefinitionRegistry()方法
可以看出, 该方法的主要作用就是创建一个ClassPathMapperScanner扫描器, 用来扫描@Mapper注解 可以推断, ClassPathMapperScanner应该是ClassPathBeanDefinitionScanner的子类 之后在类启动时, ClassPathMapperScanner扫描器就会将指定路径下的, 所有标记@Mapper注解的类注入到容器中
这就是Mybatis对象注入的全部流程
== 问题 : @Mapper注解都是标记在接口上, 那么接口什么时候生成的代理对象呢? ==
|