打开Spring世界的大门(上)


前言:

Spring是Java EE编程领域的一个轻量级开源框架,方便企业开发,本文主要简析Spring的相关知识点。


1.关于spring框架的优点

1.低侵入式设计,代码污染极低,轻量级的框架

2.方便解耦、简化开发,Spring是一个大工厂,可以将所有对象的创建和依赖关系的维护工作都交给Spring容器的管理,大大的降低了组件之间的耦合性。

3.Spring的DI机制降低了业务对象替换的复杂性,提高了组件之间的解耦

4.Spring的AOP支持允许将一些通用任务如安全、事务、日志等进行集中式管理,从而提供了更好的复用

5.支持声明式事务处理,只需要通过配置就可以完成对事物的管理,而无须手动编程。

6.Spring不排斥各种优秀的开源框架,其内部提供了对各种优秀框架(如Struts、Hibernate、MyBatis、Quartz等)的直接支持。

7.Spring提供了对Junit4的支持,可以通过注解方便的测试Spring程序。

8.Spring对Java EE开发中非常难用的一些API(如JDBC、JavaMail等),都提供了封装,使这些API应用难度大大降低。


2.Spring框架包含哪些模块

Spring框架包含以下7个模块:

  • 核心容器:核心容器提供 Spring 框架的基本功能。核心容器的主要组件是BeanFactory,它是工厂模式的实现。BeanFactory使用控制反转 (IOC) 模式将应用程序的配置和依赖性规范与实际的应用程序代码分开。
  • Spring 上下文:Spring 上下文是一个配置文件,向 Spring 框架提供上下文信息。Spring 上下文包括企业服务,例如 JNDI、EJB、电子邮件、国际化、校验和调度功能。
  • Spring AOP:通过配置管理特性,Spring AOP 模块直接将面向方面的编程功能集成到了 Spring 框架中。所以,可以很容易地使 Spring 框架管理的任何对象支持 AOP。Spring AOP 模块为基于 Spring 的应用程序中的对象提供了事务管理服务。通过使用 Spring AOP,不用依赖 EJB 组件,就可以将声明性事务管理集成到应用程序中。
  • Spring DAO:JDBC DAO 抽象层提供了有意义的异常层次结构,可用该结构来管理异常处理和不同数据库供应商抛出的错误消息。异常层次结构简化了错误处理,并且极大地降低了需要编写的异常代码数量(例如打开和关闭连接)。Spring DAO 的面向 JDBC 的异常遵从通用的 DAO 异常层次结构。
  • Spring ORM:Spring 框架插入了若干个 ORM 框架,从而提供了 ORM 的对象关系工具,其中包括 JDO、Hibernate 和 iBatis SQL Map。所有这些都遵从 Spring 的通用事务和 DAO 异常层次结构。
  • Spring Web 模块:Web 上下文模块建立在应用程序上下文模块之上,为基于 Web 的应用程序提供了上下文。所以,Spring 框架支持与 Jakarta Struts 的集成。Web 模块还简化了处理多部分请求以及将请求参数绑定到域对象的工作。
  • Spring MVC 框架:MVC 框架是一个全功能的构建 Web 应用程序的 MVC 实现。通过策略接口,MVC 框架变成为高度可配置的,MVC 容纳了大量视图技术,其中包括 JSP、Velocity、Tiles、iText 和 POI。

3.关于Spring框架中的单例bean是否是线程安全的

线程安全:就是多线程访问时,采用了加锁机制,当一个线程访问该类的某个数据时,进行保护,其他线程不能进行访问直到该线程读取完,其他线程才可使用。不会出现数据不一致或者数据污染。

线程不安全: 就是不提供数据访问保护,有可能出现多个线程先后更改数据造成所得到的数据是脏数据

spring中的bean不是线程安全的,若要实现线程安全,则可使用 threadLocal 或不使用属性变量、配置scope为多例


4.关于什么是spring的内部bean

当一个bean仅被用作另一个bean的属性时,它能被声明为一个内部bean,为了定义inner
bean,在Spring的基于XML的 配置元数据中,可以在元素内使用元素,内部bean通常是匿名的,它们的Scope一般是prototype。


5.Spring框架中bean的生命周期

bean生命周期

1、Spring容器 读取bean的定义,并实例化bean。

2、按照Spring上下文对实例化的Bean进行配置--也就是IOC注入;

3、如果这个Bean已经实现了BeanNameAware接口,会调用它实现的setBeanName(String)方法,此处传递的就是Spring配置文件中Bean的id值

4、如果这个Bean已经实现了BeanFactoryAware接口,会调用它实现的setBeanFactory(setBeanFactory(BeanFactory)传递的是Spring工厂自身

5、如果这个Bean已经实现了ApplicationContextAware接口,会调用setApplicationContext(ApplicationContext)方法,传入Spring上下文(同样这个方式也可以实现步骤4的内容,但比4更好,因为ApplicationContext是BeanFactory的子接口,有更多的实现方法);

6、如果这个Bean关联了BeanPostProcessor接口,将会调用postProcessBeforeInitialization(Object obj, String s)方法,BeanPostProcessor经常被用作是Bean内容的更改,并且由于这个是在Bean初始化结束时调用那个的方法,也可以被应用于内存或缓存技术;

7、如果Bean在Spring配置文件中配置了init-method属性会自动调用其配置的初始化方法。

8、如果这个Bean关联了BeanPostProcessor接口,将会调用postProcessAfterInitialization(Object obj, String s)方法、;

注:以上工作完成以后就可以应用这个Bean了,那这个Bean是一个Singleton的,所以一般情况下我们调用同一个id的Bean会是在内容地址相同的实例,当然在Spring配置文件中也可以配置非Singleton。

9、当Bean不再需要时,会经过清理阶段,如果Bean实现了DisposableBean这个接口,会调用那个其实现的destroy()方法;

10、最后,如果这个Bean的Spring配置中配置了destroy-method属性,会自动调用其配置的销毁方法。


6.spring bean 的几种作用域

Spring框架支持以下五种bean的作用域:
(1)singleton : bean在每个Spring ioc 容器中只有一个实例。
(2)prototype:一个bean的定义可以有多个实例。
(3)request:每次http请求都会创建一个bean,该作用域仅在基于web的Spring ApplicationContext情形下有效。
(4)session:在一个HTTP Session中,一个bean定义对应一个实例。该作用域仅在基于web的Spring ApplicationContext情形下有效。
(5)global-session:在一个全局的HTTP Session中,一个bean定义对应一个实例。该作用域仅在基于web的Spring ApplicationContext情形下有效。缺省的Spring bean 的作用域是Singleton。


7.bean的装配和自动装配

bean装配:是指在Spring 容器中把bean组装到一起,前提是容器需要知道bean的依赖关系,如何通过依赖注入来把它们装配到一起。

bean自动装配:Spring 容器能够自动装配相互合作的bean,这意味着容器不需要配置,能通过Bean工厂自动处理bean之间的协作。


8.spring的自动装配方式

有五种自动装配的方式,可以用来指导Spring容器用自动装配方式来进行依赖注入。
(1)no:默认的方式是不进行自动装配,通过显式设置ref 属性来进行装配。
(2)byName:通过参数名 自动装配,Spring容器在配置文件中发现bean的autowire属性被设置成byname,之后容器试图匹配、装配和该bean的属性具有相同名字的bean。
(3)byType:通过参数类型自动装配,Spring容器在配置文件中发现bean的autowire属性被设置成byType,之后容器试图匹配、装配和该bean的属性具有相同类型的bean。如果有多个bean符合条件,则抛出错误。
(4)constructor:这个方式类似于byType, 但是要提供给构造器参数,如果没有确定的带参数的构造器参数类型,将会抛出异常。
(5)autodetect:首先尝试使用constructor来自动装配,如果无法工作,则使用byType方式。


9.Spring自动装配的优缺点

优点

(1)自动装配可以大大地减少属性和构造器参数的指派。

(2)自动装配也可以在解析对象时更新配置。

缺点

(1)在property和constructor-arg设置中的依赖总是重载自动装配,我们无法对原始类型(如int,long,boolean等就是首字母小写的那些类型),还有String,Classes做自动装配。这是受限于设计。

(2)自动装配跟直接装配(explicit wiring)相比较,在准确性方便还是差那么点,虽然没有明确地说明,但是Spring还是尽量避免这种模棱两可的情况,导致出现没预料到的结果。

(3)Spring容器生成文档的工具可能会不能使用装配的信息。

(4)容器中多个bean的定义可能要对setter和构造器参数做类型匹配才能做依赖注入,虽然对于array,collection和map来说不是啥问题,但是对于只有单一值的依赖来讲,这就有点讲不清楚了,所以如果没有唯一的bean
定义,那只能抛出异常。


10.Spring常用的注解

@Configuration把一个类作为一个IoC容器,它的某个方法头上如果注册了@Bean,就会作为这个Spring容器中的Bean。

@Autowired 默认按类型装配,如果我们想使用按名称装配,可以结合@Qualifier注解一起使用。

@Autowired @Qualifier("personDaoBean") 存在多个实例配合使用

@Component泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注。

@Service用于标注业务层组件

@Controller用于标注控制层组件(如struts中的action)

@Repository用于标注数据访问组件,即DAO组件

@Scope用于指定scope作用域的(用在类上)

@PostConstruct用于指定初始化方法(用在方法上)

@PreDestory用于指定销毁方法(用在方法上)

@Lazy(true) 表示延迟初始化

@DependsOn 定义Bean初始化及销毁时的顺序

@Primary 自动装配时当出现多个Bean候选者时,被注解为@Primary的Bean将作为首选者,否则将抛出异常


11.Spring的注解配置和XML配置对比

注释配置相对于 XML 配置具有很多的优势

它可以充分利用 Java 的反射机制获取类结构信息,这些信息可以有效减少配置的工作。如使用 JPA 注释配置 ORM 映射时,我们就不需要指定 POJO 的属性名、类型等信息,如果关系表字段和 PO JO属性名、类型都一致,您甚至无需编写任务属性映射信息——因为这些信息都可以通过 Java 反射机制获取。

注释和 Java 代码位于一个文件中,而 XML 配置采用独立的配置文件,大多数配置信息在程序开发完成后都不会调整,如果配置信息和 Java 代码放在一起,有助于增强程序的内聚性。而采用独立的 XML 配置文件,程序员在编写一个功能时,往往需要在程序文件和配置文件中不停切换,这种思维上的不连贯会降低开发效率。

因此在很多情况下,注释配置比 XML 配置更受欢迎,注释配置有进一步流行的趋势。Spring 2.5 的一大增强就是引入了很多注释类,现在您已经可以使用注释配置完成大部分 XML 配置的功能。

注释配置和 XML 配置的适用场合

注释配置不一定在先天上优于 XML 配置。如果 Bean 的依赖关系是固定的,(如 Service 使用了哪几个 DAO 类),这种配置信息不会在部署时发生调整,那么注释配置优于 XML 配置;反之如果这种依赖关系会在部署时发生调整,XML 配置显然又优于注释配置,因为注释是对 Java 源代码的调整,您需要重新改写源代码并重新编译才可以实施调整。

如果 Bean 不是自己编写的类(如 JdbcTemplate、SessionFactoryBean 等),注释配置将无法实施,此时 XML 配置是唯一可用的方式。

注释配置往往是类级别的,而 XML 配置则可以表现得更加灵活。比如相比于 @Transaction 事务注释,使用 aop/tx 命名空间的事务配置更加灵活和简单。

所以在实现应用中,我们往往需要同时使用注释配置和 XML 配置,对于类级别且不会发生变动的配置可以优先考虑注释配置;而对于那些第三方类以及容易发生调整的配置则应优先考虑使用 XML 配置。Spring 会在具体实施 Bean 创建和 Bean 注入之前将这两种配置方式的元信息融合在一起。

Spring 在 2.1 以后对注释配置提供了强力的支持,注释配置功能成为 Spring 2.5 的最大的亮点之一。合理地使用 Spring 2.5 的注释配置,可以有效减少配置的工作量,提高程序的内聚性。但是这并不意味着传统 XML 配置将走向消亡,在第三方类 Bean 的配置,以及那些诸如数据源、缓存池、持久层操作模板类、事务管理等内容的配置上,XML 配置依然拥有不可替代的地位。


12.依赖注入(DI)

1、依赖注入(DI)是对控制反转(IOC)的更准确的描述,即组件之间的依赖关系由容器在运行期决定,即由容器动态的将某种依赖关系注入到组件之中。依赖注入(DI)的基本原则是应用组件不应该负责查找或者其他依赖的写作对象。配置对象的工作应该由容器负责,查找资源的逻辑应该从应用组件的代码中抽取出来,交给容器来完成。

2、举个例子:一个类A需要用到一个接口B中的方法,那么就需要为类A和接口B建立关系或者是依赖关系,最原始的方法是在列A中创建一个接口B的实现类C的实例,但这种方法需要开发人员自行维护两者的依赖关系,也就是说当依赖关系发生变动的时候需要修改代码并重新构建整个系统.如果通过一个容器来管理这些对象以及对象的依赖关系,则只需要在类A中定义好用于关联接口B的方法(构造器或者setter方法),将类A和接口B的实现类C放入容器中,通过对容器的配置来实现二者的关联。

3、依赖注入可以通过setter方法注入(设置注入)、构造器注入和接口注入三种方式实现,spring支持setter注入和构造器注入,通常是由构造器注入来注入必须的依赖关系,对于可选的依赖关系,则setter注入是更好的选择。setter注入需要类提供无参构造器或者无参的静态工厂来创建对象。


13.控制反转(IOC)

控制反转(IOC)是把传统上由程序代码直接操控的对象的调用权交给容器,通过容器来实现对象组件的装配和管理。
所谓的“控制反转”就是对组件控制器的转移,从程序代码本身转移到了外部容器,由容器来创建对象并管理对象之间的依赖关系。


文章作者: jackey
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 jackey !
评论
  目录