Annotation翻译:注解
拿到spring配置类之后,构造方法内部 会解析配置类AppConfig类,即会解析当前AppConfig类中,或者类上面,有哪些spring提供的注解。
解析配置类,主要就是看类中、类上的注解的。
1.拿到注解@ComponentScan
所以构造方法中,可以判断传进来的配置类,有没有注解ComponentScan
2.获取扫描路径
拿到注解对象 componentScanAnnotation 之后,就可以获取里面的属性值,也就是扫描路径
3.扫描
在路径 zhouyu\service 包中扫描类,如何根据包名得到该目录下所有的类?
使用 应用程序类加载器,把包加载到jvm里,得到class对象,得到class对象之后,才能知道这些类里面是不是有component注解。
拿到 resource 目录,并把目录转成文件(转成文件比较好用),得到file
判断 file 是不是目录
是目录的话,就遍历目录,打印出来目录
可以看到有两个类文件
4.查看类是否有 @Component 注解
看到了两个类,使用类加载器的 loadClass 方法(参数:class 的权限定名称),
看这个类是不是有@Component注解,有的话,就表示当前这个类是一个Bean
5.创建 Bean 对象
发现有Component注解之后,如何创建 Bean 对象
Bean 的作用域:单例 Bean,原型 Bean
如果是单例 Bean,三次 getBean 方法,返回的是同一个对象
如果是原型 Bean,三次 getBean 方法,返回的是三个不同的对象
单例 Bean 如何实现:
使用map ,这样每次 getBean 的时候,直接从map里面,看到beanName一样,就直接拿到同一个bean对象。这个Map,就是 单例池。
难点:何时创建单例Bean,原型Bean? 如何创建单例Bean,原型Bean?
单例 Bean,用的 ConcurrentHashMap,生成 singletonObjects 对象,即单例池
什么时候往 Map (单例池)里面存内容?
难道每次发现 Component 注解,就生成 Bean , 放到单例池里吗?,当然不是啦。
5.1 使用 BeanDefinition 解析类
解析类,判断当前 Bean 是单例 Bean,还是原型(ProtoType) Bean
每次调用 getBean方法,里面都会传入 BeanName,如何根据 BeanName 判断是单例还是原型呢?
难点:根据传来的字符串,找到对应的 类,然后解析类里面的 Scope 注解,看是单例还是原型的,难点在于如何根据字符串,找到对应的类
而且,每次 getBean 的时候都要解析类,看Scope吗?不用,使用 BeanDefinition (Bean定义),用来解析类的。
解析类BeanDefinition,其实是解析Bean 的注解、类型
每解析一个类,就会生成一个 BeanDefinition 对象。
5.1.1 创建 BeanDefinition 类
在spring包中创建 BeanDefinition
5.1.2 回到ApplicationContext 构造方法中
回到该构造方法中 扫描注解这段代码里
拿到component注解,并通过注解拿到 beanName
1.创建 beanDefinition 对象
2.看看当前扫描到的类,有没有 Scope 注解
3.有的话,就拿到 Scope 注解,并将 Scope注解的value值传给 beanDefinition
4.没有的话,就设置为“单例Bean”
这样,每扫描出来一个类,就解析出来一个Bean的定义beanDefinition,然后可以存到一个Map里面
创建一个存 beanDefinition 的Map
把 beanDefinition 存到Map里
小修改,之前在 ApplicationContext 构造方法中实现的扫描组件,并生成 beanDefinitionMap 的逻辑被封装到了 Scan 方法里,然后在 ApplicationContext 构造方法里调用这个Scan方法。
扫描之后的结果就是生成了一个 beanDefinition 构成的 Map
5.2 创建单例Bean
扫描完了之后,要把容器里面的单例Bean,全部给创建好。
所以遍历 Map 中的 beanDefinition,并查看bean的作用域是不是单例的
如果是单例的,就调用 createBean 方法,得到一个 bean 对象,然后放到单例池中
5.3 createBean 方法
里面参数是 beanDefinition ,也就是根据bean的定义,创建 bean 对象
利用beanDefinition的getClass方法,获取到bean的类型,然后反射,创建bean对象
5.4 getBean 方法
如果 beanDefinition 的 Map 里面,有这个 beanDefinition,就。。。。,否则,抛异常。
然后把beanName对应的 beanDefinition 对象拿出来,然后判断是单例还是原型
如果这个Bean 是单例的,那就应该从单例池里面去拿 bean对象,然后返回
这样就可以保证多次getBean,单例bean的话,可以返回同一个对象
否则,原型bean的话,就调用 createBean 方法,然后返回bean