为了账号安全,请及时绑定邮箱和手机立即绑定

投稿004期 | 知识点:spring 完全手册

什么是spring

spring是一个开源框架,为简化企业级开发而生,使用spring可以使简单的java bean 实现以前只有EJG才能实现的功能。

Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架。

spring的特点
  •   轻量——从大小与开销两方面而言Spring都是轻量的。完整的Spring框架可以在一个大小只有1MB多的JAR文件里发布。并 且Spring所需的处理开销也是微不足道的。此外,Spring是非侵入式的:典型地,Spring应用中的对象不依赖于Spring的特定类。 

  • 控制反转——Spring通过一种称作控制反转(IoC)的技术促进了松耦 合。当应用了IoC,一个对象依赖的其它对象会通过被动的方式传递进来,而不是这个对象自己创建或者查找依赖对象。你可以认为IoC与JNDI相反——不 是对象从容器中查找依赖,而是容器在对象初始化时不等对象请求就主动将依赖传递给它。 

  • 面向切面——Spring提供了面向切面编程的丰富支持,允许通过分离应用的 业务逻辑与系统级服务(例如审计(auditing)和事务()管理)进行内聚性的开发。应用对象只实现它们应该做的——完成业务逻辑——仅此而已。它们 并不负责(甚至是意识)其它的系统级关注点,例如日志或事务支持。 

  • 容器——Spring包含并管理应用对象的配置和生命周期,在这个意义上它是 一种容器,你可以配置你的每个bean如何被创建——基于一个可配置原型(prototype),你的bean可以创建一个单独的实例或者每次需要时都生 成一个新的实例——以及它们是如何相互关联的。然而,Spring不应该被混同于传统的重量级的EJB容器,它们经常是庞大与笨重的,难以使用。 

  • 框架——Spring可以将简单的组件配置、组合成为复杂的应用。在Spring中,应用对象被声明式地组合,典型地是在一个XML文件里。 Spring也提供了很多基础功能(事务管理、持久化框架集成等等),将应用逻辑的开发留给了你。
Spring包括哪些内容

 核心技术 IoC 和 AOP 

数据访问 (持久层解决方案)

Web层解决方案  SpringMVC 

集成 (整合其他开源框架)

 使用Spring有什么好处

Spring能有效地组织你的中间层对象,无论你是否选择使用了EJB。如果你仅仅使用了Struts或其他的包含了J2EE特有APIs的 framework,你会发现Spring关注了遗留下的问题,。 

Spring能消除在许多工程上对Singleton的过多使用。根据我的经验,这是一个主要的问题,它减少了系统的可测试性和面向对象特性。 

Spring能消除使用各种各样格式的属性定制文件的需要,在整个应用和工程中,可通过一种 一致的方法来进行配置。曾经感到迷惑,一个特定类要查找迷幻般的属性关键字或系统属性,为此不得不读Javadoc乃至源编码吗?有了Spring,你可 很简单地看到类的JavaBean属性。倒置控制的使用(在下面讨论)帮助完成这种简化。 

Spring能通过接口而不是类促进好的编程习惯,减少编程代价到几乎为零。 

Spring被设计为让使用它创建的应用尽可能少的依赖于他的APIs。在Spring应用中的大多数业务对象没有依赖于Spring。 

使用Spring构建的应用程序易于单元测试。 

Spring能使EJB的使用成为一个实现选择,而不是应用架构的必然选择。你能选择用POJOs或local EJBs来实现业务接口,却不会影响调用代码。 

Spring帮助你解决许多问题而无需使用EJB。Spring能提供一种EJB的替换物,它们适于许多web应用。例如,Spring能使用 AOP提供声明性事务而不通过使用EJB容器,如果你仅仅需要与单个的数据库打交道,甚至不需要JTA实现。 

Spring为数据存取提供了一致的框架,不论是使用JDBC或O/R mapping产品(如Hibernate)。 

Spring确实使你能通过最简单可行的解决办法解决你的问题。这些特性是有很大价值的。

总结起来,Spring有如下优点: 

低侵入式设计,代码污染极低 

 独立于各种应用服务器,可以真正实现Write Once,Run Anywhere的承诺 

Spring的DI机制降低了业务对象替换的复杂性 

Spring并不完全依赖于Spring,开发者可自由选用Spring框架的部分或全部

spring中的核心类有那些,各有什么作用
  • BeanFactory:产生一个新的实例,可以实现单例模式 

  • BeanWrapper:提供统一的get及set方法 

  • ApplicationContext:提供框架的实现,包括BeanFactory的所有功能 
spring常用的类和接口有哪些
  • A:ApplicationContextAware接口 

当一个类需要获取ApplicationContext实例时,可以让该类实现ApplicationContextAware接口。 

  • B:ApplicationEvent抽象类 

当需要创建自定义事件时,可以新建一个继承自ApplicationEvent抽象类的类。 

  • C:ApplicationListener接口 

当需要监听自定义事件时,可以新建一个实现ApplicationListener接口的类,并将该类配置到Spring容器中。 

  • D:BeanNameAware接口 

当bean需要获取自身在容器中的id/name时,可以实现BeanNameAware接口。 

  • E:InitializingBean接口 

当需要在bean的全部属性设置成功后做些特殊的处理,可以让该bean实现InitializingBean接口。 

效果等同于bean的init-method属性的使用或者@PostContsuct注解的使用。 

三种方式的执行顺序:先注解,然后执行InitializingBean接口中定义的方法,最后执行init-method属性指定的方法。 

  • F:DisposableBean接口 

当需要在bean销毁之前做些特殊的处理,可以让该bean实现DisposableBean接口。 

效果等同于bean的destroy-method属性的使用或者@PreDestory注解的使用。 

三种方式的执行顺序:先注解,然后执行DisposableBean接口中定义的方法,最后执行destroy-method属性指定的方法。 

  • G:BeanPostProcessor接口 

当需要对受管bean进行预处理时,可以新建一个实现BeanPostProcessor接口的类,并将该类配置到Spring容器中。 

  • H:BeanFactoryPostProcessor接口 

当需要对Bean工厂进行预处理时,可以新建一个实现BeanFactoryPostProcessor接口的类,并将该类配置到Spring容器中。 

spring事务的原理

事务管理的方式:编程型和声明型,spring推荐使用后一种方式 

声明型事务管理的优势非常明显:代码中无需关注关于事务逻辑,让Spring声明式事务管理负责事务逻辑,声明式事务管理无需与具体的事务逻辑耦 合,可以方便地在不同事务逻辑之间切换。 

什么是IOC,什么又是DI,他们有什么区别

依赖注入DI是一个程序设计模式和架构模型, 一些时候也称作控制反转,尽管在技术上来讲,依赖注入是一个IOC的特殊实现,依赖注入是指一个对象应用另外一个对象来提供一个特殊的能力,例如:把一个 数据库连接已参数的形式传到一个对象的结构方法里面而不是在那个对象内部自行创建一个连接。控制反转和依赖注入的基本思想就是把类的依赖从类内部转化到外 部以减少依赖 

应用控制反转,对象在被创建的时候,由一个调控系统内所有对象的外界实体,将其所依赖的对象的引用,传递给它。也可以说,依赖被注入到对象中。所 以,控制反转是,关于一个对象如何获取他所依赖的对象的引用,这个责任的反转。

image

Bean注入属性的几种方式

image

什么是aop,aop的作用是什么

面向切面编程(AOP)提供另外一种角度来思考程序结构,通过这种方式弥补了面向对象编程(OOP)的不足,除了类(classes)以外,AOP提供了切面。切面对关注点进行模块化,例如横切多个类型和对象的事务管理 

Spring的一个关键的组件就是AOP框架,可以自由选择是否使用AOP 提供声明式企业服务,特别是为了替代EJB声明式服务。最重要的服务是声明性事务管理,这个服务建立在Spring的抽象事物管理之上。允许用户实现自定义切面,用AOP来完善OOP的使用,可以把Spring AOP看作是对Spring的一种增强

image

AOP里面重要的几个名词概念解释
  • 切面(Aspect): 一个关注点的模块化,这个关注点可能会横切多个对象。事务管理是J2EE应用中一个关于横切关注点的很好的例子。 在Spring AOP中,切面可以使用通用类(基于模式的风格) 或者在普通类中以@Aspect注解(@AspectJ风格)来实现。

  • 连接点(Joinpoint): 在程序执行过程中某个特定的点,比如某方法调用的时候或者处理异常的时候。 在Spring AOP中,一个连接点 总是 代表一个方法的执行。 通过声明一个org.aspectj.lang.JoinPoint类型的参数可以使通知(Advice)的主体部分获得连接点信息。 

  • 通知(Advice): 在切面的某个特定的连接点(Joinpoint)上执行的动作。通知有各种类型,其中包括“around”、“before”和“after”等通知。 通知的类型将在后面部分进行讨论。许多AOP框架,包括Spring,都是以拦截器做通知模型, 并维护一个以连接点为中心的拦截器链。 

  • 切入点(Pointcut): 匹配连接点(Joinpoint)的断言。通知和一个切入点表达式关联,并在满足这个切入点的连接点上运行(例如,当执行某个特定名称的方法时)。 切入点表达式如何和连接点匹配是AOP的核心:Spring缺省使用AspectJ切入点语法。 

  • 引入(Introduction): (也被称为内部类型声明(inter-type declaration))。声明额外的方法或者某个类型的字段。 Spring允许引入新的接口(以及一个对应的实现)到任何被代理的对象。 例如,你可以使用一个引入来使bean实现 IsModified 接口,以便简化缓存机制。 

  • 目标对象(Target Object): 被一个或者多个切面(aspect)所通知(advise)的对象。也有人把它叫做 被通知(advised) 对象。 既然Spring AOP是通过运行时代理实现的,这个对象永远是一个 被代理(proxied) 对象。 

  • AOP代理(AOP Proxy): AOP框架创建的对象,用来实现切面契约(aspect contract)(包括通知方法执行等功能)。 在Spring中,AOP代理可以是JDK动态代理或者CGLIB代理。 注意:Spring 2.0最新引入的基于模式(schema-based)风格和@AspectJ注解风格的切面声明,对于使用这些风格的用户来说,代理的创建是透明的。 

  • 织入(Weaving): 把切面(aspect)连接到其它的应用程序类型或者对象上,并创建一个被通知(advised)的对象。 这些可以在编译时(例如使用AspectJ编译器),类加载时和运行时完成。 Spring和其他纯Java AOP框架一样,在运行时完成织入。 
通知的类型: 
  • 前置通知(Before advice): 在某连接点(join point)之前执行的通知,但这个通知不能阻止连接点前的执行(除非它抛出一个异常)。 

  • 返回后通知(After returning advice): 在某连接点(join point)正常完成后执行的通知:例如,一个方法没有抛出任何异常,正常返回。 

  • 抛出异常后通知(After throwing advice): 在方法抛出异常退出时执行的通知。 

  • 后通知(After (finally) advice): 当某连接点退出的时候执行的通知(不论是正常返回还是异常退出)。 

  • 环绕通知(Around Advice): 包围一个连接点(join point)的通知,如方法调用。这是最强大的一种通知类型。 环绕通知可以在方法调用前后完成自定义的行为。它也会选择是否继续执行连接点或直接返回它们自己的返回值或抛出异常来结束执行。 

环绕通知是最常用的一种通知类型。大部分基于拦截的AOP框架,例如Nanning和JBoss4,都只提供环绕通知。 

切入点(pointcut)和连接点(join point)匹配的概念是AOP的关键,这使得AOP不同于其它仅仅提供拦截功能的旧技术。 切入点使得定位通知(advice)可独立于OO层次。 例如,一个提供声明式事务管理的around通知可以被应用到一组横跨多个对象中的方法上(例如服务层的所有业务操作)。 

image

介绍一下Spring框架中Bean的生命周期和作用域
  • (1)  bean定义 

在配置文件里面用来进行定义。 

  • (2)  bean初始化 

有两种方式初始化: 

A.在配置文件中通过指定init-method属性来完成 

B.实现org.springframwork.beans.factory.InitializingBean接口 

  • (3)  bean调用 

有三种方式可以得到bean实例,并进行调用 

  • (4)  bean销毁 

销毁有两种方式 

A.使用配置文件指定的destroy-method属性 

B.实现org.springframwork.bean.factory.DisposeableBean接口 

作用域 
  • singleton 

当一个bean的作用域为singleton, 那么Spring IoC容器中只会存在一个共享的bean实例,并且所有对bean的请求,只要id与该bean定义相匹配,则只会返回bean的同一实例。 

  • prototype 

Prototype作用域的bean会导致在每次对该bean请求(将其注入到另一个bean中,或者以程序的方式调用容器的getBean() 方法)时都会创建一个新的bean实例。根据经验,对所有有状态的bean应该使用prototype作用域,而对无状态的bean则应该使用 singleton作用域 

  • request 

在一次HTTP请求中,一个bean定义对应一个实例;即每次HTTP请求将会有各自的bean实例, 它们依据某个bean定义创建而成。该作用 域仅在基于web的Spring ApplicationContext情形下有效。 

  • session 

在一个HTTP Session中,一个bean定义对应一个实例。该作用域仅在基于web的Spring  ApplicationContext情形下有效。 

  • global session 

在一个全局的HTTP Session中,一个bean定义对应一个实例。典型情况下,仅在使用portlet context的时候有效。该作用域仅在基于 web的Spring ApplicationContext情形下有效。 

Bean的初始化方式有哪些

有两种方式初始化Bean。

  • 1、在配置文档中通过指定init-method 属性来完成

在Bean的类中实现一个初始化Bean属性的方法,如init(),如:

public class HelloWorld{

public String msg=null;

public Date date=null;

public void init() {

msg=”HelloWorld”;

date=new Date();

}

……

}

然后,在配置文件中设置init-mothod属性:

  • 2、实现 org.springframwork.beans.factory.InitializingBean接口

Bean实现InitializingBean接口,并且增加 afterPropertiesSet() 方法:

public class HelloWorld implement InitializingBean {

public String msg=null;

public Date date=null;

public void afterPropertiesSet() {

msg=”向全世界问好!”;

date=new Date();

}

……

}

那么,当这个Bean的所有属性被Spring的BeanFactory设置完后,会自动调用afterPropertiesSet()方法对 Bean进行初始化,于是,配置文件就不用指定 init-method属性了。

Bean的调用方式有哪些

有三种方式可以得到Bean并进行调用:

1、使用BeanWrapper

HelloWorld hw=new HelloWorld();

BeanWrapper bw=new BeanWrapperImpl(hw);

bw.setPropertyvalue(”msg”,”HelloWorld”);

system.out.println(bw.getPropertyCalue(”msg”));

2、使用BeanFactory

InputStream is=new FileInputStream(”config.xml”);

XmlBeanFactory factory=new XmlBeanFactory(is);

HelloWorld hw=(HelloWorld) factory.getBean(”HelloWorld”);

system.out.println(hw.getMsg());

3、使用ApplicationConttext

ApplicationContext actx=new FleSystemXmlApplicationContext(”config.xml”);

HelloWorld hw=(HelloWorld) actx.getBean(”HelloWorld”);

System.out.println(hw.getMsg());

Bean的销毁方式有哪些
1、使用配置文件中的 destory-method 属性

与初始化属性 init-methods类似,在Bean的类中实现一个撤销Bean的方法,然后在配置文件中通过 destory-method指定,那么当bean销毁时,Spring将自动调用指定的销毁方法。

2、实现 org.springframwork.bean.factory.DisposebleBean接口

如果实现了DisposebleBean接口,那么Spring将自动调用bean中的Destory方法进行销毁,所以,Bean中必须提供 Destory方法。

介绍一下Spring的事务管理
事务就是对一系列的数据库操作(比如插入多条数据)进行统一的提交或回滚操作,如果插入成功,那么一起成功,如果中间有一条出现异常,那么回滚之 前的所有操作。 

这样可以防止出现脏数据,防止数据库数据出现问题。 

开发中为了避免这种情况一般都会进行事务管理。Spring中也有自己的事务管理机制,一般是使用TransactionMananger进行管 理,可以通过Spring的注入来完成此功能。 

spring提供了几个关于事务处理的类: 

TransactionDefinition //事务属性定义 

TranscationStatus //代表了当前的事务,可以提交,回滚。 

PlatformTransactionManager这个是spring提供的用于管理事务的基础接口,其下有一个实现的抽象类 AbstractPlatformTransactionManager,我们使用的事务管理类例如 DataSourceTransactionManager等都是这个类的子类。 

一般事务定义步骤: 

TransactionDefinition td = new TransactionDefinition(); 

TransactionStatus ts = transactionManager.getTransaction(td); 

try 

{ //do sth 

transactionManager.commit(ts); 

catch(Exception e){transactionManager.rollback(ts);} 

spring提供的事务管理可以分为两类:编程式的和声明式的。编程式的,比较灵活,但是代码量大,存在重复的代码比较多;声明式的比编程式的更 灵活。 

编程式主要使用transactionTemplate。省略了部分的提交,回滚,一系列的事务对象定义,需注入事务管理对象. 

void add(){ 

transactionTemplate.execute( new TransactionCallback(){ 

pulic Object doInTransaction(TransactionStatus ts) 

{ //do sth} 

声明式: 

使用TransactionProxyFactoryBean: 

PROPAGATION_REQUIRED PROPAGATION_REQUIRED PROPAGATION_REQUIRED,readOnly 

围绕Poxy的动态代理 能够自动的提交和回滚事务 

org.springframework.transaction.interceptor.TransactionProxyFactoryBean 

PROPAGATION_REQUIRED–支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。 

PROPAGATION_SUPPORTS–支持当前事务,如果当前没有事务,就以非事务方式执行。 

PROPAGATION_MANDATORY–支持当前事务,如果当前没有事务,就抛出异常。 

PROPAGATION_REQUIRES_NEW–新建事务,如果当前存在事务,把当前事务挂起。 

PROPAGATION_NOT_SUPPORTED–以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。 

PROPAGATION_NEVER–以非事务方式执行,如果当前存在事务,则抛出异常。 

PROPAGATION_NESTED–如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则进行与 PROPAGATION_REQUIRED类似的操作。

Spring如何处理线程并发问题

Spring使用ThreadLocal解决线程安全问题

我们知道在一般情况下,只有无状态的Bean才可以在多线程环境下共享,在Spring中,绝大部分Bean都可以声明为singleton作用域。就是因为Spring对一些Bean(如RequestContextHolder、TransactionSynchronizationManager、LocaleContextHolder等)中非线程安全状态采用ThreadLocal进行处理,让它们也成为线程安全的状态,因为有状态的Bean就可以在多线程中共享了。

ThreadLocal和线程同步机制都是为了解决多线程中相同变量的访问冲突问题。

在同步机制中,通过对象的锁机制保证同一时间只有一个线程访问变量。这时该变量是多个线程共享的,使用同步机制要求程序慎密地分析什么时候对变量进行读写,什么时候需要锁定某个对象,什么时候释放对象锁等繁杂的问题,程序设计和编写难度相对较大。

而ThreadLocal则从另一个角度来解决多线程的并发访问。ThreadLocal会为每一个线程提供一个独立的变量副本,从而隔离了多个线程对数据的访问冲突。因为每一个线程都拥有自己的变量副本,从而也就没有必要对该变量进行同步了。ThreadLocal提供了线程安全的共享对象,在编写多线程代码时,可以把不安全的变量封装进ThreadLocal。

由于ThreadLocal中可以持有任何类型的对象,低版本JDK所提供的get()返回的是Object对象,需要强制类型转换。但JDK5.0通过泛型很好的解决了这个问题,在一定程度地简化ThreadLocal的使用。

概括起来说,对于多线程资源共享的问题,同步机制采用了“以时间换空间”的方式,而ThreadLocal采用了“以空间换时间”的方式。前者仅提供一份变量,让不同的线程排队访问,而后者为每一个线程都提供了一份变量,因此可以同时访问而互不影响。

by:一只阿木木

点击查看更多内容
2人点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
JAVA开发工程师
手记
粉丝
40
获赞与收藏
206

关注作者,订阅最新文章

阅读免费教程

感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消