《Spring实战》学习笔记-第一章:Spring之旅

容纳Bean

在Spring中,应用对象生活于Spring容器中,如图所示,Spring容器可以成立、装载、配置那些Bean,并且可以管理它们的生命周期。

MyBatis 1

在Spring中,对象由Spring容器创造、装配、管理

简洁的Spring

为了降低Java开发的纷繁,Spring接纳了以下4种重大策略:

  • 基于POJO的轻量级和微小侵入性编程;
  • 通过倚重注入和面向接口实现松耦合;
  • 基于切面和规矩举行声明式编程;
  • 通过切面和模板缩小样板式代码。

常用的三种拔取上下文

  • ClassPathXmlApplicationContext:从类路径中的XML配置文件加载上下文,会在有着的类路径(包括jar文件)下寻找;
  • FileSystemXmlApplicationContext:从文件系统中读取XML配置文件并加载上下文,在指定的文件系统路径下搜寻;
  • XmlWebApplicationContext:读取Web应用下的XML配置文件并加载上下文;

Spring模块

MyBatis 2

Spring中的6个重点模块

Spring的器皿实现

  • Bean工厂(org.springframework.beans.factory.BeanFactory):最简便的容器,提供基本的DI帮助;
  • 接纳上下文(org.springframework.context.ApplicationContext):基于BeanFactory之上构建,提供面向应用的服务。

Bean的生命周期

MyBatis 3

Spring中Bean的生命周期

  1. Spring对Bean举办实例化;
  2. Spring将值和Bean的引用注入进Bean对应的特性中;
  3. 如果Bean实现了BeanNameAware接口,Spring将Bean的ID传递给setBeanName()接口方法;
  4. 如果Bean实现了BeanFactoryAware接口,Spring将调setBeanFactory()接口方法,将BeanFactory容器实例传入;
  5. 如果Bean实现了ApplicationContextAware接口,Spring将调用setApplicationContext()接口方法,将接纳上下文的引用传入;
  6. 如果Bean实现了BeanPostProcessor接口,Spring将调用postProcessBeforeInitialization()接口方法;
  7. 如果Bean实现了InitializationBean接口,Spring将调用afterPropertiesSet()主意。类似的比方Bean使用了init-method声称了开端化方法,该方法也会被调用;
  8. 如果Bean实现了BeanPostProcessor接口,Spring将调用ProcessAfterInitialization()方法;
  9. 眼下,Bean已经准备妥当,可以被应用程序使用了,它们将向来驻留在应用上下文中,直到该应用上下文被销毁;
  10. 如果Bean实现了DisposableBean接口,Spring将调用destory()艺术,同样的,即使Bean中接纳了destroy-method注解了销毁方法,也会调用该办法;

使用Spring模版

动用Spring模版可以清除许多样板式代码,比如JDBC、JMS、JNDI、REST等。

数码访问与集成

Spring的JDBC和DAO模块封装了大量的规范代码,这样可以使得在数据库代码变得简单,也足以更注意于大家的工作,仍可以够避免数据库资源自由败北而引发的题目。另外,Spring
AOP为数据访问提供了事务管理服务。同时,Spring还与流程的ORM(Object-Relational
Mapping)举办了合并,如Hibernate、MyBatis等。

核心Spring容器

容器是Spring框架最基本的部分,它担负Spring应用中Bean的创立、配置和管制。Spring模块都构建与主导容器之上,当配置利用时,其实都隐式地运用了相关的基本容器类。另外,该模块还提供了过多店家级劳动,如邮件、JNDI访问、EJB集成和调度等。

Spring是咋样注入的?

Spring通过利用上下文(ApplicationContext)来装载Bean,ApplicationContext全权负责对象的创办和组建。

Spring自带了多种ApplicationContext来加载配置,比如,Spring可以动用ClassPathXmlApplicationContext来装载XML文件中的Bean对象。

package com.springinaction.knights;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class KnightMain {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("knights.xml");// 加载Spring上下文
        Knight knight = (Knight) context.getBean("knight");// 获取knight Bean
        knight.embarhOnQuest();// 使用knight
    }
}

其一示例代码中,Spring上下文加载了knights.xml文件,随后得到了一个ID为knight的Bean的实例,得到该目标实例后,就能够展开健康的行使了。需要专注的是,那多少个类中全然不精晓是由哪些Knight来执行何种Quest任务,唯有knights.xml文本知道。

测试

Spring提供了测试模块来测试Spring应用。

流入一个Quest到Knight

创办应用组件之间协作关系的行事称为装配,Spring有多种装配Bean的点子,其中最常用的就是经过XML配置文件的主意装配。
以身作则代码:使用Spring将SlayDragonQuest注入到BraveKnight中。

<?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="knight" class="com.springinaction.knights.BraveKnight">
        <constructor-arg ref="quest"></constructor-arg>
    </bean>

    <bean id="quest" class="com.springinaction.knights.SlayDragonQuest"></bean>

</beans>

Web和远程调用

Spring提供了两种Web层框架:面向传统Web应用的依照Servlet的框架和面向应用Java
Portlet
API的按照Portlet的利用。Spring远程调用服务集成了RMI、Hessian、Burlap、JAX-WS等。

运用切面

通常情状下,系统由众多两样组件组成,其中的每一个零件分别承担一块特定功效。除了实现我核心的效应之外,这多少个零部件还每每承担着额外的职责,诸如日志、事务管理和平安等,此类的体系服务日常融入到有自身核心工作逻辑的零部件中去,这多少个序列服务普通被号称横切关注点,因为它们总是跨越系统的三个零件,如下图所示。

MyBatis 4

对分布系统的横切关注点的调用散布在相继零部件里,而这个关注点并不是组件的核心工作

AOP可以使得那些服务模块化,并以注解的章程将它们采纳到对应的组件中去,这样,这一个零件就颇具更高内聚性以及进一步关注自己工作,完全不需要精通可能涉及的序列服务的错综复杂。可想而知,AOP确保POJO保持简单。

MyBatis 5

行使AOP,可以将横切关注点覆盖在所需的组件之上,而那一个零部件不再需要异常的关注这多少个非核心业务。

如图所示,大家可以把切面想象为掩盖在重重组件之上的一个外壳。利用AOP,你能够动用各样效能层去包裹主旨业务层。那么些层以宣示的点子灵活运用到您的系列中,甚至你的中坚应用根本不掌握它们的存在。

AOP

AOP是Spring应用体系开发切面的底蕴,与依靠注入一样,能够匡助应用对象解耦。借助于AOP,可以将遍布于采取的关注点(如工作和安全等)从所使用的目的中解耦出来。

纵观Spring

看重注入

其余一个有含义的应用一般都亟需两个零件,这一个零件之间必然需要开展互相协作才能成功一定的事务,从而造成组件之间的紧耦合,牵一发而动全身
代码示例:

package com.springinaction.knights;

public class DamselRescuingKnight implements Knight {

    private RescueDamselQuest quest;

    public DamselRescuingKnight() {
        quest = new RescueDamselQuest();// 与RescueDamselQuest紧耦合
    }

    @Override
    public void embarhOnQuest() throws QuestException {
        quest.embark();
    }

}

正如你所见,DamselRescuingKnight
在它的构造函数中自行创设了RescueDamselQuest,这使得DamselRescuingKnight和RescueDamselQuest紧密地耦合到了一起,因而极大地界定了这些骑士的实践力量。假使一个姑娘需要抢救,这个骑士可以召之即来。可是一旦一条恶龙需要杀掉,那么这多少个骑士只好爱莫能助了。

另一方面,可以由此依赖注入的措施来成功目的期间的依靠关系,对象不再需要活动管理它们的倚重关系,而是通过倚重注入自动地注入到目的中去。

代码示例:

package com.springinaction.knights;

public class BraveKnight implements Knight {

    private Quest quest;

    public BraveKnight(Quest quest) {
        this.quest = quest;// quest被注入到对象中
    }

    @Override
    public void embarhOnQuest() throws QuestException {
        quest.embark();
    }

}

不同于从前的DamselRescuingKnight,BraveKnight没有机关创制探险任务,而是在构造器中把探险任务作为参数注入,这也是凭借注入的一种方法,即构造器注入

更为首要的是,BraveKnight中注入的探险类型是Quest,Quest只是一个探险任务所不可不贯彻的接口。因而,BraveKnight可以响RescueDamselQuest、SlayDraonQuest等任意一种Quest实现,这多亏多态的体现。

这里的要点是BraveKnight没有与其他特定的Quest实现暴发耦合。对它来说,被要求挑衅的探险任务只要实现了Quest接口,那么具体是哪一项目标探险就无关首要了。这就是借助注入最大的补益–松耦合。假若一个对象只经过接口MyBatis,(而不是切实贯彻或开头化的长河)来声明倚重关系,那么这种倚重就可知在目的自我毫不知情的气象下,用不同的切切实实贯彻举办替换。

激发POJO的潜能

绝对于EJB的重叠,Spring尽量制止因自身的api而弄乱用户的施用代码,Spring不会迫使用户实现Spring规范的接口或持续Spring规范的类,相反,在遵照Spring构建的行使中,它的类一般没有此外痕迹注脚你利用了Spring。最坏的场景是,一个类可能会动用Spring表明,但它仍旧是POJO。

Spring赋予POJO魔力的不二法门之一就是由此依赖注入来装载它们。

AOP应用

接上头骑士的故事,现在内需一个骚人来赞誉骑士的强悍事迹,代码如下「Minstrel是中世纪的音乐记录器」:

package com.springinaction.knights;

public class Minstrel {
    public void singBeforeQuest() { // 探险之前调用
        System.out.println("Fa la la; The knight is so brave!");
    }

    public void singAfterQuest() { // 探险之后调用
        System.out.println("Tee hee he; The brave knight did embark on a quest!");
    }
}

如代码中所示,作家会在骑兵每趟执行探险前和了结时被调用,完成骑士事迹的赞誉。骑士必须调用散文家的不二法门成功歌颂:

package com.springinaction.knights;

public class BraveKnight implements Knight {

    private Quest quest;
    private Minstrel minstrel;

    public BraveKnight(Quest quest) {
        this.quest = quest;// quest被注入到对象中
    }

    public BraveKnight(Quest quest, Minstrel minstrel) {
        this.quest = quest;// quest被注入到对象中
        this.minstrel = minstrel;
    }

    @Override
    public void embarhOnQuest() throws QuestException {
        minstrel.singAfterQuest();
        quest.embark();
        minstrel.singAfterQuest();
    }

}

但是,感觉是骑士在路边抓了一个小说家为友好「歌功颂德」,而不是小说家主动地为其扩散事迹。简单的BraveKnight类开始变得复杂,假若骑士不需要作家,那么代码将会愈加复杂。

可是有了AOP,骑士就不再需要协调调用散文家的不二法门为友好劳动了,这就需要把Minstrel注脚为一个断面:

<?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.xsd        
    http://www.springframework.org/schema/aop 
    http://www.springframework.org/schema/aop/spring-aop.xsd">

    <bean id="knight" class="com.springinaction.knights.BraveKnight">
        <constructor-arg ref="quest"></constructor-arg>
    </bean>

    <bean id="quest" class="com.springinaction.knights.SlayDragonQuest"></bean>

    <!-- 声明诗人Minstrel,待切入的对象(刀) -->
    <bean id="minstrel" class="com.springinaction.knights.Minstrel"></bean>

    <aop:config>
        <aop:aspect ref="minstrel">
            <!-- 定义切面,即定义从哪里切入 -->
            <aop:pointcut expression="execution(* *.embarkOnQuest(..))"
                id="embark" />
            <!-- 声明前置通知,在切入点之前执行的方法 -->
            <aop:before method="singBeforeQuest" pointcut-ref="embark" />

            <!-- 声明后置通知,在切入点之后执行的方法  -->
            <aop:after method="singAfterQuest" pointcut-ref="embark" />
        </aop:aspect>
    </aop:config>

</beans>

经过运行结果可以窥见,在尚未改动BraveKnight的代码的动静下,就做到了Minstrel对其的赞叹,而且BraveKnight并不知道Minstrel的存在。

网站地图xml地图