spring 的核心就是IOC(最重要)+AOP

​ Spring没有太多的新的东西,它只是抽象了大量的JavaEE应用中的常用代码,将它们抽象成一个框架,通过使用Spring可以大幅度地提高开发效率,并可以保证整个应用具有良好的设计。

​ Spring框架号称JavaEE应用的一站式解决方案,Spring本身提供了一个设计优良的MVC框架:SpringMVC.使用Spring框架则可以直接使用该MVC框架。但Spring却没有提供完整的持久层框架这可以理解成一种“空”,但这种“空”反而是Spring框架的魅力所在。

​ Spring能与大部分持久层框架无缝整合:Hibernate、JPA、MyBatis、甚至直接使用JDBC,随便我们喜欢,无论哪种持久层框架,Spring都会为我们提供无缝的整合以及极好的简化。从这个意义上看,Spring更像一种中间层容器,Spring向上可以与MVC框架无缝整合,向下可以与各种持久层框架无缝整合,具有强大的生命力。

​ 由于Spring框架的特殊地位,所以轻量级JavaEE应用通常都会使用Spring。实际上,轻量级JavaEE这个概念也是由Spring框架衍生出来的,Spring框架暂时都没有较好的替代框架

spring 简介

Spring为企业应用的开发提供了一个轻量级的解决方案。该解决方案包括:基于依赖注入的核心机制、基于
卫AOP(Aspect Oriented Programming,面向健面的程序设计)的声明式事务管理、与各种持久层技术的整合,以及优秀的Web MVC 框架等。Spring致力于JavaEE应用各层的解决方案,而不是仅仅专注于某一层的方案。可以说:Spring是企业应用开发的“一站式“选择,Spring贯穿表现层、业务层、持久层。然而,Spring并不想取代那些已有的框架,而是以高度的开发性与它们无缝整合。

图片

​ SSH(Struts2,Spring,Hibernate)
​ SSM(SpringMVC,Spring,Mybatis)

maven配置

//最基础的
<dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>5.0.8.RELEASE</version>
    </dependency>

    <!--在基础IOC功能上提供扩展服务,还提供许多企业级服务的支持,有邮件服务、 任务调度、远程访问、缓存以及多种视图层框架的支持-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.0.8.RELEASE</version>
    </dependency>


    <!-- Spring IOC的基础实现,包含访问配置文件、创建和管理bean等 -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-beans</artifactId>
        <version>5.0.8.RELEASE</version>
    </dependency>
</dependencies>

applicationContext.xml 配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
    <!-- Bean定义和依赖注入 -->

</beans>

使用

在applicationContext.xml中配置bean

通过set方法装配

<bean id="user" class="com.origin.d630.User">
    <property name="name" value="hh"></property>
    <property name="age" value="12"></property>
</bean>

通过构造方法装配

<bean id="user" class="com.origin.d630.User">
    <constructor-arg value="hh"></constructor-arg>
    <constructor-arg value="12"></constructor-arg>
</bean>

main方法中创建context加载applicationContext.xml配置文件

ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

通过getBean来获取实体类

User user = (User) context.getBean("user");

单例类 – 拓展

public class Person {
    private String name = "tom";

    private Person() {

    }
    static private Person person;
    static  Person getPerson() {
        if (person == null) { //加入双重校验锁
            synchronized (Person.class) {
                if (person == null) {
                    person =  new Person();
                }
            }
        }
        return person;
    }
}

​ 我们使用spring来配置bean和使用单例类的效果是一样的,在spring中,加载xml配置文件时会自动帮我们加载配置的bean对象,相当于new了一次,这些对象被放在了spring容器中(spring的上下文),当我们使用一个对象时,就从这个容器中取走。

IOC/依赖注入

当某个Java对象需要调用另外一个Java对象的方法时,在传统模式下通常有如下两种做法。
原始做法:调用者主动创建被依赖对象,然后再调用被依赖对象的方法。
简单工厂模式:调用者先找到被依赖对象的工厂,然后主动通过工厂去获取被依赖的对象,最后在调用依赖
对象的方法。
对于第一种方式,由于调用者需要通过形如“new构造器(”的代码创建对象,因此必然导致调用者与被依赖
对象实现类的硬编码耦合,非常不利于项目的升级的维护。
对于简单工厂的方式,大致需要把握三点:1、调用者面向被依赖对象的接口编程;2、将被依赖的对象的创
建交给工厂完成;3、调用者通过工厂来获取被依赖的组件。通过这3点改造,可以保证调用者只需要与被依赖
对象的接口耦合,这就避免了类层次的硬编码耦合。这种方式唯一的缺点是,调用组件需要主动通过工厂去获
取依赖对象,就会带来调用组件与被依赖对象工厂的耦合。
使用Spring框架之后,调用者无须主动获取被依赖对象,调用者只要被动接受Spring容器为调用者的成员变量
赋值即可。由此可见,使用Spring框架之后,调用者获取被依赖对象的方式由原来的主动获取,变成了被动接

从Spring容器的角度来看,Spring容器负责将被依赖对象赋值给调用者的成员变量——相当于为调用者注入它
依赖的实例对象

Spring容器 —-Spring (BeanFactory)

​ Spring 有两个核心接口:BeanFactory 和ApplicationContext,其中ApplicationContext是BeanFactory 的子接口。它们都可以代表 Spring 容器,Spring 容器是生成 Bean 实例的工厂,并管理容器中 Bean。在基于 Spring的Java E应用中,所有的组件都被当成 Bean处理,包括数据源、Hibernate的 SessionFactory、事务管理器等。
​ 应用中的所有组件都处于Spring的管理下,都被Spring以Bean的方式管理,Spring负责创建 Bean实例,并管理其生命周期。Spring里的Bean都是非常广义的概念,任何的Java对象、Java组件都被当成Bean处理,
对于 Spring 而言,一切 Java 对象都是 Bean。
​ Java程序面向接口编程,无须关注Bean实例的实现类,但Spring容器负责创建Bean实例。因此在Spring配置文件中必须指定Bean实例的实现类。
​ Spring容器最基本的接口就是BeanFactory。BeanFactory负责配置、创建、管理Bean,它有一个子接口:
ApplicationContext,因此也被称为Spring上下文。Spring容器还负责管理Bean与 Bean之间的依赖关系。 BeanFactory接口包含如下几个基本方法。
​ (1)boolean containsBean(String name):判断 Spring 容器中是否包含 id 为 name 的 Bean 实例。
​ (2) T getBean(ClassrequiredType):获取 Spring 容器中属于 required Type 类型的、唯一的 Bean 实例。
​ (3)Object getBean(String name):返回容器中 id 为 name 的 Bean 实例。
​ (4)T getBean(String name,Class requiredType):返回容器中 id 为 name,并且类型requiredType 的Bean。
​ (5)Class<?> getType(String name):返回容器中 id 为 name 的 Bean 的实例的类型。
​ 调用者只需要使用getBean()方法即可获得指定 Bean的引l用,无须关心Bean的实例化过程。Bean 实例的创建、初始化以及依赖关系的注入都由Spring容器完成。
​ BeanFactory 常用的实现类是DefaultListableBeanFactory。
​ ApplicationContext是Beanfactory的子接口,对于大部分 Java EE应用而言,使用它作为 Spring 容器更方便。其常用实现类是FileSystemXmlApplicationContext、ClassPathXmlApplicationContext和AnnotationConfigApplicationContext。如果在Web应用中使用 Spring 容器.则通常有XMLWebApplicationContext、AnnocationConfigWebApplicationContext 两个实现类。

ApplicationContext

​ 大部分时候,都不会使用BeanFactory实例作为Spring容器,而是使用ApplicationContext实例作为容器,
因此也把 Spring容器称为 Spring上下文。ApplicationContext是BeanFactory接口的子接口,它增强了
BeanFactory 的功能。
​ ApplicationContext允许以声明式方式操作容器,无须手动创建它。可利用如ContextLoader的支持类,在
Web应用启动时自动创建ApplicationContext。当然也可采用编程方式创建ApplicationContext。
​ ApplicationContext除了提供BeanFactory所支持的全部功能外,还有如下额外方法:

​ (1)ApplicationContext默认会预初始化所有的singletionBean.也可通过配置取消预初始化。
​ (2)ApplicationContext继承MessageSource接口,因此提供国际化支持。
​ (3)资源访问,比如访问URL和文件。
​ (4)事件机制。
​ (5)同时加载多个配置文件。
​ (6)以声明式方式启动并创建Spring容器。
​ ApplicationContext包括BeanFactory 的全部功能,因此建议优先使用ApplicationContext。除非对于某些内存非常关键的应用才考虑BeanFactory。当系统创建ApplicationContext容器时,默认会预初始化所有的singletion Bean。也就是说,当ApplicationContext容器初始化完成后,容器会自动初始化所有的singletionBean,包括调用构造器创建该Bean的实例。并根据property元素执行setter方法。这意味着:系统前期创建ApplicationContext时将有较大的系统开销,但一旦ApplicationContext初始化完成,程序后面获取singletionBean实例时将拥有较好的性能。

scope="prototype" 取消单例

事件机制

​ ApplicationContext的事件机制是观察者设计模式的实现,通过ApplicationEvent类和ApplicationListener 接口,可以实现ApplicationContext 的事件处理。如果容器中有一个ApplicationListener Bean,每当ApplicationContext发布ApplicationEvent时,ApplicationListenerBean将自动被触发。Spring的事件框架有如下两个重要成员。

​ ApplicationEvent:容器事件,必须有ApplicationContext发布。
​ ApplicationListener监听器,可由容器中的任何监听器 Bean担任。

​ 实际上,Spring的事件机制与所有的事件机制都基本相似,它们都需要由事件源、事件和事件监听器组成。
只是此处的事件源是ApplicationContext,且事件必须由Javà程序显示触发。下图为Spring容器的事件机制示
意图。

图片

​ (发布者发布applicationEvent事件到applicationContext,applicationListener监听 applicationContext)

使用

@Getter
@Setter
@ToString
public class MyEvent extends ApplicationEvent {
    private String content;
    private String target;

    public MyEvent(Object source, String content, String target) {
        super(source);
        this.content = content;
        this.target = target;
    }
}
public class MsgListener implements ApplicationListener {
    @Override
    public void onApplicationEvent(ApplicationEvent applicationEvent) {
        if (applicationEvent instanceof MyEvent) {
            MyEvent myEvent = (MyEvent) applicationEvent;
            System.out.println(myEvent);
        } else {
            System.out.println("其他事件..."+applicationEvent);
        }
    }
}
<bean class="com.origin.d630.MsgListener"></bean>
MyEvent myEvent =  new MyEvent("user1","hhh","user2");
context.publishEvent(myEvent);

系统自带的事件

​ 监听器不仅监听到程序所触发的事件,也监听到容器内置的事件。实际上,如果开发者需要在Spring容器初始化、销毁时回调方法,就可以通过上面的事件监听器来实现。
​ Spring提供如下几个内置事件。
​ ContextRefreshedEvent:ApplicationContext容器初始化或刷新触发该事件。此处的初始化是指,所有的Bean被成功加载,后处理的Bean被检测并激活,所有的 singletonBean被预实例化,ApplicationContext容器已就绪可用。

​ ContextStartedEvent:当使用ConfigurableApplicationContext 接口的 start 方法启动ApplicationContext容器时触发该事件。

​ ContextClosedEvent:当使用 ConfigurableApplicationContext 接口的 close方法时关闭ApplicationContext容器时触发该事件。

​ ContextStoppedEvent:当使用ConfigurableApplicationContext接口的 stop 方法使ApplicationContext 停止时触发该事件。
​ RequestHandlerEvent:Web相关的事件,只能应用于使用DispatcherServlet 的 Web应用中。在使用 Spring作为前端的MVC控制器时,当Spring处理用户请求结束后,系统会自动触发该事件。从 Spring4.0.3 开始, Spring 还新增了SessionConnectedEvent、SessionConnectEvent、SessionDisconnectEvent 这三个事件,它们都用于为Spring新增的WebSocket功能服务。

Bean 获取 Spring 容器

​ 为了让Bean获取它所在的 Spring容器,可以让该Bean实现BeanFactoryAware接口。BeanFactoryAware接口里只有一个方法。

​ setBeanFactory(BeanFactory factory):该方法有一个参数 factory,该参数指向创建它的BeanFactory。
​ 此方法比较特殊,该方法不需要程序员来处理,直接由Spring调用,Spring调用该方法时会将Spring容器作为参数传入该方法。与该接口类似的还有BeanNameAware、ResourceLoaderAware接口,这些接口里都会提供类似的setter方法,这些方法也由Spring负责调用。

​ 与BeanFactoryAware接口类似的有ApplicationContextAware接口,实现该接口的Bean需要实现setApplication

​ Context(ApplicationContext ctx):方法———此方法也不是由程序员负责调用,而是由 Spring来调用。当Spring容器调用该方法时,它会把自身作为参数传入该方法。

原理

class XContext{
    public X createX(){
        X x = new X();
        x.setxContext(this);
        return x;
    }
}
class X{
    private XContext xContext;

    public void setxContext(XContext xContext) {
        this.xContext = xContext;
    }
}

使用

public class User implements ApplicationContextAware {
    public String name;
    public int age;
    ApplicationContext applicationContext;

    public void f1(){
        Object aa = applicationContext.getBean("aa");
        System.out.println(aa);
    }

    public void setApplicationContext(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }

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