/**
* 自定义注解, 作用同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()方法
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, 通过给扫描器设置扫描的注解, 扫描的路径, 就会将该路径下的标有扫描注解的类进行注入
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 doScan(String... basePackages) {
return super.doScan(basePackages);
}
}
在自定义的扫描器中, 配置的扫描路基和注解
MyClassPathBeanDefinitionScanner类继承了spring提供的ClassPathBeanDefinitionScanner类, 顾名思义, 这个类就是用来扫描类, 将类转化为beanDefinition对象的
让我们进入MyImportBeanDefinitionRegistrar类的doScan方法进行源码追踪
protected Set doScan(String... basePackages) {
Assert.notEmpty(basePackages, "At least one base package must be specified");
Set beanDefinitions = new LinkedHashSet<>();
for (String basePackage : basePackages) {
// 进入findCandidateComponents方法
Set candidates = findCandidateComponents(basePackage);
for (BeanDefinition candidate : candidates) {
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
candidate.setScope(scopeMetadata.getScopeName());
String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
if (candidate instanceof AbstractBeanDefinition) {
postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
}
if (candidate instanceof AnnotatedBeanDefinition) {
AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
}
if (checkCandidate(beanName, candidate)) {
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
definitionHolder =
AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
beanDefinitions.add(definitionHolder);
registerBeanDefinition(definitionHolder, this.registry);
}
}
}
return beanDefinitions;
}
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 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定义的资源。
ClassPathBeanDefinitionScanner是springboot提供的, 它默认会扫描和启动类同级目录下的所有文件下的类, 如果类上标记了@Component注解(或者@Component是他们元注解, 比如@Service, @Controller等)就会被注入到容器中
源码解析 :
至此, @Component标记的类全部注入完成, 只有就是对beanDefinition对象赋默认值
创建一个项目, pom.xml包含
org.mybatis.spring.boot
mybatis-spring-boot-starter
2.1.4
首先查看mybatis的自动装配
进入到MapperScannerConfigurer类中
可以看到, 该类实现了BeanDefinitionRegistryPostProcessor接口, 项目启动时会执行postProcessBeanDefinitionRegistry()方法
可以看出, 该方法的主要作用就是创建一个ClassPathMapperScanner扫描器, 用来扫描@Mapper注解
可以推断, ClassPathMapperScanner应该是ClassPathBeanDefinitionScanner的子类
之后在类启动时, ClassPathMapperScanner扫描器就会将指定路径下的, 所有标记@Mapper注解的类注入到容器中
这就是Mybatis对象注入的全部流程
== 问题 : @Mapper注解都是标记在接口上, 那么接口什么时候生成的代理对象呢? ==