Spring 框架简介

来源:互联网 发布:网络的好处具体事例 编辑:程序博客网 时间:2024/06/16 22:28

Spring 框架简介

一、Spring的体系架构

                      

1.1、Spring的核心模块

         Spring框架中最基础,最重要的模块,实现了IoC功能,将类与类之间的依赖从代码中脱离出来,用配置的方式进行依赖关系的描述,有Ioc容器负责依赖类之间的创建、拼接、管理、获取等工作。BeanFactory接口是Spring框架的核心接口,它实现了容器许多核心的功能。

        Context模块构建于核心模块之上,扩展了BeanFactory的功能,添加了i18n国际化、Bean生命周期控制、框架事件体系、资源加载透明化等多项功能。此外,该模块还提供了许多企业级服务的支持。ApplicationContext是Context模块的核心接口。

        表达式语言模块是统一表达式语言的一个扩展,该表达式语言用于查询和管理运行期的对象,支持设置或获取对象属性,调用对象方法、操作数组、集合等。还提供了逻辑表达式运算、变量定义等功能。使用它可以方便地通过表达式串和Spring IoC容器进行交互。

core部分包含4个模块:

     1、spring-core:依赖注入IoC与DI的最基本实现

     2、spring-beans:Bean工厂与bean的装配

     3、spring-context:spring的context上下文即IoC容器

     4、spring-expression:spring表达式语言

它们的完整依赖关系

                 

1.2、AOP模块

        AOP是进行横切逻辑编程的思想,开拓了人们考虑问题的思路。在AOP模块里,Spring提供了满足AOPAlliance规范的实现,此外,还整合了AspectJ这种AOP语言级的框架。Java 5.0引入java.lang.instrument,允许在JVM启动时启用一个代理类,通过该代理类在运行期修改类的字节码,改变一个类的功能,实现AOP的功能。

aop部分包含4个模块:

     1、spring-aop:面向切面编程

     2、spring-aspects:集成AspectJ

     3、spring-instrument:提供一些类级的工具支持和ClassLoader级的实现,用于服务器

     4、spring-instrument-tomcat:针对tomcat的instrument实现

它们的依赖关系

                    

1.4、Web及远程调用

        该模块建立在ApplicationContext模块之上,提供了Web应用的各种工具类,若通过Listener或Servlet初始化Spring容器,将Spring容器注册到Web容器中。其次,该模块还提供了多项面向Web的功能。此外,Spring还可以整合Struts、WebWork、TapestryWeb等MVC框架。

web部分包含4个模块

      1、spring-web:基础web功能,如文件上传

      2、spring-webmvc:mvc实现

      3、spring-webmvc-portlet:基于portlet的mvc实现

      4、spring-struts:与struts的集成,不推荐,spring4不再提供

它们的依赖关系:

                      

二、Spring 核心

2.1、IoC容器

2.1.1、IoC概述

       Spring框架的核心功能是控制反转IoC,面向切片AOP和声明式事务都依赖于IoC实现的基础上。所谓IoC,就是通过容器来控制业务对象之间的依赖关系,而非传统实现中,由代码直接控制。这也就是“控制反转”概念所在;控制权由应用代码转到了外部容器,控制权的转移,就是反转。控制权转移带来的好处就是降低了业务对象之间的依赖程度。

       使用Spring IoC容器后,容器会自动对被管理对象进行初始化并完成对象之间依赖关系的维护。在被管理对象那个中无需调用Spring的API。

       依赖注入(Dependency Injection)和控制反转(Inversion ofControl)是同一个概念,都是为了处理对象之间的依赖关系。在传统的程序设计中,对象之间的依赖关系是体现在代码中的,即通过代码将被依赖独享设置到依赖者中,从而完成对象的组合;而通过DI/IoC容器,互相依赖的对象由容器负责创建和装配,而不是在代码中完成。

2.2、BeanFactory及其子类


1.BeanFactory类结构体系:

    BeanFactory接口及其子类定义了spring IoC容器体系结构,由于BeanFactory体系非常的庞大和复杂,因此要理解Spring IoC,需要先理清BeanFactory的继承机构。

               

2.ApplicationContext的结构体系:

     ApplicationContext接口是一个BeanFactory基础上封装了更多功能的,Spring中最为常用的IoC容器,其包含两个子接口:ConfigurableApplicationContext、WebApplicationContext。

ApplicationContext的三个实现类:

    a、ClassPathXmlApplication:把上下文文件当成类路径资源

    b、FileSystemXmlApplication:从文件系统中的XML文件载入上下文定义信息

   c、XmlWebApplicationContext:从Web系统中的XML文件载入上下文定义信息

    ApplicationContext接口,它由BeanFactory接口派生而来,因而提供BeanFactory所有的功能。ApplicationContext以一种更向面向框架的方式工作以及对上下文进行分层和实现继承,ApplicationContext包还提供了以下的功能:MessageSource, 提供国际化的消息访问、资源访问,如URL和文件、事件传播、载入多个(有继承关系)上下文 ,使得每一个上下文都专注于一个特定的层次,比如应用的web层。

3、ApplicationContext与BeanFActory区别

     BeanFactroy采用的是延迟加载形式来注入Bean的,即只有在使用到某个Bean时(调用getBean()),才对该Bean进行加载实例化,这样,我们就不能发现一些存在的spring的配置问题。而ApplicationContext则相反,它是在容器启动时,一次性创建了所有的Bean。这样,在容器启动时,我们就可以发现Spring中存在的配置错误。

2.3、Bean的生命周期

Bean的完整生命周期经历了各种方法调用,这些方法可以划分为以下几类:

1、Bean自身的方法:

这个包括了Bean本身调用的方法和通过配置文件中<bean>的init-method和destroy-method指定的方法

2、Bean级生命周期接口方法:

这个包括了BeanNameAware、BeanFactoryAware、InitializingBean和DiposableBean这些接口的方法

3、容器级生命周期接口方法:

这个包括了InstantiationAwareBeanPostProcessor和 BeanPostProcessor 这两个接口实现,一般称它们的实现类为“后处理器”。

4、工厂后处理器接口方法:

这个包括了AspectJWeavingEnabler, ConfigurationClassPostProcessor,CustomAutowireConfigurer等等非常有用的工厂后处理器  接口的方法。工厂后处理器也是容器级的。在应用上下文装配配置文件之后立即调用



三、Spring AOP

3.1、AOP概述

       AOP(Aspect-OrientedProgramming,面向方面编程),可以说是OOP(Object-Oriented Programing,面向对象编程)的补充和完善。OOP引入封装、继承和多态性等概念来建立一种对象层次结构,用以模拟公共行为的一个集合。当我们需要为分散的对象引入公共行为的时候,OOP则显得无能为力。也就是说,OOP允许你定义从上到下的关系,但并不适合定义从左到右的关系。例如日志功能。日志代码往往水平地散布在所有对象层次中,而与它所散布到的对象的核心功能毫无关系。对于其他类型的代码,如安全性、异常处理和透明的持续性也是如此。这种散布在各处的无关的代码被称为横切(cross-cutting)代码,在OOP设计中,它导致了大量代码的重复,而不利于各个模块的重用。

      而AOP技术则恰恰相反,它利用一种称为“横切”的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其名为“Aspect”,即方面。所谓“方面”,简单地说,就是将那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可操作性和可维护性。AOP代表的是一个横向的关系,如果说“对象”是一个空心的圆柱体,其中封装的是对象的属性和行为;那么面向方面编程的方法,就仿佛一把利刃,将这些空心圆柱体剖开,以获得其内部的消息。而剖开的切面,也就是所谓的“方面”了。然后它又以巧夺天功的妙手将这些剖开的切面复原,不留痕迹。

      使用“横切”技术,AOP把软件系统分为两个部分:核心关注点和横切关注点。业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点。横切关注点的一个特点是,他们经常发生在核心关注点的多处,而各处都基本相似。比如权限认证、日志、事务处理。Aop 的作用在于分离系统中的各种关注点,将核心关注点和横切关注点分离开来。正如Avanade公司的高级方案构架师Adam Magee所说,AOP的核心思想就是“将应用程序中的商业逻辑同对其提供支持的通用服务进行分离。”

       实现AOP的技术,主要分为两大类:一是采用动态代理技术,利用截取消息的方式,对该消息进行装饰,以取代原有对象行为的执行;二是采用静态织入的方式,引入特定的语法创建“方面”,从而使得编译器可以在编译期间织入有关“方面”的代码。

1、AOP使用场景

AOP用来封装横切关注点,具体可以在下面的场景中使用:

Authentication 权限

Caching 缓存

Context passing 内容传递

Error handling 错误处理

Lazy loading 懒加载

Debugging  调试

logging, tracing,profiling and monitoring 记录跟踪 优化 校准

Performanceoptimization 性能优化

Persistence  持久化

Resource pooling 资源池

Synchronization 同步

Transactions 事务

AOP核心概念

1.通知(Advice)

  就是你想要的功能,也就是上面说的 安全,事物,日志等。你给先定义好把,然后在想用的地方用一下。

2.连接点(JoinPoint

  这个更好解释了,就是spring允许你使用通知的地方,那可真就多了,基本每个方法的前,后(两者都有也行),或抛出异常时都可以是连接点,spring只支持方法连接点.其他如aspectJ还可以让你在构造器或属性注入时都行,不过那不是咱关注的,只要记住,和方法有关的前前后后(抛出异常),都是连接点。

3.切入点(Pointcut)

  上面说的连接点的基础上,来定义切入点,你的一个类里,有15个方法,那就有几十个连接点了对把,但是你并不想在所有方法附近都使用通知(使用叫织入,以后再说),你只想让其中的几个,在调用这几个方法之前,之后或者抛出异常时干点什么,那么就用切点来定义这几个方法,让切点来筛选连接点,选中那几个你想要的方法。

4.切面(Aspect)

  切面是通知和切入点的结合。现在发现了吧,没连接点什么事情,连接点就是为了让你好理解切点,搞出来的,明白这个概念就行了。通知说明了干什么和什么时候干(什么时候通过方法名中的before,after,around等就能知道),而切入点说明了在哪干(指定到底是哪个方法),这就是一个完整的切面定义。

5.引入(introduction)

  允许我们向现有的类添加新方法属性。这不就是把切面(也就是新方法属性:通知定义的)用到目标类中吗

6.目标(target)

  引入中所提到的目标类,也就是要被通知的对象,也就是真正的业务逻辑,他可以在毫不知情的情况下,被咱们织入切面。而自己专注于业务本身的逻辑。

7.代理(proxy)

怎么实现整套aop机制的,都是通过代理,这个一会给细说。

8.织入(weaving)

把切面应用到目标对象来创建新的代理对象的过程。有3种方式,spring采用的是运行时,为什么是运行时,后面解释。

关键就是:切点定义了哪些连接点会得到通知

 

Spring AOP的通知

spring aop通知(advice)分成五类:

前置通知[Beforeadvice]:在连接点前面执行,前置通知不会影响连接点的执行,除非此处抛出异常。

正常返回通知[Afterreturning advice]:在连接点正常执行完成后执行,如果连接点抛出异常,则不会执行。

异常返回通知[Afterthrowing advice]:在连接点抛出异常后执行。

返回通知[After(finally) advice]:在连接点执行完成后执行,不管是正常执行完成,还是抛出异常,都会执行返回通知中的内容。

环绕通知[Aroundadvice]:环绕通知围绕在连接点前后,比如一个方法调用的前后。这是最强大的通知类型,能在方法调用前后自定义一些操作。环绕通知还需要负责决定是继续处理join point(调用ProceedingJoinPoint的proceed方法)还是中断执行。

import org.aspectj.lang.JoinPoint;import org.aspectj.lang.ProceedingJoinPoint;public class TestAOP { public void doAfter(JoinPoint jp) {          System.out.println("log Ending method: " + jp.getTarget().getClass().getName() + "." + jp.getSignature().getName());      }        public Object doAround(ProceedingJoinPoint pjp) throws Throwable {          long time = System.currentTimeMillis();          Object retVal = pjp.proceed();          time = System.currentTimeMillis() - time;          System.out.println("process time: " + time + " ms");          return retVal;      }        public void doBefore(JoinPoint jp) {          System.out.println("log Begining method: " + jp.getTarget().getClass().getName() + "." + jp.getSignature().getName());      }        public void doThrowing(JoinPoint jp, Throwable ex) {          System.out.println("method " + jp.getTarget().getClass().getName() + "." + jp.getSignature().getName() + " throw exception");          System.out.println(ex.getMessage());      }}
<?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:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsdhttp://www.springframework.org/schema/aop   http://www.springframework.org/schema/aop/spring-aop.xsd"><aop:config>          <aop:aspect id="TestAspect" ref="aspect">              <!--配置com.spring.service包下所有类或接口的所有方法-->              <aop:pointcut id="businessService" expression="execution(* com.spring.testbean.*.*(..))" />              <aop:before pointcut-ref="businessService" method="doBefore"/>              <aop:after pointcut-ref="businessService" method="doAfter"/>              <aop:around pointcut-ref="businessService" method="doAround"/>              <aop:after-throwing pointcut-ref="businessService" method="doThrowing" throwing="ex"/>          </aop:aspect>  </aop:config> <bean id="helloworld" class="com.spring.testbean.HelloWorld"><property name="name" value="www1234"></property></bean><bean id="aspect" class="com.spring.testaop.TestAOP"></bean></beans>

public class HelloWorld {private String name;public String getName() {return name;}public void setName(String name) {this.name = name;}public void print(){System.out.println("hello "+name+" ");}}log Begining method: com.spring.testbean.HelloWorld.printhello www1234 process time: 11 mslog Ending method: com.spring.testbean.HelloWorld.print

基于注解的AOP实现

<?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:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsdhttp://www.springframework.org/schema/aop   http://www.springframework.org/schema/aop/spring-aop.xsd"><aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy><bean class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator"/><bean id="helloworld" class="com.spring.testbean.Student"><property name="name" value="www1234"></property></bean><bean id="aspect" class="com.spring.testaop.AnnoAOP"></bean></beans>

public interface IStudent {public void print();}public class Student implements IStudent{private String name;public String getName() {return name;}public void setName(String name) {this.name = name;}public void print(){System.out.println("hello "+name+" ");}}

import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.annotation.After;import org.aspectj.lang.annotation.AfterReturning;import org.aspectj.lang.annotation.AfterThrowing;import org.aspectj.lang.annotation.Around;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Before;import org.aspectj.lang.annotation.Pointcut;@Aspectpublic class AnnoAOP { @Pointcut("execution(* com.spring.testbean.*.*(..))")      private void pointCutMethod() {      }        //声明前置通知      @Before("pointCutMethod()")      public void doBefore() {          System.out.println("前置通知");      }        //声明后置通知      @AfterReturning(pointcut = "pointCutMethod()", returning = "result")      public void doAfterReturning(String result) {          System.out.println("后置通知");          System.out.println("---" + result + "---");      }        //声明例外通知      @AfterThrowing(pointcut = "pointCutMethod()", throwing = "e")      public void doAfterThrowing(Exception e) {          System.out.println("例外通知");          System.out.println(e.getMessage());      }        //声明最终通知      @After("pointCutMethod()")      public void doAfter() {          System.out.println("最终通知");      }        //声明环绕通知      @Around("pointCutMethod()")      public Object doAround(ProceedingJoinPoint pjp) throws Throwable {          System.out.println("进入方法---环绕通知");          Object o = pjp.proceed();          System.out.println("退出方法---环绕通知");          return o;      }  }

public class Main {public static void main(String[] args) {ApplicationContext act = new ClassPathXmlApplicationContext("applicationContext.xml");IStudent helloWorld = (IStudent)act.getBean("helloworld");helloWorld.print();}}