常用注解结构

当前IOC容器设计结构

可以看到分为了注解、核心、包扫描器3部分。

注解部分最基础的bean注解我们实现了Component,3层架构中的注解我们实现了Controller,Service,Repository,这3者均“继承”了Component(其实是在其注解定义中加入了注解@Component).

待补充:Autowired,Qualifier,Scope

BeanDefinition

核心部分,我们先介绍BeanDefinition,该类作为Bean元数据类,主要包含4个属性:用于反射类型,用于实例化的对象名,是否单例(2个属性用于描述)。

那么为何使用两个属性来表示是否单例?

reply: 无需多余的字符串比较,可直接由其中一个字段的bool值直接得到是否单例。这在判断性能上提升多倍。

1
2
3
4
5
6
7
8
9
@Data
@NoArgsConstructor
@AllArgsConstructor
public class BeanDefinition {
    private Class<?> beanClass;     // Bean的Class对象(用于反射创建实例)
    private String beanName;        // Bean的唯一标识符
    private String scope;           // 作用域(singleton/prototype)
    private boolean singleton;      // 是否单例的快速标志位
}

两个字段表示是否单例,也带来了新问题:我们设置信息时需要保证二者的一致性

1
2
3
4
5
6
7
8
9
public void setScope(String scope) {
    this.scope = scope;
    this.singleton = "singleton".equals(scope);  // 自动同步
}

public void setSingleton(boolean singleton) {
    this.singleton = singleton;
    this.scope = singleton ? "singleton" : "prototype";  // 自动同步
}

构造器方面,我们提供2个不同参数的构造器,区别是后者可以传入scope(即是否单例)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
  /**
     *两参数的构造
     */
    public BeanDefinition(Class<?> beanClass, String beanName) {
        this.beanClass = beanClass;
        this.beanName = beanName;
    }

    /**
     * 三个参数的构造,设置scope,singleton也要设置
     */
    public BeanDefinition(Class<?> beanClass, String beanName, String scope) {
        this.beanClass = beanClass;
        this.beanName = beanName;
        this.scope = scope;
        this.singleton = "singleton".equals(scope);
    }

BeanFactory接口与DefaultBeanFactory实现类

BeanFactory方面,我们实现了一个接口和一个实现类,主要功能包含:注册、获取bean(根据类型或者名称)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package cn.amebob.ioc.core;

public interface BeanFactory {

    
    /**
     * 注册bean
     */
    void registerBeanDefinition(String beanName, BeanDefinition beanDefinition);

    /**
     * 根据名称获取bean
     */
    Object getBean(String beanName);

    /**
     * 根据类型获取bean
     */
    <T> T getBean(Class<T> beanClass);

    /**
     * 是否包含指定bean
     */
    boolean containsBean(String beanName);

    /**
     * 获取存放bean信息的BeanDefinition
     */
    BeanDefinition getBeanDefinition(String beanName);
}

说完接口,就要开始说其实现类,这里是DefaultBeanFactory,用于bean的管理,包含3个属性

1
2
3
4
5
6
7
8
//用map分别存储完全实例化的单例bean,早期暴露的单例bean,bean定义
    //这种3级缓存机制,有效避免了循环依赖注入的问题
    //1.存储bean定义
    private final Map<String,BeanDefinition> beanDefinitionMap = new HashMap<>();
    //2.存储完全实例化的单例bean(一种缓存池)
    private final Map<String,Object> singletonBeanMap = new HashMap<>();
    //3.存储早期暴露的bean
    private final Map<String,Object> earlyExposedBeanMap = new HashMap<>();

用来返回bean的方法,主要针对单例bean进行缓存查找,非单例则直接创建并返回

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
    /**
     * 是单例bean,则先检查缓存,无则创建后返回bean;
     * 非单例,则直接创建后返回bean
     */
    @Override
    public Object getBean(String beanName) {
        //1.检查有无bean定义
        if(!beanDefinitionMap.containsKey(beanName)){
            throw new RuntimeException("No bean definition found for " + beanName);
        }
        BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
        //是单例才执行2和3
        if(beanDefinition.isSingleton()){
            //2.检查单例缓存池
            if(singletonBeanMap.containsKey(beanName)){
                return singletonBeanMap.get(beanName);
            }
            //3.检查早期暴露缓存池
            if(earlyExposedBeanMap.containsKey(beanName)){
                return earlyExposedBeanMap.get(beanName);
            }
        }
        //4.创建bean

        Object bean = createBean(beanName,beanDefinition);
        //// 如果是非单例Bean,立即完成依赖注入
        if(!beanDefinition.isSingleton()){
            autowireFields(bean);
        }
        return bean;
    }

这里值得一提的是,创建单例bean时采用提前暴露,来杜绝循环注入问题,具体来说就是 ApplicationContext中先统一初始化单例bean,再统一注入单例bean,这分离了实例对象创建和注入,例如Bean A,B已经完成初始化创建,无论哪个先进行注入,都可以成功注入(注入的是半成品)。

在实例化完成后移动该bean到单例缓存池。即在注入完成后会调用promoteBean方法,其中非单例bean,在创建后就进行依赖注入,单例bean则统一进行依赖注入(这发生在所有单例bean对象初始化创建完成后)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
protected Object createBean(String beanName, BeanDefinition beanDefinition) {
    // 步骤1:反射创建Bean实例
    Object bean = beanDefinition.getBeanClass()
                                .getDeclaredConstructor()
                                .newInstance();

    // 步骤2:单例Bean提前暴露(关键设计!)
    if (beanDefinition.isSingleton()) {
        earlySingletonObjects.put(beanName, bean);  // 暴露半成品
    }

    // 步骤3:返回半成品Bean
    return bean;  // 注意:不放入singletonObjects
}
1
2
3
4
public void promoteBean(String beanName, Object bean) {
    earlySingletonObjects.remove(beanName);  // 从半成品池移除
    singletonObjects.put(beanName, bean);    // 放入成品池
}

依赖注入时,优先按名注入

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
    private void autowireFields(Object bean){
        //1.获取注解信息
        Field[] fields = bean.getClass().getDeclaredFields();
        for(Field field : fields){
            if(field.isAnnotationPresent(Autowired.class)){
                try {
                    field.setAccessible( true); //允许访问其他类的成员变量
                    //优先按名注入
                    Object dependentBean = null;
                    if(field.isAnnotationPresent(Qualifier.class)){
                        Qualifier qualifier = field.getAnnotation(Qualifier.class);
                        String beanName = qualifier.value();
                        dependentBean = getBean(beanName);
                    }else{
                        //其次根据类型注入
                        dependentBean = getBean(field.getType());
                    }
                    field.set(bean,dependentBean);
                } catch (Exception e) {
                    Autowired autowired = field.getAnnotation(Autowired.class);
                    if(autowired.required()){
                        throw new RuntimeException("依赖注入失败: " + bean.getClass().getName() + "." + field.getName(), e);

                    }
                }
            }

        }


    }

ApplicationContext

下面要说的类呢,ApplicationContext目前是负责单例的初始化(之前,需要先扫描包)和依赖注入。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
    //1.引入bean工场,对bean进行管理
    private final DefaultBeanFactory beanFactory;

    public ApplicationContext(String basePackage) {
        //a.创建bean工厂
        beanFactory = new DefaultBeanFactory();
        //b.扫描包,将扫描到的bean定义注册到bean工厂中
        scanAndRegisterBean(basePackage);
        //c.初始化bean
        initSingletonsBean();
        //d.注入依赖
        autowireBean();
    }

首先调用ClassScanner的方法扫描包,再调用bean工厂的方法进行bean注册

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
 //2.扫描包,注册bean
    private void scanAndRegisterBean(String basePackage) {
        //a.扫描包
        List<BeanDefinition> beanDefinitions = ClassScanner.scan(basePackage);
        //b.注册bean
        for(BeanDefinition beanDefinition : beanDefinitions){
            beanFactory.registerBeanDefinition(beanDefinition.getBeanName(),beanDefinition);
        }

    }

初始化bean,是初始化单例bean,非单例bean,则采取懒加载的方式,在获取时直接创建并返回;初始化后接着进行依赖注入    

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
//3.初始化单例bean
    private void initSingletonsBean() {

        Map<String,BeanDefinition> beanDefinitionMap = beanFactory.getBeanDefinitionMap();

        for(Map.Entry<String,BeanDefinition> entry : beanDefinitionMap.entrySet()){
            //获取键值对Map.Entry<String,BeanDefinition> entry
            //返回全部键值对beanDefinitionMap.entrySet()
            //增加两个变量提升可读性
            String beanName = entry.getKey();
            BeanDefinition beanDefinition = entry.getValue();
            if(beanDefinition.isSingleton()){
                beanFactory.getBean(beanName);
            }
        }
    }

    //4.自动注入bean
    private void autowireBean() {
        //这里也是只处理单例(非单例创建后直接返回即可)
        Map<String,Object> earlyExposedBeanMap = beanFactory.getEarlyExposedBeanMap();
        Map<String,Object> beansToBuild = new HashMap<>(earlyExposedBeanMap);
        for(Map.Entry<String,Object> entry : beansToBuild.entrySet()){
            String beanName = entry.getKey();
            Object bean = entry.getValue();
            //a.注入
            autowireFields(bean);
            //b.提升到完成的bean,即提升到singletonBeanMap
            beanFactory.promoteBean(beanName,bean);
        }


    }

非单例bean,不进行初始化,直接调用bean工厂的getbean方法,该方法会直接返回一个创建好的非单例bean,且在返回前完成依赖注入(注入的依赖是单例的哦,并未能解决多例和多例间的依赖注入)

1
2
3
  public Object getBean(String beanName) {
        return beanFactory.getBean(beanName);
    }

ClassScanner

这个类用于包扫描,并返回beanDefinition类型的列表(记录包下所以类的信息)

主要涉及,递归遍历文件夹,扫描记录类上的注解(bean名称、Class、Scope),

得到包名

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
    /**
     * 扫描指定包下的类
     */
    public static List<BeanDefinition> scan(String basePackage) {
        List<BeanDefinition> beanDefinitions = new ArrayList<>();

        try {
            String path = basePackage.replace(".", "/");
            //URL对象用于文件定位
            URL url = Thread.currentThread().getContextClassLoader().getResource(path);
            if(url == null) {
                System.err.println("未找到包: " + basePackage);
                return beanDefinitions;
            }
            //File 对象用于文件操作
            File packageDir = new File(url.getFile());
            //递归扫描该文件夹下所有的类
            scanClasses(packageDir,basePackage,beanDefinitions);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return beanDefinitions;
    }

得到Class

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
  private static void scanClasses(File packageDir, String packageName, List<BeanDefinition> beanDefinitions) {
        //1.检查文件夹是否存在
        if(!packageDir.exists() || !packageDir.isDirectory()){
            return;
        }
        //2.获取文件夹下的所有文件
        File[] files = packageDir.listFiles();
        //3.递归扫描,获取所有类
        for(File file : files){
            //分别处理目录和类文件,目录递归遍历,类文件进行处理
            if(file.isDirectory()){
                scanClasses(file,packageName+"."+file.getName(), beanDefinitions);
            }else if(file.getName().endsWith(".class")){
                //格式化类名(带包格式)
                String className = packageName + "." + file.getName().replace(".class", "");
                //利用反射机制,检测当前类是否被@Component注解,即是否需要实例化

                try {
                    Class< ?>clazz = Class.forName(className); //获取Class对象
                    //进行注解解析
                    BeanDefinition beanDefinition = parseBeanDefinition(clazz);
                    if(beanDefinition != null){
                        beanDefinitions.add(beanDefinition);
                    }
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                }


            }
        }
    }

解析注解信息,与ag-0-1j7lvvlo4ag-1-1j7lvvlo4生成默认bean名称

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
 /**
     * 解析类文件中的注解信息,生成BeanDefinition
     */
    private static BeanDefinition parseBeanDefinition (Class<?> clazz){
        //获取注解,无注解返回null,有注解,获取注解上的信息(bean名称,scope ..),
        // 如果没有指定beanName,则调用方法生成,获取Scope注解,以生产单例或者多例
        String beanName = null;
        String scope = "singleton";

        //1.获取注解
        if(clazz.isAnnotationPresent(Component.class)){
            Component component = clazz.getAnnotation(Component.class);
            beanName = component.value(); //获取注解上的beanName
        }// 检查@Service注解
        else if (clazz.isAnnotationPresent(Service.class)) {
            Service service = clazz.getAnnotation(Service.class);
            beanName = service.value();
        }
        // 检查@Repository注解
        else if (clazz.isAnnotationPresent(Repository.class)) {
            Repository repository = clazz.getAnnotation(Repository.class);
            beanName = repository.value();
        }
        // 检查@Controller注解
        else if (clazz.isAnnotationPresent(Controller.class)) {
            Controller controller = clazz.getAnnotation(Controller.class);
            beanName = controller.value();
        }else{
            return null;
        }

        //2.没有指定名称,生成默认beanName
        if(beanName == null || beanName.isEmpty()){
            beanName = getBeanName(clazz);
        }
        //3.获取Scope注解
        if(clazz.isAnnotationPresent(Scope.class)){
            Scope scopeAnnotation = clazz.getAnnotation(Scope.class);
            scope = scopeAnnotation.value();
        }

        return new BeanDefinition(clazz,beanName,scope);
    }

    /**
     * 生成Bean的名称,以小写字母开头
     */
    private static String getBeanName(Class<?> clazz){
        String simpleName =clazz.getSimpleName();
        return simpleName.substring(0,1).toLowerCase() + simpleName.substring(1);
    }