Spring combat | The first part of the core of Spring (first chapter Spring Tour)

  • Spring's bean container
  • Introduction Spring's core module
  • Spring more powerful ecosystem
  • New features of Spring

First, simplify the development of java

In order to reduce the complexity of the development of Spring, Spring Bell has taken the following 4 key strategies:

  • Lightweight and minimally invasive programming of POJO;
  • Dependency injection oriented interfaces and loose coupling;
  • Section and inertia based on declarative programming;
  • Cut and style code by reducing the template.

1, POJO excitation potential (i.e., common POJO java class)

2, injection dependency (dependency injection DI)

Dependency injection daunting word, and now has evolved into a complex programming skills or design pattern concept. But the fact that dependency injection is not as complicated as it sounds, DI application in the project, you will find that your code will become very simple and easier to understand and test.

① DI function is how to achieve

Procedures are a combination of a plurality of classes, complete collaboration between the specific business logic classes. According to the traditional approach, each object with the object itself is responsible for managing mutual cooperation (ie, it depends on the object) reference, which will lead to code highly coupled and difficult to test.

② coupling has two sides.

On the one hand, tightly coupled code is difficult to test, difficult to reuse, difficult to understand, and typically exhibit a characteristic bug "hit hamster" type (fix a bug, there will be one or more new bug). On the other hand, the coupling of a certain program is a must, there is no coupling of the code is valid and can not do. In order to complete meaningful function, different classes must interact in an appropriate manner. All in all, the coupling is necessary, but should be carefully managed.

By DI, dependencies by the system object is responsible for coordinating the team's third-party components in common target setting time. Objects do not need to create your own or manage their dependencies, the following chart, dependencies are automatically injected into the objects to their needs.

③ injection dependent manner

spring supports three ways dependency injection

  • Properties injection

I.e., injection injection property or attribute value dependent bean setter method object by

Injection using an element attribute, using the name attribute specifies the bean property name, value or attribute property value subnode

Property is actually injected into the development of the most common injection method

public void setName(String name)
{
    System.out.println("setName:"+name);
    this.name=name;
}
<bean id="helloWorld" class="spring.bean.HelloWorld">
    <property name="name" value="Spring"></property>
</bean>
  • Constructor injection

Object bean property values ​​by injecting constructor or a dependent (reference), to ensure that the examples may be used in the bean after instantiation

Constructor injection declared in the elements where the attribute, no attribute name

Creating a People Object

package com.container;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class People {
        private String name;
        private String sex;
        private int age;

        public People(String name, int age) {
            this.name = name;
            this.age = age;
        }

        public People(String name, String sex) {
            this.name = name;
            this.sex = sex;
        }

        @Override
        public String toString() {
            return "people{" +
                    "name='" + name + '\'' +
                    ", sex='" + sex + '\'' +
                    ", age=" + age +
                    '}';
        }

        public static void main(String[] args) {
            ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-config.xml");
            People people1 = (com.container.People) applicationContext.getBean("people1");
            System.out.println(people1);
            People people2 = (com.container.People) applicationContext.getBean("people2");
            System.out.println(people2);
        }
    }
<?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="people1" class="com.container.People">
        <constructor-arg value="江疏影" type="java.lang.String"></constructor-arg>
        <constructor-arg value="20" type="int"></constructor-arg>
    </bean>
    <bean id="people2" class="com.container.People">
        <constructor-arg value="江疏影" type="java.lang.String"></constructor-arg>
        <constructor-arg value="man" type="java.lang.String"></constructor-arg>
    </bean>
</beans>

  • Factory Method Injection (know on the line, not recommended)

3, the application of section

DI enables software components that work together to maintain loose coupling, and Aspect Oriented Programming (aspect-oriented programming, AOP) allows you to separate the form of reusable components throughout the entire application functionality.

Aspect Oriented Programming is often defined as promote software system to achieve separation of concerns of a technology. The system consists of many different components, each component of each responsible for a specific function. In addition to implementing its core functions, these components often bear the additional responsibilities. Such as logging, transaction management and security of such systems will be integrated into the core business service components, these systems are often referred to as service crosscutting concerns, because they span multiple components of the system.

If all of these concerns go across multiple components, your code will bring complexity twofold.

  • Code that implements the system function will be repeated concerns appear in multiple components, which means that if you want to change the logic of these concerns, we must modify each module associated implementation. Even if you focus abstract object as a separate module, other modules simply call its methods, but the method is still a call repeated in each module.
  • Those components because the code has nothing to do with their core business and become confused. An added address to the address book entry method should only focus on how to add an address, and should not be concerned that it is not safe or whether it needs to support the transaction.

The following diagram illustrates this complexity, the left and system services business code combination too closely. Each object not only to know that it needs diary, security control and participate in transactions, but also personally perform these services.

AOP allows these modular services, and declaratively apply them to the influence of the components they need to go. The result is that these components would have greater cohesion and will be more concerned about their own business, you do not need to fully understand the complexity of system design services brings. In short, AOP to ensure the simplicity of a POJO.

如下图所示,我们可以把切面想象为覆盖在很多组件之上的一个外壳。应用是由那些实现各自业务功能的模块组成,借助AOP,可以使用各种功能层去包裹核心业务层,这些层以声明的方式灵活的应用在系统中,你的核心应用甚至不知道他们的存在,这是一个非常强大的理念,可以将安全、事务和日志关注点与核心业务逻辑相分离。

通过少量的XML配置,声明一个Spring切面。

4、使用模块消除样板式代码

二、Spring容器

Spring容器,顾名思义是用来容纳东西的,装的就是Bean。Spring容器负责创建、配置、管理Bean。spring容器有两个核心接口:BeanFactory和ApplicationContext接口,后者是前者的子接口。在基于spring的Java EE程序中,所有的组件都被当成Bean来处理,包括数据源对象、hibernate的sessionFactory、事务管理等,程序中的所有Java类都可以被当成spring容器中的bean。

在基于Spring的应用中,你的应用对象生存于Spring容器(container)中。如下图所示,Spring容器负责创建对象,装配它们,配置它们并管理它们的整个生命周期,从生存到死亡(在这里可能就是new到finalize())。

1、spring容器

spring容器的核心接口是BeanFactory,它有一个子接口就是ApplicationContext。ApplicationContext也被称为spring上下文。

调用者只需要使用getBean()方法即可获得指定bean的引用。对于大部分的Java程序而言,使用ApplicationContext作为spring容易更为方便。其常用的实现类有FileSystemXmlApplicationContext、ClassPathXmlApplicationContext和AnnotationConfigXmlApplicationContext。如果Java web中使用spring容器,则通常有XmlWebApplicationContext、AnnotationConfigWebApplicationContext两个容器。

创建spring容器的实例时,必须提供spring容器管理的bean的配置文件,也就是我们常说的spring.xml配置文件。因此在创建beanFactory时配置文件作为参数传入。xml配置文件一般以resource对象传入。resource是spring提供的资源访问接口,通过该接口spring更简单、透明的访问磁盘,网络系统和类路径上的相关资源。

对于独立的Java EE应用程序,可以通过如下方法来实例化BeanFactory。

//在当前项目类路径下搜索配置文件
ApplicationContext appContext = new ClassPathXmlApplicationContext("beans_7_3_3.xml");
//在文件系统搜索配置文件
appContext = new FileSystemXmlApplicationContext("D:\\spring-tool-workspace\\myspring\\src\\beans_7_3_3.xml");
//获取chinese的Bean,并且返回的类型为Chinese
Person chinese = appContext.getBean("chinese", Chinese.class);
chinese.useAxe();

2、使用ApplicationContext

大部分时间,都不会使用beanFactory实例作为spring容器,而是使用ApplicationContext作为spring容器,因此spring容器也被称为spring上下文。ApplicationContext增强了beanFactory的功能,提供了很多有用、方便开发的功能。

在web中可以利用如contextLoader的支持类,在web应用启动的时候自动创建ApplicationContext。

除了提供beanFactory所支持的全部功能外,application还额外的提供如下功能:

① ApplicationContext会默认初始化所有的singleton bean(单例bean),也可以通过配置取消。

② ApplicationContext继承了messageSource接口,因此提供国际化支持。

③ 资源访问,比如URL和文件。

④ 事件机制。

⑤ 同时加载多个配置文件。

⑥ 以声明式方式启动并创建spring容器。

ApplicationContext包括beanFactory的所有功能,并提供了一些额外的功能,优先使用ApplicationContext。对于在内存消耗的才使用beanFactory。

当系统创建ApplicationContext容器时,会默认初始化singleton bean,包括调用构造器创建该bean的实例,通过元素驱动spring调用setting方法注入所依赖的对象。这就意味着,系统前期创建ApplicationContext会有很大的开销,但是一旦初始化完成后面获取bean实例就会拥有较好的性能。为了阻止在使用ApplicationContext作为spring容器初始化singleton bean可以在元素添加lazy-init="true"属性。

3、ApplicationContext的国际化支持

ApplicationContext接口继承了MessageSource接口,因此具备国际化功能。

//MessageSource接口提供的国际化的两个方法
String getMessage(String code, Object [] args, Locale loc){
}
String getMessage(String code, Object[]args, String default, Locale loc){
}

spring国际化的支持,其实是建立在Java国际化的基础上的。其核心思路将程序中需要国际化的消息写入资源文件,而代码中仅仅使用国际化信息响应的key。

4、ApplicationContext的事件机制

ApplicationContext的事件机制是观察者设计模式的实现。通过ApplicationEvent和ApplicationListener接口实现,前者是被观察者,后者是观察者。

spring事件框架有两个核心的接口:

ApplicationEvent(事件):必须由ApplicationContext来发布。

ApplicationListener(监听器):实现了此接口就可以担任容器中的监听器bean。

实际上,spring的事件机制是由事件(实现ApplicationEvent接口的类)、事件源(也就是spring容器,并且有Java代码显示的触发)、监听器(ApplicationListener接口实现类)。这就像我们在页面点击一个button。button是事件源,单机的这个动作就是事件,处理函数就是监听器。

以下代码演示spring事件机制:

import org.springframework.context.ApplicationEvent;

public class EmailEvent extends ApplicationEvent{
    private String address;
    private String text;
    public EmailEvent(Object source) {
        super(source);
    }

    public EmailEvent(Object source, String address, String text) {
        super(source);
        this.address = address;
        this.text = text;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }
}
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class EmailNotifier implements ApplicationListener {
    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        //处理email事件
        if(event instanceof EmailEvent){
            EmailEvent email = (EmailEvent) event;
            System.out.println(email.getAddress()+"  "+email.getText());
        }else {
            //输出spring容器的内置事件
            System.out.println("其它事件:"+event);
        }
    }

    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans_7_4_4.xml");
        EmailEvent emailEvent = applicationContext.getBean("emailEvent",EmailEvent.class);
        applicationContext.publishEvent(emailEvent);
    }
}
<?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 class="EmailNotifier"></bean>
    <bean id="emailEvent" class="EmailEvent">
        <constructor-arg value="test"></constructor-arg>
        <constructor-arg value="[email protected]"></constructor-arg>
        <constructor-arg value="this is a test"></constructor-arg>
    </bean>
</beans>

从上面的代码可以看出,事件监听器不仅监听到了我们程序显示触发的事件,还监听了spring容器内置的事件。如果实际开发需要,我们可以在spring容器初始化或销毁时回调自定义方法,就可以通过上面的事件监听机制来完成。

spring提供了如下几个内置对象:

ContextRefreshedEvent、ContextStartedEvent、ContextClosedEvent、ContextStoppedEvent、RequestHandledEvent。

5、让bean获取spring容器

上面都是通过ApplicationContext创建spring容器,再调用spring容器的getBean()方法获取bean。这种情况下,程序总是持有spring容器的引用。但是在web应用中,我们可以用声明式的方法来创建spring容器:在web.xml文件中配置一个监听,让这个监听类帮我们来创建spring容器,前端MVC框架直接调用bean,使用依赖注入功能,无需访问spring容器本身。

在某些特殊情况下,bean需要实现某个功能(比如:bean需要输出国际化信息,或向spring容器发布事件),这些功能都需要借助spring容器来完成。就是说我们需要将spring容器作为一个bean来注入到其它bean中,只不过spring容器bean是一个容器级别的bean。

为了让bean获取它所在容器的引用,可以让bean实现beanFactoryAware接口。该接口只有一个方法setBeanFactory(BeanFactory beanFactory)方法,方法的beanFactory参数指向spring容器,会由spring容器注入。我们bean中定义一个setter方法后,通常都是由在配置文件中配置元素来驱动spring容器来注入依赖bean的,但是这里我们并没有这样做,这是因为一个bean如果实现了beanFactory接口,spring在创建该bean时,会自动注入spring容器本身。与beanFactoryAware接口类似的还有BeanNameAware、ResourceLoaderAware接口,这些接口都会提供类似的setter方法,这些方法会由spring容器来注入。

6、bean的生命周期

正确理解Spring bean的生命周期非常重要,因为你或许要利用Spring提供的扩展点来自定义bean的创建过程。下图展示了bean装载到Spring应用上下文中的一个典型的生命周期过程。

正如你所见,在bean准备就绪前,bean工厂执行了若干启动步骤。

现在你已经了解了如何创建和加载一个Spring容器。但是一个空的容器并没有太大的价值,在你把东西放进去之前,它什么也没有。为了从Spring的DI中受益,我们必须将应用对象装配进Spring容器中。我们将在第二章对bean装配进行更详细的探讨。

我们现在首先浏览一下Spring的体系结果,了解一下Spring框架的基本组成部分和最新版本的Spring所发布的新特性。

三、俯瞰Spring风景线

1、Spring模块

Spring发布版本中lib目录下有多个jar文件。

Spring核心容器

Spring的AOP模块

数据访问与集成

 web与远程调用

测试

Spring  Boot(第二十一章介绍)

四、Spring的新功能

五、小结

Spring致力于简化企业级Java开发,促进代码的松散耦合,成功的关键在于依赖注入和AOP。

 

发布了110 篇原创文章 · 获赞 8 · 访问量 6902

Guess you like

Origin blog.csdn.net/guorui_java/article/details/104254041