回炉重造Spring 之 IoC
spring

Spring IoC即通过Spring IoC容器来负责容器的生命周期管理及容器对象之间的依赖关系。

初始如下常见代码示例中【小明想吃牛肉】:

public class Beef{
...
}

public class XiaoMing{
private Beef beef;
public XiaoMing(){
beef = new Beef();
}
public void eat(){
....;
}}

这里通过 new Beef() 生成一个新的对象进行 XiaoMing 的 Beef 属性的赋值,但是如果小明明后天想吃鱼肉、鸡肉 等情况下,我们不得不去手动修改 new 的部分,而且需要程序员自己去维护这个对象之间的依赖关系。

IoC的概念出现

IoC一般的解释为控制反转,那么什么是控制反转?
原来由程序员控制的对象依赖关系扔给 Spring IoC 容器去进行处理。
以下的内容不包括配置 xml 文件来描述 各个 Bean 之间的关系。

由此引出了DI 依赖注入的概念

这里先抛开 IoC的明细内容。
通过以上代码,我们是通过在构造器中手动new 一个对象注入,这里的入口控制是在 内部的 new 对象构造中,如果需要改变我们不得不改变代码,那么如何进行依赖注入的控制 使得代码的使用更加灵活,引入依赖注入的三种方式。

  1. 构造器注入:这里虽然也是构造器注入,但是我们将代码入口的可控制性提升到参数入口层面,可以想象下,原来我们是通过在XiaoMing的构造器内部 new 新的对象,现在我们只需要在 XiaoMing 的调用处进行控制,控制的入口暴露的更加上层了。不会关心内部的具体实现。同时我们只要将 具体类 Beef 抽象成抽象接口 Meat【在这里举例可能不够丰满】,在runtime 时候会根据具体的实现类进行灵活的调整,这样在鱼、鸡肉等肉食情况下我们都能满足。
public interface Meat{}

public class XiaoMing{
private Meat meat;
public XiaoMing(Meat meat){
this.meat = meat;
}
...}
  1. setter 注入:其实本质上和上一条没多大区别,只是具体实现的差异罢了。当然这里的控制更加灵活,在小明想好想吃啥的时候再进行控制吃啥,避免了在构造小明对象的时候就已经决定了吃啥。
pubclic interface Meat{}

public class XiaoMing{

private Meat meat;

public XiaoMing(){}

public void setMeat(Meat meat){
this.meat = meat;
}
}
  1. interface 接口注入:使用的不多,主要解释为被依赖的对象实现了其他不必要的接口,带有侵入性。

IoC 和 DI 的区别:个人理解 IoC 其实是一种理论思想而 DI 则更偏向于 具体实现

IoC 容器种类

在Spring 中我们的 Bean 全权托付给 IoC 容器管理,常见的 IoC 容器一般分为 BeanFactory、ApplicationContext 两种。

BeanFactory

public interface BeanFactory {
    String FACTORY_BEAN_PREFIX = "&";

    Object getBean(String var1) throws BeansException;

    <T> T getBean(String var1, Class<T> var2) throws BeansException;

    Object getBean(String var1, Object... var2) throws BeansException;

    <T> T getBean(Class<T> var1) throws BeansException;

    <T> T getBean(Class<T> var1, Object... var2) throws BeansException;

    <T> ObjectProvider<T> getBeanProvider(Class<T> var1);

    <T> ObjectProvider<T> getBeanProvider(ResolvableType var1);

    boolean containsBean(String var1);

    boolean isSingleton(String var1) throws NoSuchBeanDefinitionException;

    boolean isPrototype(String var1) throws NoSuchBeanDefinitionException;

    boolean isTypeMatch(String var1, ResolvableType var2) throws NoSuchBeanDefinitionException;

    boolean isTypeMatch(String var1, Class<?> var2) throws NoSuchBeanDefinitionException;

    @Nullable
    Class<?> getType(String var1) throws NoSuchBeanDefinitionException;

    String[] getAliases(String var1);
}

可以发现BeanFactory实际上就是一个Interface接口,提供了基本能力行为约束。

ApplicationContext

通过源码发现我们会发现实际上ApplicationContext 实际上是扩展了BeanFactory接口,进行了功能增强。
WX20200828-110448@2x.png

  • BeanFactory
  • ApplicationEventPublisher:用于封装事件接口功能,向事件监听器发送消息
  • ResourceLoader:Spring 顶层 资源加载器,用于加载资源
  • MessageSource:解析Message策略接口,比如支持国际化等
  • EnvironmentCable:用于获取Env的接口。

WX20200828-111459@2x.png
通过继承关系举例,WebServerApplicationContext是 ApplicationContext 的直接子接口,ConfigurableWebServerApplicationContext是 ConfigableApplicationContext和WebServerApplicationContext的共同子类。

//用于获取Web相关的上下文。
public interface WebServerApplicationContext extends ApplicationContext {
    WebServer getWebServer();

    String getServerNamespace();
}


//包括了对于生命周期及资源释放关闭的功能。
public interface ConfigurableApplicationContext extends ApplicationContext, Lifecycle, Closeable {
    String CONFIG_LOCATION_DELIMITERS = ",; \t\n";
    String CONVERSION_SERVICE_BEAN_NAME = "conversionService";
    String LOAD_TIME_WEAVER_BEAN_NAME = "loadTimeWeaver";
    String ENVIRONMENT_BEAN_NAME = "environment";
    String SYSTEM_PROPERTIES_BEAN_NAME = "systemProperties";
    String SYSTEM_ENVIRONMENT_BEAN_NAME = "systemEnvironment";

    void setId(String var1);

    void setParent(@Nullable ApplicationContext var1);

    void setEnvironment(ConfigurableEnvironment var1);

    ConfigurableEnvironment getEnvironment();

    void addBeanFactoryPostProcessor(BeanFactoryPostProcessor var1);

    void addApplicationListener(ApplicationListener<?> var1);

    void addProtocolResolver(ProtocolResolver var1);

    void refresh() throws BeansException, IllegalStateException;

    void registerShutdownHook();

    void close();

    boolean isActive();

    ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;
}

相比较而言 BeanFactory 为低级容器工厂,而ApplicationContext为高级容器工厂,里面增强了新的功能。

常见的BeanFactory 为XmlBeanFactory,不过现已被建议废弃。

/** @deprecated */
@Deprecated
public class XmlBeanFactory extends DefaultListableBeanFactory {
    private final XmlBeanDefinitionReader reader;

    public XmlBeanFactory(Resource resource) throws BeansException {
        this(resource, (BeanFactory)null);
    }

    public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
        super(parentBeanFactory);
        this.reader = new XmlBeanDefinitionReader(this);
        this.reader.loadBeanDefinitions(resource);
    }
}

WX20200828-112740@2x.png
在此包下面我们会看到常见的扩展于ApplicationContext的常见容器工厂,比较常见的为

  • ClassPathXmlApplicationContext
  • FileSystemXmlApplicationContext
  • XmlWebApplicationContext

WX20200828-113822@2x.png

WX20200828-114037@2x.png

举例ClassPathXmlApplicationContext

简单示例:

ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
StudentService studentService = (StudentService)ac.getBean("studentService");

WX20200828-125433@2x.png

关键性的顶层接口有:

  • BeanFactory: Spring 容器管理
  • ResourcePatterReslover: 资源加载
  • MessageSource:message国际化
  • Closeable:资源释放关闭
  • LifeCycle:生命周期管理
  • InitializingBean:自定义初始化
  • BeanNameAware:设置 beanName 的 Aware 接口
  • ApplicationEventPublisher:事件发布

关键接口详解分析

ApplicationEventPublisher

既然到了事件与监听过程,那么就不得不讲到设计模式中的观察者模式

观察者模式

实际上观察者模式可以抽象为4个部分:

  1. Subject : 用于抽象 事件动作,同时存放对事件通知者的一些 常规操作,如 add、remove 操作,一般来说事件通知者通过列表来存放,然后抽象需要通知的事件操作。
  2. Observer:抽象事件通知者
  3. ConcreteSubject:实现类
  4. ConcreteObject:实现类

对应的 UML 类图关系如下:

WX20200828-175448@2x.png

简单的示例代码如下:

public abstract Subject{
        protected List<Observer> list = new ArrayList<>();

        public void add(Observer o){
                list.add(o);
        }

        public void remove(Observer o){
                list.remove(o);
        }

        public abstract notifyObserver(){}
}

public interface Observer{
        void notifyObserver();
}

public class ConcreteSubject extends Subject{
        @Override
        public void notifyObserver(String msg){
                for(Observer item;list){
                        item.notifyObserver(msg);
                }
        }
}

public class ConcreteObserver extends Observer{
        public void notifyObserver(String  msg){
                ....;
        }
}

JDK 中对事件监听机制的支持

深究源码我们发现关键类

public class EventObject implements java.io.Serializable {

    private static final long serialVersionUID = 5516075349620653480L;

    /**
     * The object on which the Event initially occurred.
     */
    protected transient Object  source;

    /**
     * Constructs a prototypical Event.
     *
     * @param    source    The object on which the Event initially occurred.
     * @exception  IllegalArgumentException  if source is null.
     */
    public EventObject(Object source) {
        if (source == null)
            throw new IllegalArgumentException("null source");

        this.source = source;
    }

    /**
     * The object on which the Event initially occurred.
     *
     * @return   The object on which the Event initially occurred.
     */
    public Object getSource() {
        return source;
    }

    /**
     * Returns a String representation of this EventObject.
     *
     * @return  A a String representation of this EventObject.
     */
    public String toString() {
        return getClass().getName() + "[source=" + source + "]";
    }
}

/**
 * A tagging interface that all event listener interfaces must extend.
 * @since JDK1.1
 */
public interface EventListener {
}

在此基础上 需要我们根据实际的场景来扩展或者实现以上关键类,综上所述,另外需要自定义的就是时间发布器

Spring 容器对事件监听的支持

Spring 中对应的如下:

public abstract class ApplicationEvent extends EventObject {
    private static final long serialVersionUID = 7099057708183571937L;
    private final long timestamp = System.currentTimeMillis();

    public ApplicationEvent(Object source) {
        super(source);
    }

    public final long getTimestamp() {
        return this.timestamp;
    }
}

WX20200828-182926@2x.png

@FunctionalInterface
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
    void onApplicationEvent(E var1);
}

WX20200828-183135@2x.png

事件发布器为 ApplicationEventPublisher:

@FunctionalInterface
public interface ApplicationEventPublisher {
    default void publishEvent(ApplicationEvent event) {
        this.publishEvent((Object)event);
    }

    void publishEvent(Object var1);
}

通过关系图如下:
WX20200828-183730@2x.png
通过继承关系继续深究:
WX20200828-183953@2x.png
深究源码发现:
WX20200828-184102@2x.png
所以,真正的事件发布器是ApplicationEventMulticaster,这是一个接口,定义了事件发布器需要具备的基本功能:管理事件监听器以及发布事件。其默认实现类是
SimpleApplicationEventMulticaster,该组件会在容器启动时被自动创建,并以单例的形式存在,管理了所有的事件监听器,并提供针对所有容器内事件的发布功能。

简述IoC实现机制

简单的理解就是 工厂模式+反射机制

public interface Fruit{
        void eat();
}
public class Apple implements Fruit{
        @Override
        publict void eat(){
            ...;
        }
}

public class Orange implements Fruit{
        @Overrid
        public void eat(){
            ...;
        }
}

public class Factory{
        public static getInstance(String str){
                Fruit f= null;
                try{
                        f = (Fruit)Class.forName(str).newInstance();
                }catch (Exception e){
                        e.printStackTrace();
                }
                return f;
        }
}

BeanFactory 与 FactoryBean 区别

在Spring 中很多博客中我们会看到BeanFactory及FactoryBean的区别分析,在此我也记录下个人理解。
BeanFactory 可以提供对Bean 的实例化与管理,另外Spring 也提供了FactoryBean 让我们来做自定义增强,比如一些逻辑的实现与处理的Bean扩展,通过xml配置实现比较困难。

public interface FactoryBean<T> {
    @Nullable
    T getObject() throws Exception;

    @Nullable
    Class<?> getObjectType();

    default boolean isSingleton() {
        return true;
    }
}

在FactoryBean 中应用了工厂模式及装饰器模式。这样可以将复杂的Bean实例化过程封装起来,让使用者无需关系具体的实现过程。

Spring 框架中的事件类型

WX20200828-221023@2x.png
Spring 提供了5 种标准的事件类型:

上下文更新事件

  • ContextRefreshedEvent 事件,该事件会在ApplicationContext被初始化或者更新时发布,也可以在调用ConfigurableApplicationContext 接口中的 #refresh() 方法时被触发。
  • 上下文开始事件(ContextStartedEvent):当容器调用ConfigurableApplicationContext 的 #start() 方法开始/重新开始容器时触发该事件。
  • 上下文停止事件(ContextStoppedEvent):当容器调用 ConfigurableApplicationContext 的 #stop() 方法停止容器时触发该事件。
  • 上下文关闭事件(ContextClosedEvent):当ApplicationContext 被关闭时触发该事件。容器被关闭时,其管理的所有单例 Bean 都被销毁。
  • 请求处理事件(RequestHandledEvent):在 We b应用中,当一个HTTP 请求(request)结束触发该事件。

如何实现自定义的事件:

  1. 扩展 ApplicationEvent 实现自定义的事件
public class CustomApplicationEvent extends ApplicationEvent{  

    public CustomApplicationEvent(Object source, final String msg) {  
        super(source);
    }  

}
  1. 创建自定义的监听器
public class CustomApplicationListener implements ApplicationListener<CustomApplicationEvent> {

    @Override  
    public void onApplicationEvent(CustomApplicationEvent applicationEvent) {  
        ....;
    }
    
}
  1. 通过ApplicationContext 的 publishEvent 进行发布
// 创建 CustomApplicationEvent 事件
CustomApplicationEvent customEvent = new CustomApplicationEvent(applicationContext, "Test message");
// 发布事件
applicationContext.publishEvent(customEvent);

目前先写到这么多,后续有新的想法继续增添内容。

暂无评论