Spring体系结构及IoC介绍

Spring的体系结构

如下图所示,整个spring框架按其所属功能可以划分为五个主要模块,这五个模块几乎为企业应用提供了所需的一切,从持久层、业务层到表现层都拥有相应的支持,这也是为什么称Spring是一站式框架的原因。
在这里插入图片描述
Test模块

Spring可以用非容器依赖的方式进行几乎所有的测试工作,支持JUnit和TestNG等测试框架。

核心模块(Core Container)

  • Beans: 负责Bean工厂中Bean的装配,所谓Bean工厂即创建对象的工厂,Bean的装配也就是对象的创建工作。
  • Core: 负责IoC(控制反转)最基本的实现
  • Context: Spring的IoC容器,因大量调用了Spring Core中的函数,整合了Spring的大部分功能。Beans创建好对象后,由Context负责建立Bean和Bean之间的关系并维护。所以也可以把Context看成是Bean关系的集合。
  • SpEL: 即 Spring Expression Language,Spring表达式语言。可以更加方便的通过表达式与Spring IoC容器进行交互。

Spring的核心模块实现了IoC的功能,它将类和类之间的依赖从代码中脱离出来,用配置的方式进行依赖关系描述。由IoC容器负责类的创建,管理,获取等。BeanFactory接口是Spring框架的核心接口,实现了容器很多核心功能。

Context模块构建于核心模块之上,扩展了BeanFactory的功能,包括国际化、资源加载、邮件服务、任务调度等多项功能。ApplicationContext是Context模块的核心接口。

AOP模块

Spring AOP模块提供了满足AOP Alliance规范的实现,还整合了AspectJ这种AOP语言级的框架。通过AOP能降低耦合。

Instrumentation(设备):相当于一个检测器,提供对JVM以及对Tomcat的检测。

Messaging(消息):Spring提供的对消息处理的功能

Data Access/Integration(数据访问/集成)模块:

该模块包含了JDBC、ORM、OXM、JMS和事务管理

  • JDBC: 对JDBC进行简单的封装,提供一个JDBC样例模板,使用这些模板能够消除传统冗长的JDBC编码,还能享受到Spring管理事务的好处。
  • ORM: 提供与流行的“对象–关系”映射框架的无缝集成,包括Hibernate、JPA、MyBatis等。可以使用Spring事务管理,无需额外控制事务。
  • OXM: 提供一个对Object/XML映射的实现,将Java对象映射成XML数据,或将XML数据映射成Java对象,Object/XML映射实现包括JAXB、Castor、XMLBeans和XStream。
  • JMS: Java Messaging Service,提供一套“消息生产者,消息消费者”模板,简化JMS的使用,JMS用于两个程序之间,或分布式系统中发送消息,进行异步通信。
  • 事务: 该模块用于Spring管理事务,无需在代码中进行事务控制,而且支持编程和声明式的事务管理。

Web模块

该模块建立在ApplicationContext模块之上,提供了Web应用的功能,如文件上传、FreeMarker等。

  • WebSocket:提供Socket通信,web端的推送功能
  • Servlet:Spring MVC框架的实现
  • Web:包含web应用开发用到Spring框架时所需的核心类,包括自动载入WebApplicationContext特性的类,Struts集成类,文件上传的支持类,Filter类和大量辅助工具类。
  • Portlet:实现web模块功能的聚合

Spring的核心

IoC(控制反转)和 AOP(面向切面编程)

IoC(Inversion of Control)

IOC是指在程序开发过程中,对象实例的创建不再由调用者管理,而是由Spring容器创建,Spring容器会负责控制程序之间的关系,而不是由代码直接控制,因此,控制权由程序代码转移到了Spring容器,控制权发生了反转,即 控制反转

IoC不是一种技术,只是一种思想,它能指导我们如何设计出松耦合、更优良的程序。传统应用程序都是由我们在类内部主动创建依赖对象,从而导致类与类之间高耦合,难于测试;有了IoC容器后,把创建和查找依赖对象的控制权交给了容器,由容器进行注入组合对象,所以对象与对象之间是松散耦合,这样也方便测试,利于功能复用,更重要的是使得程序的整个体系结构变得非常灵活。

Spring的Ioc容器详解

Spring IOC提供了两种IOC容器,分别是 BeanFactoryApplicationContext

1、BeanFactory

BeanFactory是一个类工厂,和传统的类工厂不同,传统的类工厂仅负责构造一个类或几个类的实例;而BeanFactory可以创建并管理各种类的对象,Spring称这些被创建和管理的Java对象为Bean。

BeanFactory是一个接口,Spring为BeanFactory提供了多种实现,最常用的就是XmlBeanFactory。其中,BeanFactory接口最主要的方法就是getBean(String beanName),该方法从容器中返回指定名称的Bean。此外,BeanFactory接口的功能可以通过实现它的子接口进行扩展(比如ApplicationContext)。看下面的示例:

//我们使用Spring配置文件为User类提供配置信息,然后通过BeanFactory装载配置文件,
//启动Spring IoC容器。 
<?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="user" class="com.cad.domain.User"></bean>   
</beans>
// 我们通过XmlBeanFactory实现类启动Spring IoC容器 
public class Test {

    @org.junit.Test
    public void test(){ 
        //获取配置文件
        ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); 
        Resource rs = resolver.getResource("classpath:bean.xml");

        //加载配置文件并启动IoC容器
        BeanFactory bf = new XmlBeanFactory(rs);

        //从容器中获取Bean对象
        User user=(User) bf.getBean("user");

        user.speak();
    }
}

BeanFactory和ApplicationContext的区别:
如果Bean的某一个属性没有注入,则使用BeanFactory加载后,在第一次调用getBean方法时会抛出异常,而ApplicationContext会在初始化时检查,有利于检查所依赖的属性是否注入。

XmlBeanFactory装载Spring配置文件并启动IoC容器,通过BeanFactory启动IoC容器时,并不会初始化配置文件中定义的Bean,初始化创建动作在第一个调用时。在初始化BeanFactory,必须提供一种日志框架,我们使用Log4J。

2、ApplicationContext

ApplicationContext是BeanFactory的子接口,也被称为应用上下文,不仅提供了BeanFactory的所有功能,还添加了对国际化、资源访问、事件传播等方面的支持。

ApplicationContext提供了两个实现类:

ClassPathXmlApplicationContext: 该类从类路径ClassPath中寻找制定的xml文件

ApplicationContext applicationContext =
			 new ClassPathXmlApplicationContext(String configLocation);
	
//	configLocation参数用来指定Spring配置文件的名称和位置

FileSystemXmlApplicationContext: 该类从指定的文件系统路径中寻找指定的xml文件

ApplicationContext applicationContext = 
			new FileSystemXmlApplicationContext(String configLocation);
	

ApplicationContext的初始化和BeanFactory初始化有一个重大的区别,BeanFactory初始化容器时并未初始化Bean,只有第一次访问Bean时才创建;而ApplicationContext则在初始化时就实例化所有的单实例的Bean。因此,ApplicationContext的初始化时间会稍长一点。

3、WebApplicationContext

WebApplicationContext是专门为Web应用准备的,它允许以相对于Web根目录的路径中加载配置文件完成初始化工作。从WebApplicationContext中可以获取ServletContext的引用,整个WebApplicationContext对象作为属性放置到ServletContext中,以便Web应用环境中可以访问Spring应用上下文。ConfigurableWebApplicationContext扩展了WebApplicationContext,允许通过配置方式实例化WebApplicationContext,并定义了两个重要方法。

setServletContext(ServletContext servletcontext):为Spring设置ServletContext
setConfigLocation(String[] configLocations):设置Spring配置文件地址。

WebApplicationContext初始化的时机和方式是:利用Spring提供的ContextLoaderListener监听器去监听ServletContext对象的创建,当ServletContext对象创建时,创建并初始化WebApplicationContext对象。因此,我们只需要在web.xml配置监听器即可。

<!-- 利用Spring提供的ContextLoaderListener监听器去监听ServletContext对象的创建,并初始化WebApplicationContext对象 -->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <!-- Context Configuration locations for Spring XML files(默认查找/WEB-INF/applicationContext.xml) -->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:applicationContext.xml</param-value>
    </context-param>

4、BeanFactory、ApplicationContext和WebApplicationContext的联系与区别

Spring通过一个配置文件描述Bean与Bean之间的依赖关系,通过Java语言的反射技术能实例化Bean并建立Bean之间的依赖关系。Spring的IoC容器在完成这些底层工作的基础上,还提供了bean实例缓存、生命周期管理、事件发布,资源装载等高级服务。

BeanFactory是Spring最核心的接口,提供了高级IoC的配置机制。ApplicationContext建立在BeanFactory的基础上,是BeanFactory的子接口,提供了更多面向应用的功能。我们一般称BeanFactory为IoC容器,ApplicationContext为应用上下文,也称为Spring容器。WebApplicationContext是专门为Web应用准备的,它允许以相对于Web根目录的路径中加载配置文件完成初始化工作,是ApplicationContext接口的子接口。

BeanFactory是Spring框架的基础,面向Spring本身;ApplicationContext面向使用Spring框架的开发者,几乎所有的应用我们都直接使用ApplicationContext而非底层的BeanFactory;WebApplicationContext是专门用于Web应用。

5、父子容器

通过HierarchicalBeanFactory接口,Spring的IoC容器可以建立父子层级关联的体系:子容器可以访问父容器的Bean,父容器不能访问子容器的Bean。

Spring使用父子容器实现了很多功能,比如在Spring MVC中,控制器Bean位于子容器中,业务层和持久层Bean位于父容器中。但即使这样,控制器Bean也可以引用持久层和业务层的Bean,而业务层和持久层就看不到控制器Bean。


在Java项目中,通常使用ClassPathXmlApplicationContext类实例化ApplicationContext容器,而在web项目中,ApplicationContext容器的实例化工作交给web服务器完成,web服务器实例化ApplicationContext容器通常使用基于ContextLoaderListener实现的方式,只需要编辑web.xml文件即可

<!--指定Spring配置文件的位置,有多个配置文件时,以逗号分隔-->
<context-param>
    <param-name>contextConfigLocation</param-name>
    <!--spring将加载spring目录下的applicationContext.xml文件-->
    <param-value>
        classpath:spring/applicationContext.xml
    </param-value>
</context-param>
<!--指定以ContextLoaderListener方式启动Spring容器-->
<listener>
    <listener-class>
        org.springframework.web.context.ContextLoaderListener
    </listener-class>
</listener>


DI (Dependency Injection) —— 依赖注入

在系统运行中,动态的向某个对象提供它所需要的其他对象。这一点是通过DI(依赖注入)来实现的。

依赖注入和控制反转含义相同,他们是从两个角度描述同一个概念。

当某个对象实例需要另外一个对象实例时,传统的方法是由调用者创建被调用者的实例,比如使用new,而使用Spring框架后,被调用者的实例不再由调用者创建,而是交给了Spring容器,这称为控制反转。

Spring容器在创建被调用实例时,会自动将调用者需要的对象实例注入调用者,这样,通过 Spring容器获得被调用者实例,就叫做 依赖注入。

比如对象A需要操作数据库,以前我们总是要在A中自己编写代码来获得一个Connection对象,有了 spring我们就只需要告诉spring,A中需要一个Connection,至于这个Connection怎么构造,何时构造,A不需要知道。在系统运行时,spring会在适当的时候制造一个Connection,然后像打针一样,注射到A当中,这样就完成了对各个对象之间关系的控制。A需要依赖 Connection才能正常运行,而这个Connection是由spring注入到A中的,依赖注入的名字就这么来的。

那么DI是如何实现的呢? Java 1.3之后一个重要特征是反射(reflection),它允许程序在运行的时候动态的生成对象、执行对象的方法、改变对象的属性,spring就是通过反射来实现注入的。

依赖注入的实现方式

  • 属性setter注入

    //创建类A
    public class A {
        public A() {
            System.out.println("正在初始化类A,调用无参构造器A。。。");
        }
        public void print() {
            System.out.println("调用了类A的print方法。。。");
        }
    }
    //创建类B
    public class B {
        private A a;
        public void setA(A a) {
            this.a = a;
        }
        public void print() {
            a.print();
        }
    }
    //配置Beans.xml
        <bean id="a" class="com.ssm.ioc.A"/>
        <bean id="b" class="com.ssm.ioc.B">
            <property name="a" ref="a"/>
        </bean>
    //测试
        @Test
        public void test() {
            B b = (B) context.getBean("b");
            b.print();
        }
    
    
  • 构造构造器注入

    //配置Beans.xml
        <bean id="a" class="com.ssm.ioc.A"/>
        <bean id="b" class="com.ssm.ioc.B">
            <constructor-arg name="a" ref="a"/>
        </bean>
    //测试
        @Test
        public void test() {
            B b = (B) context.getBean("b");
            b.print();
        }
    
    
  • 静态工厂方式实例化

    //创建工厂类
    public class MyBeanFactory {
        public static A createCoffer() {
            return new A();
        }
    }
    //配置Beans.xml
    <bean id="a" class="com.ssm.ioc.MyBeanFactory" factory-method="createA"/>
    //测试
        @Test
        public void test() {
            A a = (A) context.getBean("a");
        }
    
    
  • 实例工厂实例化

    //创建工厂类
    public class MyBeanFactory {
        public MyBeanFactory() {
            System.out.println("A工厂实例化中。。。");
        }
        public A createBean() {
            return new A();
        }
    }
    //配置Beans.xml
        <bean id="myBeanFactory" class="com.ssm.ioc.MyBeanFactory"/>
        <bean id="a" factory-bean="myBeanFactory" factory-method="createBean"/>
    //测试
        @Test
        public void test() {
            A a = (A) context.getBean("a");
        }
    
    

Spring的IoC例子

(1) 创建工程,导入jar包

这里我们只是做IoC的操作,所以只需要导入核心模块里的jar包,beans、core、context、expression等。因为spring中并没有日志相关的jar包,所以我们还需要导入log4j和commons-logging。

(2) 创建一个类

public class User {
    public void add(){
        System.out.println("add.....");
    }
}

(3) 创建一个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"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
                        http://www.springframework.org/schema/beans/spring-beans.xsd"> 

    //配置要创建的类  
    <bean id="user" class="com.cad.domain.User"/>        
</beans>

(4) 进行测试

//这只是用来测试的代码,后期不会这么写
public class Test {

    @org.junit.Test
    public void test(){
        //加载配置文件
        ApplicationContext context= new ClassPathXmlApplicationContext("bean.xml");
        //获取对象
        User user=(User) context.getBean("user");
        System.out.println(user);
        //调用方法
        user.add();
    }
}

在容器启动时,Spring会根据配置文件的描述信息,自动实例化Bean并完成依赖关系的装配,从容器中即可获得Bean实例,就可以直接使用。

Spring的DI例子

我们的service层总是用到dao层,以前我们总是在Service层new出dao对象,现在我们使用依赖注入的方式向Service层注入dao层。

// UserDao
public class UserDao {
    public void add(){
        System.out.println("dao.....");
    }
}

// UserService
public class UserService {
    UserDao userdao;
    public void setUserdao(UserDao userdao){
        this.userdao=userdao;
    }

    public void add(){
        System.out.println("service.......");
        userdao.add();
    }
}

-------------------------------分割线--------------------------

// 配置文件
<bean id="userdao" class="com.cad.domain.UserDao"></bean> 
//这样在实例化service的时候,同时装配了dao对象,实现了依赖注入
<bean id="userservice" class="com.cad.domain.UserService">
    //ref为dao的id值
    <property name="userdao" ref="userdao"></property>
</bean>

AOP(Asepct-Orentid-Programming)

AOP概述

AOP和OOP类似,也是一种编程模式,Spring AOP是基于AOP编程模式的一个框架,它的使用有效减少了系统间的重复代码,达到了模块间解耦的作用。

AOP的全程是"Aspect Oriented Programming",即面向切面编程,它将业务逻辑的各部分进行隔离,使开发人员在编写业务逻辑时可以专心核心业务,从而提高开发基础。

AOP采取横向抽取机制,取代了传统的纵向继承体系,其应用主要体现在事务处理、日志管理、权限控制、异常处理等方面。

目前最流行的AOP有Spring AOP和AspectJ

Spring AOP使用纯Java实现,不需要专门的编译过程和类加载器,在运行期间通过代理方式向目标类植入增强的代码。

AspectJ是一个基于Java语言的AOP框架,从Spring2.0开始,Spring AOP引入了对AspectJ的支持。

深入了解Spring AOP 请看 https://blog.csdn.net/qq_41142785/article/details/116934607.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值