Java后端必备Java Web知识Spring

SpringIOC不可不知

2018-11-28  本文已影响1人  关捷

Spring是一个非侵入的、轻量级的构建企业级应用的解决方案。它采用的是模块化设计,能够简单的开箱即用,它的无侵入设计,使得开发人员能够专注于业务逻辑的开发,而这些都是建立在IOC容器基础上的。

定版本

Spring不同的版本的实现还是有些差距的,不定版本,将没法达成共识,后续的代码都是通过spring-framework-bom约定4.3.20.RELEASE版本。

<parent>
    <groupId>org.springframework</groupId>
    <artifactId>spring-framework-bom</artifactId>
    <version>4.3.20.RELEASE</version>
</parent>
<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-beans</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
    </dependency>
</dependencies>

使用介绍

通过下面三个类,采用Java-based配置方式启动容器,来进行SpringIOC的演示。

@Component
public class Car {
    @Autowired
    private Wheel wheel;
    public void work() {
        System.out.println("轮子【 " + wheel + " 】动了");
    }
}
@Component
public class Wheel {
}
@Configuration
//扫描的路径以实际为准
@ComponentScan(basePackages = "com.esy.stu")
public class BootStrap {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context =
                new AnnotationConfigApplicationContext(BootStrap.class);
        context.getBean(Car.class).work();
    }
}

运行:轮子【 com.esy.stu.Wheel@73d4cc9e 】动了

例子展示的是Spring最核心的功能,具有依赖注入,控制反转功能的IOC容器。

如果没有Spring,上述的功能,将为以下面的方式实现:

Car car = new Car();
car.wheel = new Wheel();
car.work();

虽然例子比较简单,不能体现实际情况,但不通过Spring,在真实的业务场景下,每个类都依赖一堆的对象,每个对象又有一堆依赖,要得到完整的目标对象,进行的组装工作将会是一个怎样的噩梦?

由此可见,在现在的企业级开发中,Spring可以说极大的简化了开发工作,几乎不可或缺。

这种对象自动装配的功能也被称作依赖注入,也叫控制反转。

BeanFactory是IOC容器,AnnotationConfigApplicationContext是Spring上下文也叫Spring容器,是Spring对外的门面,它通过代理模式,将调用传递给真正的组件,例如:context.getBean()真正的处理逻辑在BeanFactory中实现。

过程分解

AnnotationConfigApplicationContext是Spring对外的门面,内部包含了很多可拔插的组件,用来提供Spring对外的服务。也正是由于这些灵活的可拔插的组件,使得Spring这样大型的项目便于维护。

Spring整个容器的启动,其实可以粗略的分为三步:


而组件按照功能也可以简单的分为两类:一类搜集bean定义、一类实例化组装bean。

搜集Bean

实例化Bean

DefaultListableBeanFactory生成Bean

首先通过一个简单的例子,演示DefaultListableBeanFactory功能。

public static void main(String[] args) {
    class Foo {
        public String fun() {
            return "我是Foo";
        }
    }
    DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
    beanFactory.registerBeanDefinition("foo", new AnnotatedGenericBeanDefinition(Foo.class));
    System.out.println(beanFactory.getBean(Foo.class).fun());
}

运行:我是Foo

beanFactory是生成Bean的工厂,原料就是BeanDefinition。他本身实例化过程中需要调用很多的接口方法,通过这些接口方法来完善整个Bean的组装。所以上面的例子中,并没有依赖注入的功能。

AutowiredAnnotationBeanPostProcessor 装配Bean

Spring的实例化过程要做的事情非常多,如果整个流程是流水线模式,那么不但代码极度臃肿,并且难以维护与测试。所以整个实例化Bean的功能,被分解成为多个实现,例如:装配、校验、初始化方法以及Aop等等,下面演示下依赖注入:

public static void main(String[] args) {
    class Foo {
        public String fun() {
            return "我是Foo";
        }
    }
    class Bar {
        @Autowired
        Foo foo;
        public String fun() {
            return "我是Bar , " + foo.fun();
        }
    }
    DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
    beanFactory.registerBeanDefinition("foo", new AnnotatedGenericBeanDefinition(Foo.class));
    beanFactory.registerBeanDefinition("bar", new AnnotatedGenericBeanDefinition(Bar.class));
    AutowiredAnnotationBeanPostProcessor beanPostProcessor = new AutowiredAnnotationBeanPostProcessor();
    beanPostProcessor.setBeanFactory(beanFactory);
    beanFactory.addBeanPostProcessor(beanPostProcessor);
    System.out.println(beanFactory.getBean(Bar.class).fun());
}

运行:我是Bar , 我是Foo

可见@Autowired注解标注的Foo,被自动的进行注入装配了,形成了完整的Bean实例。而装配的思路其实也是非常的简单。

上面的过程貌似存在循环引用的问题,举个例子,看看循环引用我们是怎么解决的,

static class Foo {
    @Autowired
    Bar bar;
}
static class Bar {
    @Autowired
    Foo foo;
}
public static void main(String[] args) {
    Foo foo = new Foo();
    Bar bar = new Bar();
    foo.bar = bar;
    bar.foo = foo;
}

可以看出,一个对象能进行赋值操作的唯一条件就是,它被实例化了。所以在Spring中也是一样,只需要分解为两个步骤,实例化与装配,就完美的解决了这个问题。

整个实例化装配的过程如下图:

ConfigurationClassPostProcessor配置解析

通过java-based方式启动容器的过程中,最为主要的就是带有Configuration注解的配置类,ConfigurationClassPostProcessor就是用来解析配置类中相关注解的,包括:

@Configuration
public class ConfigurationClassPostProcessorDemo {
    public static void main(String[] args) {
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        beanFactory.registerBeanDefinition("ConfigurationClassPostProcessorDemo", new AnnotatedGenericBeanDefinition(ConfigurationClassPostProcessorDemo.class));
        ConfigurationClassPostProcessor configurationClassPostProcessor = new ConfigurationClassPostProcessor();
        configurationClassPostProcessor.postProcessBeanDefinitionRegistry(beanFactory);
        System.out.println(beanFactory.getBean(Executor.class));
    }
    @Bean
    public Executor executor() {
        return Executors.newCachedThreadPool();
    }
}

执行结果:java.util.concurrent.ThreadPoolExecutor@67b6d4ae[Running, pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 0]

通过这三个例子可以看出,BeanFactory中实现的是实例化,组装Bean的流程模版,通过插件增强整个流程。

上一篇下一篇

猜你喜欢

热点阅读