Spring

Spring简介

<span style="color:#000000"><code>Spring是一个分层的Java SE/EE应用一站式的轻量级开源框架。Spring核心是IOC和AOP。 
</code></span>

Spring优点

<span style="color:#000000"><code>-方便解耦,简化开发,通过Spring提供的IoC容器,我们可以将对象之间的依赖关系交由Spring进行控制,避免硬编码造成的程序耦合度高。 

-AOP编程的支持,通过Spring提供的AOP功能,方便进行面向切面编程。

-声明式事务的支持,在Spring中,我们可以从单调烦闷的事务管理代码中解脱出来,通过声明式方式灵活地进行事务的管理,提高开发效率和质量。

-方便程序的测试,可以用非容器依赖的编程方式进行几乎所有的测试工作。

-方便集成各种优秀框架,Spring提供了对各种优秀框架的直接支持。
</code></span>

Spring的体系结构

spring的关键技术 spring技术体系_依赖关系

整个Spring框架按其所属功能可以划分为五个主要模块,这五个模块几乎为企业应用提供了所需的一切,从持久层、业务层到表现层都拥有相应的支持,这就是Spring为什么是一站式框架。IoC和AOP是Spring的核心。

-核心模块(Core Container)

  • Spring的核心模块实现了IoC的功能,它将类和类之间的依赖从代码中脱离出来,用配置的方式进行依赖关系描述。 由IoC容器负责类的创建,管理,获取等。BeanFactory接口是Spring框架的核心接口,实现了容器很多核心的功能。
  • Context模块构建于核心模块之上,扩展了BeanFactory的功能,包括国际化,资源加载,邮件服务,任务调度等多项功能。ApplicationContext是Context模块的核心接口。
  • 表达式语言(Expression Language)是统一表达式语言(EL)的一个扩展,支持设置和获取对象属性,调用对象方法,操作数组、集合等。使用它可以很方便的通过表达式和Spring IoC容器进行交互。

-AOP模块

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

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

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

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

-Web模块

  • 该模块建立在AoolicationContext模块之上,提供了Web应用的功能。如文件上传、FreeMarker等。
  • Spring可以整合Struts2等MVC框架。Spring自己提供了MVC框架Spring MVC。

-测试模块

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

Spring的IoC容器详解

我们首先来讲解一下IoC的概念。 
IoC(控制反转:Inverse of Control)是Spring容器的核心。但是IoC这个概念却比较晦涩,让人不太容易望文生义。

IoC控制反转和DI依赖注入

  • 传统程序设计中,我们需要使用某个对象的方法,需要先通过new创建一个该对象,我们这时是主动行为。而IoC是我们将创建对象的控制权交给IoC容器,这时是由容器帮忙创建及注入依赖对象,我们的程序被动的接受IoC容器创建的对象,控制权反转,所以叫控制反转。
  • 因为IoC确实不够开门见山,所以提出了DI(依赖注入:Dependency Injection)的概念 
    即让第三方来实现注入,以移除我们类与需要使用的类之间的依赖关系。
  • IoC是目的,DI是手段。我们为了实现IoC,让生成对象的方式由传统方式(new)反转过来,需要创建相关对象时由IoC容器帮我们注入。(DI)
  • 简单的说,就是我们类里需要另一个类,只需要让Spring帮我们创建 ,这叫做控制反转,然后Spring帮我们将需要的对象设置到我们的类中,这叫做依赖注入。

注入方法

  • 使用有参构造方法注入
<span style="color:#000000"><code>        <span style="color:#000088">public</span> <span style="color:#000088">class</span>  User{
            <span style="color:#000088">private</span> String name;
            <span style="color:#000088">public</span> <span style="color:#009900">User</span>(String name){
                <span style="color:#000088">this</span>.name=name;
            }
        } 

        User user=<span style="color:#000088">new</span> User(<span style="color:#009900">"tom"</span>);</code></span>
  • 使用属性注入
<span style="color:#000000"><code>    通过属性的<span style="color:#000088">set</span>方法进行注入。 

        <span style="color:#000088">public</span> <span style="color:#000088">class</span>  User{
            <span style="color:#000088">private</span> String name;
            <span style="color:#000088">public</span> <span style="color:#000088">void</span> <span style="color:#009900">setName</span>(String name){
                <span style="color:#000088">this</span>.name=name;
            }
        }

        User user=<span style="color:#000088">new</span> User();
        user.setName(<span style="color:#009900">"jack"</span>);</code></span>
  • 使用接口注入
<span style="color:#000000"><code>        将调用类所有依赖注入的方法抽取到接口中,调用类通过实现该接口提供相应的注入方法。 

        <span style="color:#000088">public</span> <span style="color:#000088">interface</span> <span style="color:#4f4f4f">Dao</span>{
            <span style="color:#000088">public</span> <span style="color:#000088">void</span> <span style="color:#009900">delete</span>(String name);
        } 

        <span style="color:#000088">public</span> <span style="color:#000088">class</span> <span style="color:#4f4f4f">DapIml</span> <span style="color:#000088">implements</span> <span style="color:#4f4f4f">Dao</span>{
            <span style="color:#000088">private</span> String name;
            <span style="color:#000088">public</span> <span style="color:#000088">void</span> <span style="color:#009900">delete</span>(String name){
                <span style="color:#000088">this</span>.name=name;
            }

        }
</code></span>
  • 通过容器完成依赖关系的注入

上面的注入方式都需要我们手动的进行注入,如果有一个第三方容器能帮助我们完成类的实例化,以及依赖关系的装配,而我们只需要专注于业务逻辑的开发即可。Spring就是这样的容器,它通过配置文件或注解描述类和类之间的依赖关系,自动完成类的初始化和依赖注入的工作。

Spring的IoC例子

  • 一 .创建工程,导入jar包
<span style="color:#000000"><code>    这里我们只是做IoC的操作,所以只需要导入核心模块里的jar包,beans,core,context,expression等 
    因为spring中并没有日志相关的jar包,所以我们还需要导入log4j和commons-logging  
</code></span>
  • 二 .创建一个类
<span style="color:#000000"><code>        <span style="color:#000088">public</span> <span style="color:#000088">class</span> User {
            <span style="color:#000088">public</span> <span style="color:#000088">void</span> <span style="color:#009900">add</span>(){
                System.<span style="color:#000088">out</span>.println(<span style="color:#009900">"add....."</span>);
            }
        }</code></span>
  • 三 .创建一个类
<span style="color:#000000"><code>创建一个xml配置文件,放在src目录下,名字可以随便取  
            <span style="color:#006666"><?xml version="1.0" encoding="UTF-8"?></span>
            <span style="color:#006666"><<span style="color:#4f4f4f">beans</span> <span style="color:#4f4f4f">xmlns</span>=<span style="color:#009900">"http://www.springframework.org/schema/beans"</span>
                <span style="color:#4f4f4f">xmlns:xsi</span>=<span style="color:#009900">"http://www.w3.org/2001/XMLSchema-instance"</span>
                <span style="color:#4f4f4f">xsi:schemaLocation</span>=<span style="color:#009900">"
                    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"</span>></span> 

             //配置要创建的类  
            <span style="color:#006666"><<span style="color:#4f4f4f">bean</span> <span style="color:#4f4f4f">id</span>=<span style="color:#009900">"user"</span> <span style="color:#4f4f4f">class</span>=<span style="color:#009900">"com.cad.domain.User"</span>></span><span style="color:#006666"></<span style="color:#4f4f4f">bean</span>></span>        
            <span style="color:#006666"></<span style="color:#4f4f4f">beans</span>></span>  </code></span>
  • 四 .进行测试
<span style="color:#000000"><code>    <span style="color:#880000">//这只是用来测试的代码,后期不会这么写</span>
    <span style="color:#000088">public</span> <span style="color:#000088">class</span> Test {

            @org.junit.Test
            <span style="color:#000088">public</span> <span style="color:#000088">void</span> <span style="color:#009900">test</span>(){
                <span style="color:#880000">//加载配置文件</span>
                ApplicationContext context=<span style="color:#000088">new</span> ClassPathXmlApplicationContext(<span style="color:#009900">"bean.xml"</span>);
                <span style="color:#880000">//获取对象</span>
                User user=(User) context.getBean(<span style="color:#009900">"user"</span>);
                System.<span style="color:#000088">out</span>.println(user);
                <span style="color:#880000">//调用方法</span>
                user.add();
            }
    }       </code></span>

在容器启动时,Spring会根据配置文件的描述信息,自动实例化Bean并完成依赖关系的装配,从容器中即可获得Bean实例,就可以直接使用。Spring为什么仅凭一个简单的配置文件,就能神奇的实例化并配置好程序使用的Bean呢?

答案是通过Java的反射技术。

Spring的DI例子

<span style="color:#000000"><code>    我们的service层总是用到dao层,以前我们总是在Service层<span style="color:#000088">new</span>出dao对象,现在我们使用依赖注入
    Service层依赖dao层。

                    UserDao
                        <span style="color:#000088">public</span> <span style="color:#000088">class</span> UserDao {
                            <span style="color:#000088">public</span> <span style="color:#000088">void</span> <span style="color:#009900">add</span>(){
                                System.<span style="color:#000088">out</span>.println(<span style="color:#009900">"dao....."</span>);
                            }
                        }

                    UserService
                        <span style="color:#000088">public</span> <span style="color:#000088">class</span> UserService {
                            UserDao userdao;
                            <span style="color:#000088">public</span> <span style="color:#000088">void</span> <span style="color:#009900">setUserdao</span>(UserDao userdao){
                                <span style="color:#000088">this</span>.userdao=userdao;
                            }

                            <span style="color:#000088">public</span> <span style="color:#000088">void</span> <span style="color:#009900">add</span>(){
                                System.<span style="color:#000088">out</span>.println(<span style="color:#009900">"service......."</span>);
                                userdao.add();
                            }
                        }

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

Spring的资源访问神器

JDK提供的访问资源的类(如java.net.URL,File)等并不能很好很方便的满足各种底层资源的访问需求。Spring设计了一个Resource接口,为应用提供了更强的访问底层资源的能力,该接口拥有对应不同资源类型的实现类。

Resource接口的主要方法

  • boolean exists():资源是否存在
  • boolean isOpen():资源是否打开
  • URL getURL():返回对应资源的URL
  • File getFile():返回对应的文件对象
  • InputStream getInputStream():返回对应资源的输入流

Resource在Spring框架中起着不可或缺的作用,Spring框架使用Resource装载各种资源,包括配置文件资源,国际化属性资源等。

Resource接口的具体实现类

  • ByteArrayResource:二进制数组表示的资源。
  • ClassPathResource:类路径下的资源 ,资源以相对于类路径的 方式表示
  • FileSystemResource:文件系统资源,资源以文件系统路径方式表示,如d:/a/b.txt
  • InputStreamResource:对应一个InputStream的资源
  • ServletContextResource:为访问容器上下文中的资源而设计的类。负责以相对于web应用根目录的路径加载资源。
  • UrlResource:封装了java.net.URL。用户能够访问任何可以通过URL表示的资源,如Http资源,Ftp资源等。

例子

<span style="color:#000000"><code>通过FileSystemResource以文件系统绝对路径的方式进行访问资源 
<span style="color:#000088">public</span> <span style="color:#000088">class</span> Demo {
    <span style="color:#000088">public</span> <span style="color:#000088">static</span> <span style="color:#000088">void</span> <span style="color:#009900">main</span>(String[] args) throws IOException { 
        <span style="color:#880000">//文件绝对路径</span>
        String filepath=<span style="color:#009900">"E:/a.txt"</span>; 
        <span style="color:#880000">//加载文件</span>
        Resource r1=<span style="color:#000088">new</span> FileSystemResource(filepath); 
        System.<span style="color:#000088">out</span>.println(r1.getFilename());
        InputStream <span style="color:#000088">in</span>=r1.getInputStream(); 
        <span style="color:#000088">byte</span>[] b=<span style="color:#000088">new</span> <span style="color:#000088">byte</span>[<span style="color:#006666">1024</span>];
        <span style="color:#000088">int</span> c=<span style="color:#006666">0</span>; 
        <span style="color:#880000">//输出文件内容</span>
        <span style="color:#000088">while</span>((c=<span style="color:#000088">in</span>.read())!=-<span style="color:#006666">1</span>){
            System.<span style="color:#000088">out</span>.println((<span style="color:#000088">char</span>)c);
        }
    }
}</code></span>

为了访问不同类型的资源,必须使用相应的Resource实现类,这是比较麻烦的。Spring提供了一个强大的加载资源的机制,仅通过资源地址的特殊标识就可以加载相应的资源。

首先,我们了解一下Spring支持哪些资源类型的地址前缀

  • classpath: 例如classpath:com/cad/domain/bean.xml。从类路径中加载资源
  • file:例如 file:com/cad/domain/bean.xml.使用UrlResource从文件系统目录中加载资源。
  • http:// 例如http://www.baidu.com/resource/bean.xml 使用UrlResource从web服务器加载资源
  • ftp:// 例如frp://10.22.10.11/bean.xml 使用UrlResource从ftp服务器加载资源

Spring定义一套资源加载的接口。ResourceLoader接口仅有一个getResource(String location)的方法,可以根据资源地址加载文件资源。资源地址仅支持带资源类型前缀的地址,不支持Ant风格的资源路径表达式。ResourcePatternResolver扩展ResourceLoader接口,定义新的接口方法getResources(String locationPattern) ,该方法支持带资源类型前缀以及Ant风格的资源路径的表达式。 
PathMatchingResourcePatternResolver是Spring提供的标准实现类。

BeanFactory和ApplicationContext

  • Spring通过一个配置文件描述Bean与Bean之间的依赖关系,通过Java语言的反射技术能实例化Bean并建立Bean之间的依赖关系。Spring的IoC容器在完成这些底层工作的基础上,还提供了bean实例缓存、生命周期管理、事件发布,资源装载等高级服务。
  • BeanFactory是Spring最核心的接口,提供了高级IoC的配置机制。ApplicationContext建立在BeanFactory的基础上,提供了更多面向应用的功能。我们一般称BeanFactory为IoC容器,ApplicationContext为应用上下文,也称为Spring容器。
  • BeanFactory是Spring框架的基础,面向Spring本身,ApplicationContext面向使用Spring框架的开发者,几乎所有的应用我们都直接使用ApplicationContext而非底层的BeanFactory

BeanFactory介绍

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

BeanFactory是一个接口,Spring为BeanFactory提供了多种实现,最常用的就是XmlBeanFactory。 
BeanFactory接口最主要的方法就是getBean(String beanName),该方法从容器中返回指定名称的Bean。 
BeanFactory接口的功能通过其他实现它的接口不断扩展。

例子:

<span style="color:#000000"><code>我们使用Spring配置文件为User类提供配置信息,然后通过BeanFactory装载配置文件,启动Spring IoC容器。 

<span style="color:#006666"><?xml version="1.0" encoding="UTF-8"?></span>
<span style="color:#006666"><<span style="color:#4f4f4f">beans</span> <span style="color:#4f4f4f">xmlns</span>=<span style="color:#009900">"http://www.springframework.org/schema/beans"</span>
    <span style="color:#4f4f4f">xmlns:xsi</span>=<span style="color:#009900">"http://www.w3.org/2001/XMLSchema-instance"</span>
    <span style="color:#4f4f4f">xsi:schemaLocation</span>=<span style="color:#009900">"
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"</span>></span>

<span style="color:#006666"><<span style="color:#4f4f4f">bean</span> <span style="color:#4f4f4f">id</span>=<span style="color:#009900">"user"</span> <span style="color:#4f4f4f">class</span>=<span style="color:#009900">"com.cad.domain.User"</span>></span><span style="color:#006666"></<span style="color:#4f4f4f">bean</span>></span>   

<span style="color:#006666"></<span style="color:#4f4f4f">beans</span>></span>        </code></span>
<span style="color:#000000"><code>我们通过XmlBeanFactory实现类启动Spring IoC容器 

<span style="color:#000088">public</span> <span style="color:#000088">class</span> Test {

    @org.junit.Test
    <span style="color:#000088">public</span> <span style="color:#000088">void</span> <span style="color:#009900">test</span>(){ 
        <span style="color:#880000">//获取配置文件</span>
        ResourcePatternResolver  resolver=<span style="color:#000088">new</span> PathMatchingResourcePatternResolver(); 
        Resource rs=resolver.getResource(<span style="color:#009900">"classpath:bean.xml"</span>);

        <span style="color:#880000">//加载配置文件并启动IoC容器</span>
        BeanFactory bf=<span style="color:#000088">new</span> XmlBeanFactory(rs);

        <span style="color:#880000">//从容器中获取Bean对象</span>
        User user=(User) bf.getBean(<span style="color:#009900">"user"</span>);

        user.speak();
    }

}</code></span>

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

ApplicationContext介绍

ApplicationContext由BeanFactory派生而来,提供了更多面向实际应用的功能。在BeanFactory中,很多功能需要编程方式来实现,ApplicationContext中可以通过配置的方式来实现

ApplicationContext的主要实现类是ClassPathXmlApplicationContext和FileSystemXmlApplicationContext,前者默认从类路径加载配置文件,后者默认从文件系统中加载配置文件。

<span style="color:#000000"><code>和BeanFactory初始化相似,ApplicationContext初始化也很简单。

ApplicationContext ac=<span style="color:#000088">new</span> ClassPathXmlApplicationContext(<span style="color:#009900">"bean.xml"</span>);</code></span>

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

WebApplicationContext介绍

WebApplicationContext是专门为Web应用准备的,它允许以相对于Web根目录的路径中加载配置文件完成初始化工作。从WebApplicationContext中可以获取ServletContext的引用,整个WebApplicationContext对象作为属性放置到ServletContext中,以便Web应用环境中可以访问Spring应用上下文。

ConfigurableWebApplicationContext扩展了WebApplicationContext,允许通过配置方式实例化WebApplicationContext,定义了两个重要方法。

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

WebApplicationContext的初始化 
在ServletContext对象创建的时候,借助监听器监听ServletContext对象的创建,然后初始化WebApplicationContext对象。Spring提供了这个监听器。ContextLoaderListener。我们只需要在web.xml配置监听器即可。

父子容器

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

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

在IoC容器中装配Bean基于XML

为了让IoC容器帮我们创建和管理对象,我们必须在Spring IoC容器中装配好Bean,并建立好Bean和Bean之间的关联关系。

Spring配置概述

Spring启动时读取应用程序提供的Bean配置信息,并在Spring容器中生成一份相应的Bean配置注册表,然后根据这张注册表实例化Bean,装配好Bean之间的依赖关系。

对于基于XML的配置,Spring2.0以后配置文件使用Schema格式。

我们可以在我们下载的Spring jar包中找到相关Schema文件的配置。

spring-framework-4.3.8.RELEASE-dist\spring-framework-4.3.8.RELEASE\docs\spring-framework-reference\html\ xsd-configuration.html

Bean的基本配置

< bean id=”userdaoid” class=”UserDao”>< /bean > 
id:Bean的名称 
class:指定了Bean对应的实现类

Bean的命名 
一般情况下,配置Bean时需要为其指定一个id属性作为Bean的名称。id在IoC容器中必须是唯一的。id的命名需要满足xml的命名规范:必须以字母开始,后面可以使字母数字、下划线、句号、冒号等符号,逗号和空格等字符是非法的。

< bean>还有一个name属性,和id属性作用一样,但是name几乎可以使用任何字符。

Spring配置文件中不允许出现相同的id,却允许出现相同的name。如果有相同的name,通过getBean(beanName)获取Bean时,将返回最后生命的Bean,原因是最后的Bean覆盖了前面同名的Bean。应该尽量使用id。

Bean的实例化方式

  • 使用默认的无参构造方法实例化
<span style="color:#000000"><code>     创建一个类
      <span style="color:#000088">public</span> <span style="color:#000088">class</span> User{
      }  

    配置xml文件

    <bean id=<span style="color:#009900">"user"</span> class=<span style="color:#009900">"com.cad.domain.User"</span> ></bean>
</code></span>
  • 使用实例工厂方法实例化 
    工厂方法是非静态的,即必须实例化工厂类后才能调用工厂方法。
<span style="color:#000000"><code>
        创建一个工厂类,提供一个普通的方法,返回指定的对象
                <span style="color:#000088">public</span> <span style="color:#000088">class</span> UserFactory {
                    <span style="color:#000088">public</span>  User <span style="color:#009900">getUser</span>(){
                        <span style="color:#000088">return</span> <span style="color:#000088">new</span> User();
                    }
                }
</code></span>
<span style="color:#000000"><code>        配置<span style="color:#4f4f4f">xml</span>文件 

            <span style="color:#880000">//先要实例工厂</span>
            <span style="color:#4f4f4f"><</span>bean id<span style="color:#4f4f4f">=</span><span style="color:#009900">"factory"</span> class<span style="color:#4f4f4f">=</span><span style="color:#009900">"com.cad.domain.UserFactory"</span> <span style="color:#4f4f4f">><</span>/bean<span style="color:#4f4f4f">></span> 
            <span style="color:#880000">//通过实例化工厂调用工厂方法获取对象,factory-bean属性引用工厂实例,factory-method指定工厂方法</span>
            <span style="color:#4f4f4f"><</span>bean id<span style="color:#4f4f4f">=</span><span style="color:#009900">"user"</span> factory-bean<span style="color:#4f4f4f">=</span><span style="color:#009900">"factory"</span> factory-method<span style="color:#4f4f4f">=</span><span style="color:#009900">"getUser"</span><span style="color:#4f4f4f">><</span>/bean<span style="color:#4f4f4f">></span></code></span>
  • 使用静态工厂方法实例化

工厂类方法是静态的,可以不用创建工厂类实例直接使用。

<span style="color:#000000"><code>        创建一个工厂类,提供一个静态方法,返回指定的对象
            <span style="color:#000088">public</span> <span style="color:#000088">class</span> UserFactory {
                <span style="color:#000088">public</span> <span style="color:#000088">static</span> User <span style="color:#009900">getUser</span>(){
                    <span style="color:#000088">return</span> <span style="color:#000088">new</span> User();
                }
            }</code></span>
<span style="color:#000000"><code>配置<span style="color:#4f4f4f">xml</span>文件
        <span style="color:#880000">//class指定工厂类,factory指定工厂方法</span>
        <span style="color:#4f4f4f"><</span>bean id<span style="color:#4f4f4f">=</span><span style="color:#009900">"user"</span> class<span style="color:#4f4f4f">=</span><span style="color:#009900">"com.cad.domain.UserFactory"</span> factory-method<span style="color:#4f4f4f">=</span><span style="color:#009900">"getUser"</span><span style="color:#4f4f4f">><</span>/bean<span style="color:#4f4f4f">></span></code></span>

Bean的属性注入

Spring支持两种依赖注入方式,分别是属性注入和构造方法注入。用户不但可以将String,int等类型参数注入到Bean中,还可以将集合、Map类型注入到Bean中。

  • 属性注入(使用属性的set方法)
<span style="color:#000000"><code>属性注入要求Bean提供一个默认的构造方法,并为需要注入的属性提供对应的<span style="color:#000088">set</span>方法。Spring调Bean的默认构造方法创建对象,然后通过反射的方式调用<span style="color:#000088">set</span>方法注入属性。 

        创建类
        <span style="color:#000088">public</span> <span style="color:#000088">class</span> User {
                <span style="color:#000088">private</span> String username;
                <span style="color:#000088">public</span> <span style="color:#000088">void</span> <span style="color:#009900">setUsername</span>(String username){
                    <span style="color:#000088">this</span>.username=username;
                }
                <span style="color:#000088">public</span> <span style="color:#000088">void</span> <span style="color:#009900">speak</span>(){
                    System.<span style="color:#000088">out</span>.println(<span style="color:#009900">"my name is"</span>+username);
                }
            }

            配置文件
            <bean id=<span style="color:#009900">"user"</span> class=<span style="color:#009900">"com.cad.domain.User"</span>> 
                <!--<property>对应一个属性,name是属性的名称,<span style="color:#000088">value</span>是属性的值,<span style="color:#000088">ref</span>用来引用其他bean-->
                <property name=<span style="color:#009900">"username"</span> <span style="color:#000088">value</span>=<span style="color:#009900">"张三"</span>></property>
            </bean>

</code></span>
  • 使用有参数构造方法注入
<span style="color:#000000"><code>使用构造方法注入前提是Bean必须提供带参的构造方法。 

        创建User类
        <span style="color:#000088">public</span> <span style="color:#000088">class</span> User {
            <span style="color:#000088">private</span> String username;
            <span style="color:#000088">public</span> <span style="color:#009900">User</span>(String username){
                <span style="color:#000088">this</span>.username=username;
            }
            <span style="color:#000088">public</span> <span style="color:#000088">void</span> <span style="color:#009900">speak</span>(){
                System.<span style="color:#000088">out</span>.println(<span style="color:#009900">"my name is"</span>+username);
            }
        }

        配置文件
        <bean id=<span style="color:#009900">"user"</span> class=<span style="color:#009900">"com.cad.domain.User"</span>>
            <!--<constructor-arg>标签对应构造方法的参数,name是参数名称,<span style="color:#000088">value</span>是参数值-->
            <constructor-arg name=<span style="color:#009900">"username"</span> <span style="color:#000088">value</span>=<span style="color:#009900">"jack"</span>></constructor-arg>
        </bean> 


           =============================================================
            这里有一个小问题,如果类中有两个带参构造方法,我们应该怎样注入? 
            <constructor-arg>标签有两个属性 index和type。
            type是指定要注入的属性的类型,index指定注入的属性的顺序,从<span style="color:#006666">0</span>开始。

</code></span>
  • 注入null值
<span style="color:#000000"><code>    如果需要为某个属性注入null值,必须使用专用的<span style="color:#006666"><<span style="color:#4f4f4f">null</span>/></span>标签。

    <span style="color:#006666"><<span style="color:#4f4f4f">bean</span> <span style="color:#4f4f4f">id</span>=<span style="color:#009900">"userdaoid"</span> <span style="color:#4f4f4f">class</span>=<span style="color:#009900">"UserDao"</span>></span> 
        <span style="color:#006666"><<span style="color:#4f4f4f">property</span> <span style="color:#4f4f4f">name</span>=<span style="color:#009900">"username"</span>></span><span style="color:#006666"><<span style="color:#4f4f4f">null</span>/></span><span style="color:#006666"></<span style="color:#4f4f4f">property</span>></span>
    <span style="color:#006666"></<span style="color:#4f4f4f">bean</span>></span></code></span>
  • 注入集合类型

java.util包中的集合类是最常用的数据结构类型。主要包括List、Set、map、Properties等,Spring为这些集合提供了专门的标签来配置。

<span style="color:#000000"><code>        我们创建一个类,包含了各种集合类型 

        <span style="color:#000088">public</span> class CollectionDemo {
            <span style="color:#000088">private</span> <span style="color:#4f4f4f">List</span><span style="color:#4f4f4f"><</span><span style="color:#4f4f4f">String</span><span style="color:#4f4f4f">></span> <span style="color:#4f4f4f">list</span>; 
            <span style="color:#000088">private</span> <span style="color:#4f4f4f">Set</span><span style="color:#4f4f4f"><</span><span style="color:#4f4f4f">String</span><span style="color:#4f4f4f">></span> <span style="color:#4f4f4f">set</span>; 
            <span style="color:#000088">private</span> <span style="color:#4f4f4f">Map</span><span style="color:#4f4f4f"><</span><span style="color:#4f4f4f">String</span>,<span style="color:#4f4f4f">String</span><span style="color:#4f4f4f">></span> <span style="color:#4f4f4f">map</span>; 
            <span style="color:#000088">private</span> Properties properties;
            <span style="color:#000088">public</span> <span style="color:#4f4f4f">List</span><span style="color:#4f4f4f"><</span><span style="color:#4f4f4f">String</span><span style="color:#4f4f4f">></span> getList() {
                <span style="color:#000088">return</span> <span style="color:#4f4f4f">list</span>;
            }
            <span style="color:#000088">public</span> <span style="color:#006666">void</span> setList(<span style="color:#4f4f4f">List</span><span style="color:#4f4f4f"><</span><span style="color:#4f4f4f">String</span><span style="color:#4f4f4f">></span> <span style="color:#4f4f4f">list</span>) {
                this<span style="color:#4f4f4f">.</span><span style="color:#4f4f4f">list</span> <span style="color:#4f4f4f">=</span> <span style="color:#4f4f4f">list</span>;
            }
            <span style="color:#000088">public</span> <span style="color:#4f4f4f">Set</span><span style="color:#4f4f4f"><</span><span style="color:#4f4f4f">String</span><span style="color:#4f4f4f">></span> getSet() {
                <span style="color:#000088">return</span> <span style="color:#4f4f4f">set</span>;
            }
            <span style="color:#000088">public</span> <span style="color:#006666">void</span> setSet(<span style="color:#4f4f4f">Set</span><span style="color:#4f4f4f"><</span><span style="color:#4f4f4f">String</span><span style="color:#4f4f4f">></span> <span style="color:#4f4f4f">set</span>) {
                this<span style="color:#4f4f4f">.</span><span style="color:#4f4f4f">set</span> <span style="color:#4f4f4f">=</span> <span style="color:#4f4f4f">set</span>;
            }
            <span style="color:#000088">public</span> <span style="color:#4f4f4f">Map</span><span style="color:#4f4f4f"><</span><span style="color:#4f4f4f">String</span>, <span style="color:#4f4f4f">String</span><span style="color:#4f4f4f">></span> getMap() {
                <span style="color:#000088">return</span> <span style="color:#4f4f4f">map</span>;
            }
            <span style="color:#000088">public</span> <span style="color:#006666">void</span> setMap(<span style="color:#4f4f4f">Map</span><span style="color:#4f4f4f"><</span><span style="color:#4f4f4f">String</span>, <span style="color:#4f4f4f">String</span><span style="color:#4f4f4f">></span> <span style="color:#4f4f4f">map</span>) {
                this<span style="color:#4f4f4f">.</span><span style="color:#4f4f4f">map</span> <span style="color:#4f4f4f">=</span> <span style="color:#4f4f4f">map</span>;
            }
            <span style="color:#000088">public</span> Properties getProperties() {
                <span style="color:#000088">return</span> properties;
            }
            <span style="color:#000088">public</span> <span style="color:#006666">void</span> setProperties(Properties properties) {
                this<span style="color:#4f4f4f">.</span>properties <span style="color:#4f4f4f">=</span> properties;
            }

            <span style="color:#000088">public</span> <span style="color:#4f4f4f">String</span> toString() {
                <span style="color:#000088">return</span> <span style="color:#009900">"CollectionDemo [list="</span> <span style="color:#4f4f4f">+</span> <span style="color:#4f4f4f">list</span> <span style="color:#4f4f4f">+</span> <span style="color:#009900">", set="</span> <span style="color:#4f4f4f">+</span> <span style="color:#4f4f4f">set</span> <span style="color:#4f4f4f">+</span> <span style="color:#009900">", map="</span> <span style="color:#4f4f4f">+</span> <span style="color:#4f4f4f">map</span> <span style="color:#4f4f4f">+</span> <span style="color:#009900">", properties="</span> <span style="color:#4f4f4f">+</span> properties <span style="color:#4f4f4f">+</span> <span style="color:#009900">"]"</span>;
            } 


        }</code></span>
<span style="color:#000000"><code>        配置文件 

        <span style="color:#006666"><<span style="color:#4f4f4f">bean</span> <span style="color:#4f4f4f">id</span>=<span style="color:#009900">"collid"</span> <span style="color:#4f4f4f">class</span>=<span style="color:#009900">"com.cad.domain.CollectionDemo"</span>></span> 
            <span style="color:#880000"><!--配置list集合--></span>
            <span style="color:#006666"><<span style="color:#4f4f4f">property</span> <span style="color:#4f4f4f">name</span>=<span style="color:#009900">"list"</span>></span>
            <span style="color:#006666"><<span style="color:#4f4f4f">list</span>></span>
                <span style="color:#006666"><<span style="color:#4f4f4f">value</span>></span>张三<span style="color:#006666"></<span style="color:#4f4f4f">value</span>></span>
                <span style="color:#006666"><<span style="color:#4f4f4f">value</span>></span>李四<span style="color:#006666"></<span style="color:#4f4f4f">value</span>></span>
            <span style="color:#006666"></<span style="color:#4f4f4f">list</span>></span> 
            <span style="color:#006666"></<span style="color:#4f4f4f">property</span>></span> 

            <span style="color:#880000"><!--配置set集合--></span>
            <span style="color:#006666"><<span style="color:#4f4f4f">property</span> <span style="color:#4f4f4f">name</span>=<span style="color:#009900">"set"</span>></span>
            <span style="color:#006666"><<span style="color:#4f4f4f">set</span>></span>
                <span style="color:#006666"><<span style="color:#4f4f4f">value</span>></span>java<span style="color:#006666"></<span style="color:#4f4f4f">value</span>></span>
                <span style="color:#006666"><<span style="color:#4f4f4f">value</span>></span>c#<span style="color:#006666"></<span style="color:#4f4f4f">value</span>></span>
            <span style="color:#006666"></<span style="color:#4f4f4f">set</span>></span>
            <span style="color:#006666"></<span style="color:#4f4f4f">property</span>></span> 

            <span style="color:#880000"><!--配置map集合--></span>
            <span style="color:#006666"><<span style="color:#4f4f4f">property</span> <span style="color:#4f4f4f">name</span>=<span style="color:#009900">"map"</span>></span>
            <span style="color:#006666"><<span style="color:#4f4f4f">map</span>></span>
                <span style="color:#006666"><<span style="color:#4f4f4f">entry</span> <span style="color:#4f4f4f">key</span>=<span style="color:#009900">"jack"</span> <span style="color:#4f4f4f">value</span>=<span style="color:#009900">"杰克"</span>></span><span style="color:#006666"></<span style="color:#4f4f4f">entry</span>></span>
                <span style="color:#006666"><<span style="color:#4f4f4f">entry</span> <span style="color:#4f4f4f">key</span>=<span style="color:#009900">"tom"</span>  <span style="color:#4f4f4f">value</span>=<span style="color:#009900">"汤姆"</span>></span><span style="color:#006666"></<span style="color:#4f4f4f">entry</span>></span>
            <span style="color:#006666"></<span style="color:#4f4f4f">map</span>></span>
            <span style="color:#006666"></<span style="color:#4f4f4f">property</span>></span> 

            <span style="color:#880000"><!--配置properties类型--></span>
            <span style="color:#006666"><<span style="color:#4f4f4f">property</span> <span style="color:#4f4f4f">name</span>=<span style="color:#009900">"properties"</span>></span>
            <span style="color:#006666"><<span style="color:#4f4f4f">props</span>></span>
                <span style="color:#006666"><<span style="color:#4f4f4f">prop</span> <span style="color:#4f4f4f">key</span>=<span style="color:#009900">"prop1"</span>></span>prop1<span style="color:#006666"></<span style="color:#4f4f4f">prop</span>></span>
                <span style="color:#006666"><<span style="color:#4f4f4f">prop</span> <span style="color:#4f4f4f">key</span>=<span style="color:#009900">"prop2"</span>></span>prop2<span style="color:#006666"></<span style="color:#4f4f4f">prop</span>></span>
            <span style="color:#006666"></<span style="color:#4f4f4f">props</span>></span>
            <span style="color:#006666"></<span style="color:#4f4f4f">property</span>></span>


        <span style="color:#006666"></<span style="color:#4f4f4f">bean</span>></span>

</code></span>

使用p命名空间

为了简化Xml的配置,Spring引入了一个P命名空间。

  • 未使用P命名空间之前
<span style="color:#000000"><code>        创建一个User类
        <span style="color:#000088">public</span> <span style="color:#000088">class</span> User {
            <span style="color:#000088">private</span> String name;
            <span style="color:#000088">private</span> <span style="color:#000088">int</span> age;
            <span style="color:#000088">public</span> <span style="color:#000088">void</span> <span style="color:#009900">setName</span>(String name) {
                <span style="color:#000088">this</span>.name = name;
            }
            <span style="color:#000088">public</span> <span style="color:#000088">void</span> <span style="color:#009900">setAge</span>(<span style="color:#000088">int</span> age) {
                <span style="color:#000088">this</span>.age = age;
            }
            <span style="color:#000088">public</span> <span style="color:#000088">void</span> <span style="color:#009900">say</span>(){
                System.<span style="color:#000088">out</span>.println(name+<span style="color:#009900">":"</span>+age);
            }

        } 


</code></span>
<span style="color:#000000"><code>    配置文件
    <span style="color:#006666"><?xml version="1.0" encoding="UTF-8"?></span>
    <span style="color:#006666"><<span style="color:#4f4f4f">beans</span> <span style="color:#4f4f4f">xmlns</span>=<span style="color:#009900">"http://www.springframework.org/schema/beans"</span>
        <span style="color:#4f4f4f">xmlns:xsi</span>=<span style="color:#009900">"http://www.w3.org/2001/XMLSchema-instance"</span>
        <span style="color:#4f4f4f">xsi:schemaLocation</span>=<span style="color:#009900">"
            http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"</span>></span>


    <span style="color:#006666"><<span style="color:#4f4f4f">bean</span> <span style="color:#4f4f4f">id</span>=<span style="color:#009900">"user"</span> <span style="color:#4f4f4f">class</span>=<span style="color:#009900">"com.cad.domain.User"</span>></span>
        <span style="color:#006666"><<span style="color:#4f4f4f">property</span> <span style="color:#4f4f4f">name</span>=<span style="color:#009900">"name"</span> <span style="color:#4f4f4f">value</span>=<span style="color:#009900">"张三"</span>></span><span style="color:#006666"></<span style="color:#4f4f4f">property</span>></span>
        <span style="color:#006666"><<span style="color:#4f4f4f">property</span> <span style="color:#4f4f4f">name</span>=<span style="color:#009900">"age"</span> <span style="color:#4f4f4f">value</span>=<span style="color:#009900">"18"</span>></span><span style="color:#006666"></<span style="color:#4f4f4f">property</span>></span>
    <span style="color:#006666"></<span style="color:#4f4f4f">bean</span>></span>

    <span style="color:#006666"></<span style="color:#4f4f4f">beans</span>></span>   </code></span>
  • 使用P命名空间
<span style="color:#000000"><code>    <span style="color:#006666"><?xml version="1.0" encoding="UTF-8"?></span>
    <span style="color:#006666"><<span style="color:#4f4f4f">beans</span> <span style="color:#4f4f4f">xmlns</span>=<span style="color:#009900">"http://www.springframework.org/schema/beans"</span>
        <span style="color:#4f4f4f">xmlns:xsi</span>=<span style="color:#009900">"http://www.w3.org/2001/XMLSchema-instance"</span>
        <span style="color:#4f4f4f">xmlns:p</span>=<span style="color:#009900">"http://www.springframework.org/schema/p"</span>     //声明<span style="color:#4f4f4f">p</span>命名空间
        <span style="color:#4f4f4f">xsi:schemaLocation</span>=<span style="color:#009900">"
            http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"</span>></span>


    <span style="color:#880000"><!--使用p:属性名="xxx" 或者 p:属性名-ref="引用id"来指定属性--></span>
    <span style="color:#006666"><<span style="color:#4f4f4f">bean</span> <span style="color:#4f4f4f">id</span>=<span style="color:#009900">"user"</span> <span style="color:#4f4f4f">class</span>=<span style="color:#009900">"com.cad.domain.User"</span> <span style="color:#4f4f4f">p:name</span>=<span style="color:#009900">"李四"</span> <span style="color:#4f4f4f">p:age</span>=<span style="color:#009900">"88"</span>></span>
    <span style="color:#006666"></<span style="color:#4f4f4f">bean</span>></span>

    <span style="color:#006666"></<span style="color:#4f4f4f">beans</span>></span>   </code></span>

Bean的作用域

Bean的作用域会对Bean的生命周期和创建方式产生影响。

spring的关键技术 spring技术体系_User_02

<span style="color:#000000"><code>我们来演示一下,将User类的作用域设置为singleton
<bean id=<span style="color:#009900">"user"</span> class=<span style="color:#009900">"com.cad.domain.User"</span> p:name=<span style="color:#009900">"李四"</span> p:age=<span style="color:#009900">"88"</span> scope=<span style="color:#009900">"singleton"</span>>
</bean>  


public class Test {

    @org<span style="color:#009900">.junit</span><span style="color:#009900">.Test</span>
    public void test(){
        ApplicationContext ac=new ClassPathXmlApplicationContext(<span style="color:#009900">"bean.xml"</span>)<span style="color:#880000">;</span>
        User user1=(User) ac<span style="color:#009900">.getBean</span>(<span style="color:#009900">"user"</span>)<span style="color:#880000">;  //获得的两个对象是一样的</span>
        User user2=(User) ac<span style="color:#009900">.getBean</span>(<span style="color:#009900">"user"</span>)<span style="color:#880000">; </span>
        System<span style="color:#009900">.out</span><span style="color:#009900">.println</span>(user1)<span style="color:#880000">;</span>
        System<span style="color:#009900">.out</span><span style="color:#009900">.println</span>(user2)<span style="color:#880000">;</span>
    }

} 

输出 
<span style="color:#000088">com</span><span style="color:#009900">.cad</span><span style="color:#009900">.domain</span><span style="color:#009900">.User</span>@1c3a4799
<span style="color:#000088">com</span><span style="color:#009900">.cad</span><span style="color:#009900">.domain</span><span style="color:#009900">.User</span>@1c3a4799</code></span>
<span style="color:#000000"><code>将User的作用域设置为多例
<bean id=<span style="color:#009900">"user"</span> class=<span style="color:#009900">"com.cad.domain.User"</span> p:name=<span style="color:#009900">"李四"</span> p:age=<span style="color:#009900">"88"</span> scope=<span style="color:#009900">"prototype"</span>>
</bean> 


输出 
<span style="color:#000088">com</span><span style="color:#009900">.cad</span><span style="color:#009900">.domain</span><span style="color:#009900">.User</span>@5d76b067
<span style="color:#000088">com</span><span style="color:#009900">.cad</span><span style="color:#009900">.domain</span><span style="color:#009900">.User</span>@2a17b7b6</code></span>

FactoryBean

我们前面的< bean >都是普通bean,Spring利用反射机制通过bean的class属性来实例化Bean。 
如果有的Bean属性特别多,我们就需要编写大量的配置信息。Spring提供了一个FactoryBean< T >接口。 
我们可以通过实现该接口来返回特定的Bean。 
该接口定义了三个方法

  • T getObject():返回由FactoryBean创建的Bean实例。
  • boolean isSingleton():确定创建的Bean的作用域是singleton还是prototype
  • Class< ? > getObjectType():返回FactoryBean创建Bean的类型
<span style="color:#000000"><code>        我们创建一个类实现FactoryBean接口 

        <span style="color:#000088">public</span> <span style="color:#000088">class</span> <span style="color:#4f4f4f">UserFactory</span> <span style="color:#000088">implements</span> <span style="color:#4f4f4f">FactoryBean</span><<span style="color:#4f4f4f">User</span>> {

           <span style="color:#880000">//返回对象</span>
            <span style="color:#000088">public</span> User getObject() throws Exception {
                User user=<span style="color:#000088">new</span> User();
                user.setAge(<span style="color:#006666">14</span>);
                user.setName(<span style="color:#009900">"tom"</span>);
                <span style="color:#000088">return</span> user;
            }

            <span style="color:#880000">//返回bean的类型</span>
            <span style="color:#000088">public</span> Class<User> getObjectType() {

                <span style="color:#000088">return</span> User.class;
            }

            <span style="color:#000088">public</span> <span style="color:#000088">boolean</span> isSingleton() {
                <span style="color:#880000">// TODO Auto-generated method stub</span>
                <span style="color:#000088">return</span> <span style="color:#000088">false</span>;
            }

        }</code></span>
<span style="color:#000000"><code>配置 
<span style="color:#006666"><<span style="color:#4f4f4f">bean</span> <span style="color:#4f4f4f">id</span>=<span style="color:#009900">"userfactory"</span> <span style="color:#4f4f4f">class</span>=<span style="color:#009900">"com.cad.domain.UserFactory"</span>></span><span style="color:#006666"></<span style="color:#4f4f4f">bean</span>></span></code></span>
<span style="color:#000000"><code>测试 
<span style="color:#000088">public</span> <span style="color:#000088">class</span> Test {

    @org.junit.Test
    <span style="color:#000088">public</span> <span style="color:#000088">void</span> <span style="color:#009900">test</span>(){
        ApplicationContext ac=<span style="color:#000088">new</span> ClassPathXmlApplicationContext(<span style="color:#009900">"bean.xml"</span>);
        User user=(User) ac.getBean(<span style="color:#009900">"userfactory"</span>); 
        user.say();
    }

}  

输出 tom:<span style="color:#006666">14</span> 

</code></span>

当我们< bean >标签的class属性配置的类实现了FactoryBean接口时,通过getBean返回的就不是该类本身,而是getObject()方法所返回的对象,相当于getObject()方法代理了getBean().

Bean的生命周期

spring的关键技术 spring技术体系_AOP_03

spring的关键技术 spring技术体系_User_04

步骤如下

  1. 实例化BeanFactoryPostProcessor,调用postProcessBeanFactory()方法对工厂定义信息进行后处理。
  2. 调用者通过getBean向容器请求bean时,如果容器注册了InstantiationAwareBeanPostProcessor接口,在实例化Bean之前,会调用接口的postProcessBeforeInstantiation()方法。
  3. 根据配置文件调用Bean的构造方法或者工厂方法实例化Bean。
  4. 实例化Bean后,调用InstantiationAwareBeanPostProcessor接口的postProcessAfterInstantiation()方法,在这里可以对已经实例化的对象进行一些修饰。
  5. 如果Bean配置了属性信息,在设置每个属性之前将先调用InstantiationAwareBeanPostProcessor的postProcessPropertyValues()方法。
  6. 调用Bean的属性设置方法为Bean设置属性。
  7. 如果Bean实现了BeanNameAware接口,会调用该接口的setBeanName()方法,将配置文件中该Bean对应的名称设置到Bean中。
  8. 如果Bean实现了BeanFactoryAware接口,会调用该接口的setBeanFactory方法,将BeanFactory容器实例设置到Bean中。
  9. 如果BeanFactory装配了BeanPostProcessor后处理器,将调用Object postProcessBeforeInitialization(Object bean,String beanName)方法对Bean进行加工操作,bean是当前处理的Bean,beanName是当前bean的配置名,返回的对象是加工处理后的Bean。用户可以使用该方法对Bean进行特殊处理。BeanPostProcessor在Spring框架中占有重要地位,AOP等都通过该BeanPostProcessor实施。
  10. 如果Bean实现了InitializingBean接口,会调用该接口的afterPropertiesSet()方法。
  11. 如果< bean >中配置了init-method属性,执行指定的初始化方法。
  12. 调用BeanPostProcessor后处理器的Object postProcessAfterInitialization(Object bean,String beanName)方法再次获得对Bean的加工处理机会。
  13. 将Bean返回给调用者。
  14. 当容器关闭时, 如果Bean实现了DisposableBean接口,调用接口的destory方法。
  15. 如果< bean >设置了destory-method属性,执行指定的销毁方法。

生命周期中方法的划分

Bean的完整生命周期从Spring容器着手实例化bean开始,直到销毁Bean。其中有很多关键的方法。 
这些方法大致分为三类

  • Bean自身的方法:如Bean的构造方法,调用set方法设置属性,和init-method和destory-method指定的方法。
  • Bean的生命周期接口方法:如BeanNameAware、BeanFactoryAware、InitializingBean、DisposableBean等接口的方法由Bean自己直接实现
  • 容器级生命周期接口方法:如InstantiationAwareBeanPostProcessor和BeanPostProcessor接口,一般称为后处理器。这些接口的实现类与Bean无关,直接装配到Spring容器中。当Spring容器创建任何Bean时,这些后处理器都会起作用。

测试Bean生命周期的例子

<span style="color:#000000"><code><span style="color:#880000">//实现Bean级生命周期接口</span>
<span style="color:#000088">public</span> <span style="color:#000088">class</span> <span style="color:#4f4f4f">User</span> <span style="color:#000088">implements</span> <span style="color:#4f4f4f">BeanFactoryAware</span>,<span style="color:#4f4f4f">BeanNameAware</span>,<span style="color:#4f4f4f">InitializingBean</span>,<span style="color:#4f4f4f">DisposableBean</span>{
    <span style="color:#000088">private</span> String name;
    <span style="color:#000088">private</span> <span style="color:#000088">int</span> age;


    <span style="color:#000088">public</span> <span style="color:#000088">void</span> <span style="color:#009900">setName</span>(String name) {
        <span style="color:#000088">this</span>.name = name;
    }


    <span style="color:#000088">public</span> <span style="color:#000088">void</span> <span style="color:#009900">setAge</span>(<span style="color:#000088">int</span> age) {
        <span style="color:#000088">this</span>.age = age;
    }


    <span style="color:#000088">public</span> <span style="color:#000088">void</span> <span style="color:#009900">myinit</span>(){
        System.out.println(<span style="color:#009900">"初始化..."</span>); 
        name=<span style="color:#009900">"王五"</span>;
        age=<span style="color:#006666">55</span>;
    }   
    <span style="color:#000088">public</span> <span style="color:#000088">void</span> <span style="color:#009900">say</span>(){
        System.out.println(name+<span style="color:#009900">":"</span>+age);
    }

    <span style="color:#000088">public</span> <span style="color:#000088">void</span> <span style="color:#009900">mydestory</span>(){
        System.out.println(<span style="color:#009900">"销毁中..."</span>);
    }


    <span style="color:#000088">public</span> <span style="color:#000088">void</span> <span style="color:#009900">destroy</span>() <span style="color:#000088">throws</span> Exception {
        System.out.println(<span style="color:#009900">"听说我是最后被调用"</span>);

    }



    <span style="color:#000088">public</span> <span style="color:#000088">void</span> <span style="color:#009900">afterPropertiesSet</span>() <span style="color:#000088">throws</span> Exception {
        System.out.println(<span style="color:#009900">"听说我是第三个被调用"</span>);

    }



    <span style="color:#000088">public</span> <span style="color:#000088">void</span> <span style="color:#009900">setBeanName</span>(String arg0) {
        System.out.println(<span style="color:#009900">"听说我是第一个被调用"</span>);

    }

    <span style="color:#000088">public</span> <span style="color:#000088">void</span> <span style="color:#009900">setBeanFactory</span>(BeanFactory arg0) <span style="color:#000088">throws</span> BeansException {
        System.out.println(<span style="color:#009900">"听说我是第二个被调用"</span>);

    }
}</code></span>
<span style="color:#000000"><code><span style="color:#880000"><!--我们在配置时配置init-method和destory-method属性来指定初始化和销毁的方法--></span>
<span style="color:#006666"><<span style="color:#4f4f4f">bean</span> <span style="color:#4f4f4f">id</span>=<span style="color:#009900">"user"</span> <span style="color:#4f4f4f">class</span>=<span style="color:#009900">"com.cad.domain.User"</span> <span style="color:#4f4f4f">init-method</span>=<span style="color:#009900">"myinit"</span> <span style="color:#4f4f4f">destroy-method</span>=<span style="color:#009900">"mydestory"</span>></span><span style="color:#006666"></<span style="color:#4f4f4f">bean</span>></span> </code></span>
<span style="color:#000000"><code>     我们进行测试
        <span style="color:#000088">public</span> <span style="color:#000088">class</span> Test {

            @org.junit.Test
            <span style="color:#000088">public</span> <span style="color:#000088">void</span> <span style="color:#009900">test</span>(){
                ClassPathXmlApplicationContext ac=<span style="color:#000088">new</span> ClassPathXmlApplicationContext(<span style="color:#009900">"bean.xml"</span>);
                User user=(User) ac.getBean(<span style="color:#009900">"user"</span>);  
                user.say();
                <span style="color:#880000">//destory方法执行必须在容器关闭之后才能执行</span>
                ac.close();
            }

        } 

</code></span>

输出结果

spring的关键技术 spring技术体系_spring的关键技术_05

装配后处理器

<span style="color:#000000"><code><span style="color:#880000">//提供BeanPostProcessor的实现类</span>
<span style="color:#000088">public</span> <span style="color:#000088">class</span> <span style="color:#4f4f4f">MyBeanPostProcessor</span> <span style="color:#000088">implements</span> <span style="color:#4f4f4f">BeanPostProcessor</span> {


    <span style="color:#000088">public</span> Object <span style="color:#009900">postProcessAfterInitialization</span>(Object arg0, String arg1) <span style="color:#000088">throws</span> BeansException {
        System.out.println(<span style="color:#009900">"后处理器:初始化方法之后执行"</span>);
        <span style="color:#000088">return</span> arg0;
    }


    <span style="color:#000088">public</span> Object <span style="color:#009900">postProcessBeforeInitialization</span>(Object arg0, String arg1) <span style="color:#000088">throws</span> BeansException {
        System.out.println(<span style="color:#009900">"后处理器:初始化方法之前执行"</span>);
        <span style="color:#000088">return</span> arg0;
    }

}</code></span>
<span style="color:#000000"><code><span style="color:#880000"><!--在配置文件中装配后处理器--></span>
<span style="color:#006666"><<span style="color:#4f4f4f">bean</span> <span style="color:#4f4f4f">id</span>=<span style="color:#009900">"myBeanPostProcessor"</span> <span style="color:#4f4f4f">class</span>=<span style="color:#009900">"com.cad.domain.MyBeanPostProcessor"</span>></span><span style="color:#006666"></<span style="color:#4f4f4f">bean</span>></span> </code></span>
<span style="color:#000000"><code>        测试一下 

        <span style="color:#000088">public</span> <span style="color:#000088">class</span> Test {

            @org.junit.Test
            <span style="color:#000088">public</span> <span style="color:#000088">void</span> <span style="color:#009900">test</span>(){
                ClassPathXmlApplicationContext ac=<span style="color:#000088">new</span> ClassPathXmlApplicationContext(<span style="color:#009900">"bean.xml"</span>);
                User user=(User) ac.getBean(<span style="color:#009900">"user"</span>); 

                ac.close();
            }

        }</code></span>



spring的关键技术 spring技术体系_User_06

仔细观察输出结果,就会发现验证了我们说的Bean的生命周期过程。

关于Bean生命周期接口的一些问题

通过实现Bean的生命周期接口对Bean进行额外的一些控制,虽然具有一些优点,但是带来了一个很严重的问题,我们的类必须实现这些接口,Bean和Spring紧密的结合在了一起,这就带来了很大的麻烦。

所以我们一般不使用这些接口,而是通过< bean >的init-method和destory-method属性来达到我们的初始化和销毁效果,达到框架解耦的问题。

但是BeanPostProcessor接口是像插件一样注册到Spring容器中,使应用与框架解耦,同时可以为我们完成一些额外的功能。例如可以获取动态代理,还有实现AOP功能。