手写Spring Config,最终一战,来瞅瞅撒!

配置分析

为什么要提供配置的方式呢,之前的内容中我们测试的时候都是通过代码来进行的:

GeneralBeanDefinition bd = new GeneralBeanDefinition();
bd.setBeanClass(Lad.class);
List<Object> args = new ArrayList<>();
args.add("sunwukong");
args.add(new BeanReference("magicGril"));
bd.setConstructorArgumentValues(args);
bf.registerBeanDefinition("swk", bd);

bd = new GeneralBeanDefinition();
bd.setBeanClass(MagicGril.class);
args = new ArrayList<>();
args.add("baigujing");
bd.setConstructorArgumentValues(args);
bf.registerBeanDefinition("magicGril", bd);

下面看下平时使用的时候,通过配置是什么样的:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="girl" class="di.MagicGirl"
     init-method="start" destroy-method="end">
        <constructor-arg type="java.lang.String" value="girl"></constructor-arg>
        <property name="friend" ref="boy"></property>
    </bean>

    <bean id="boy" class="di.Lad">
        <constructor-arg type="java.lang.String" value="boy"></constructor-arg>
        <constructor-arg type="di.MagicGirl" value="girl"></constructor-arg>
    </bean>
</beans>

可以看出,提供配置的方式的优点:

  • 实用简单,改动起来比较灵活
  • 而且不需要改动代码

常用的配置方式,就是XML和注解的形式,它们的工作过程如下:

image.png

配置的工作过程

定义XML标记和注解

需要定义什么样的XML标记和注解呢?通过之前的内容知道,配置的内容就是Bean定义信息,那么Bean定义的内容就是需要配置的内容

首先来看下Bean定义接口中有哪些信息:

image.png

XML配置的方式,首先需要定义一个DTD或者XSD文档,来定义一套标记信息,去指定Bean定义

<bean id="girl" class="di.MagicGirl"
     init-method="start" destroy-method="end">
        <constructor-arg type="java.lang.String" value="girl"></constructor-arg>
        <property name="friend" ref="boy"></property>
</bean>

可以看出,bean的配置指定的内容就是Bean定义接口中的信息

注解的方式,需要定义一套注解,那么需要哪些注解呢,也是Bean定义接口中的内容:

  • 指定类、指定BeanName、指定scope、指定工厂方法、指定工厂Bean、指定init method、指定destroy method,这些在我们使用Spring的时候是通过@Component来实现的
  • 指定构造参数的依赖:@Autowired、@Qualifier
  • 指定属性依赖:@Value

Bean配置的解析

Bean配置的解析过程,需要单独的接口来实现,而不是在BeanFactory中来做,要做到单一职责原则,所以需要定义单独的接口来解析Bean配置,然后再向BeanFactory注册Bean定义

ApplicationContext接口

ApplicationContext这个接口就是用来完成Bean配置解析的,上面说到实现配置的方式有XML和注解,所以会有两个实现类来实现ApplicationContext接口

image.png

  1. XML方式的实现:
  • XML文件可能存在多个,所以这里使用了list
  • 需要完成:加载xml、解析xml、创建Bean定义、注册Bean定义的任务
  1. 注解方式的实现
  • 扫描的包也会存在多个,这里也使用list
  • 需要完成:扫描包、获取注解、创建Bean定义、注册Bean定义的任务

因为需要创建和注册Bean定义,所以会使用到BeanFactory和BeanDefinitionRegistry接口,那么这部分代码在子类中分别实现的话就会重复,所以抽象出来放在父类中:

image.png

用户在使用的使用需要知道哪些接口和类呢?

  1. 指定配置相关:xml、注解
  2. 获取bean相关:BeanFactory

那么可以使用外观模式,让用户只需要知道ApplicationContext和其子类就行了,ApplicationContext可以继承BeanFactory,继而把两个接口合在一起:

image.png

ApplicationContext接口:

/**
 * @className: ApplicationContext
 * 用来构建整个应用环境的接口,用来完成Bean的配置和解析
 * 1:为了减少用户对框架类接口的依赖,扩展了BeanFactory接口,
 * Bean的配置和Bean的获取都可以通过ApplicationContext接口来完成
 * 2:配置资源的方式有xml和注解,所以存在xml和注解两种子类的实现
 * 3. Bean配置解析首先需要加载,所以实现了配置资源Resource的加载接口ResourceLoader
 * @author: TR
 */
public interface ApplicationContext extends ResourceLoader,BeanFactory {

}

ApplicationContext的抽象类实现

/**
 * @className: AbstractApplicationContext
 * @description: ApplicationContext的抽象类实现
 * @author: TR
 */
public abstract class AbstractApplicationContext implements ApplicationContext {

    /** 用组合的方式来持有BeanFactory,完成BeanFactory接口的方法 */
    protected BeanFactory beanFactory;

    public AbstractApplicationContext() {
        super();
        this.beanFactory = new PreBuildBeanFactory();
    }

    public AbstractApplicationContext(BeanFactory beanFactory) {
        super();
        this.beanFactory = beanFactory;
    }

    @Override
    public Object getBean(String beanName) throws Exception {
        return this.beanFactory.getBean(beanName);
    }

    @Override
    public void registerBeanPostProcessor(BeanPostProcessor beanPostProcessor) {
        this.beanFactory.registerBeanPostProcessor(beanPostProcessor);
    }
}

xml配置方式的ApplicationContext实现类

/**
 * @className: XmlApplicationContext
 * @description: xml配置方式的ApplicationContext实现类
 * @author: TR
 */
public class XmlApplicationContext extends AbstractApplicationContext {

}

注解配置方式的ApplicationContext实现类

/**
 * @className: AnnotationApplicationContext
 * @description: 注解配置方式的ApplicationContext实现类
 * @author: TR
 */
public class AnnotationApplicationContext extends AbstractApplicationContext {

}

猜你喜欢

转载自blog.csdn.net/qq_41701956/article/details/118159022
今日推荐