作者:禅楼望月(http://www.cnblogs.com/yaoyinglong

Spring是Web框架,是容器框架,用于配置bean,并维护bean之间的关系的框架。

1. Spring在整个项目层次中的位置:

2. 快速入门

1、引入spring开发包(最小配置)如下:

2、创建spring的一个核心文件(如struts中的struts-config.xml)applicationContext.xml文件。该文件一般放在src目录下,该文件需引入xsd文件:可以从下载下来的开发包中的例子中粘贴过来。

上面我们看了配置单个bean的做法,但是当两个bean之间是嵌套的(就像某人有一只狗),该怎么设置呢?

3. 细节讨论

使用spring ,没有new对象,我们把创建对象的任务交给spring框架

spring的运行原理图:

spring开发提倡接口编程,配合di技术可以层与层的解耦

现在我们体验一下spring的di配合接口编程

例:

建立一个用户验证接口,使用两种不同的验证方法。两种不同的验证方法都继承用户验证接口:

4. bean工厂容器

可以从ApplicationContext 应用上下文容器中获取bean也可以从BeanFactory中获取bean。那他们有什么区别呢?

当从ApplicationContext 中取bean时,是这样的:

怎么验证呢?很简单,因为它是利用反射机制来实现的,所以在实例化对象时会调用该bean的默认构造函数:

在该bean中加入默认构造函数:

执行该语句时:

假如我们有需求:用我们自己的构造函数来实例化这个bean。该怎么办呢?→在该bean的配置中添加<constructor-arg>标签(通过构造函数来注入值)


注意:

当从BeanFactory中获取bean时:

当我们开始使用bean时:

由此可见:

1.如果使用ApplicationContext ,并且配置的bean如果是 singlton(默认),不管你用不用,都被实例化.(好处就是可以预先加载,缺点就是耗内存)

2.如果是 BeanFactory ,则当你获取beanfacotry时候,配置的bean不会被马上实例化,当你使用的时候,才被实例(好处节约内存,缺点就是速度)

3.规定: 一般没有特殊要求,应当使用ApplicatioContext完成(90%)

5. ApplicationContext 对象有3种应用方法

1. ClassPathXmlApplicationContext -> 通过类路径

2. FileSystemXmlApplicationContext -> 通过文件路径

举例:

ApplicationContext ac=new FileSystemXmlApplicationContext("文件路径beans.xml / applicationContext.xml");

3. XmlWebApplicationContext

6. bean生命周期

6.1 利用ApplicationContext获取bean时,bean的生命周期

① 实例化(当我们的程序加载beans.xml文件),把我们的bean(前提是scope=singleton)实例化到内存

② 调用set方法设置属性

③ 如果你实现了bean名字关注接口(BeanNameAware) 则,可以通过setBeanName获取Bean的id属性值

④ 如果你实现了bean工厂关注接口(BeanFactoryAware),则可以获取BeanFactory

⑤ 如果你实现了 ApplicationContextAware接口,则调用方法

//该方法传递ApplicationContext

public void setApplicationContext(ApplicationContext arg0) throws BeansException {

System.out.println("setApplicationContext"+arg0);

}

⑥ 如果bean 和 一个BeanPostProcessor(前置处理器)关联,则会自动去调用 Object postProcessBeforeInitialization方法

⑦ 如果你实现InitializingBean 接口,则会调用 afterPropertiesSet

⑧ 如果自己在<bean init-method=”init”/> 则可以在bean定义自己的初始化方法.


public class Chinese implements InitializingBean {
    private String name;
    private int age;  
    public void setName(String name) {
        System.out.println("正在设置name属性……");
        this.name = name;
    }
    public void setAge(int age) {
        System.out.println("正在设置age属性……");
        this.age = age;
    }
 
 
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("在执行我之前,该Bean 实例已创建,并且通过setter方法将所有属性都设置完毕");
    }
    public void init(){
        System.out.println("我的功能和InitializingBean接口一样");
    }

}


配置:


<bean id="chinese" class="smzq.Chinese" init-method="init">
    <property name="name" value="小明"/>
    <property name="age" value="23"/>
</bean>

测试:
 

通过实例我们可以看出,在同时配置了init-method属性和实现了InitializingBean接口,会先执行接口方法然后执行init-method属性配置的方法。使用init-method属性配置时,类依旧是普通的Java类,没有受到污染。
在实际开发中使用其中的任何一个就可以,但这里推荐使用init-method属性。

⑨ 如果bean 和 一个BeanPostProcessor(后置处理器)关联,则会自动去调用 Object postProcessAfterInitialization方法

⑩ 使用我们的bean

11. 容器关闭

12. 可以通过实现DisposableBean 接口来调用方法 destory

13. 可以在<bean destory-method=”fun1”/> 调用定制的销毁方法

12和13的使用和7、8一样。

记住他们的顺序。

小结: 我们实际开发中往往,没有用的这么的过程,常见的是:

1->2->6->10->9->11

6.2 利用BeanFactory获取bean时,bean的生命周期

只经历了以下的接口:

BeanNameAware,BeanFactoryAware,InitializingBean和自己配置的init-method方法。

7. 配置bean的细节

7.1 scope 的说明

singleton(默认):在整个Spring Ioc容器中,使用 scope="singleton" 的bean将只有一个实例。

prototype:每次通过容器的getBean方法获取scope="prototype"的bean时,都将产生一个新的bean实例。

request:每次HTTP请求,使用 scope=" request" 的bean都将产生一个新的bean实例。

session:对于每个HttpSession,使用 scope=" session" 的bean都将产生一个新的bean实例。

global session:每个全局的HttpSession对应一个Bean实例。

☞ 尽量使用 scope=”singleton” ,不要使用prototype,因为这样对我们的性能影响较大.

对有状态的bean应该使用prototype作用域,而对无状态的bean则应该使用singleton作用域。

注意

Spring不能对一个prototype bean的整个生命周期负责。程序每次请求该bean,Spring都会创建一个新的Bean实例,然后交给程序,然后就对该Bean实例不闻不问了。这就意味着,任何配置好的析构生命周期回调方法都将不会被调用。清除prototype作用域的对象并释放任何prototype bean所持有的昂贵资源,都是客户端代码的职责。(让Spring容器释放被prototype作用域bean占用资源的一种可行方式是,通过使用bean的后置处理器,该处理器持有要被清除的bean的引用。)

7.2 给集合类型注入值

①给List注入值:

②给数组注入值

和List一样。

③给set注入值

④向Map注入值

⑤向属性集合注入

7.3 集合的合并

子集合的值是从其父集合中继承和覆盖而来的。

集合合并只能在spring2.0以后使用并且不同集合是不能合并的。

7.4 强类型集合

在Java5以后才能使用。

public class Foo {
                   private Map<String, Float> accounts;
        public void setAccounts(Map<String, Float> accounts) {
        this.accounts = accounts;
    }
}
<beans>
    <bean id="foo" class="x.y.Foo">
        <property name="accounts">
            <map>
                <entry key="one" value="9.99"/>
                <entry key="two" value="2.75"/>
                <entry key="six" value="3.99"/>
            </map>
        </property>
    </bean>
</beans>

7.5 嵌套Bean

如果某个Bean依赖的Bean不想被Spring容器直接访问,可以使用嵌套bean。

<bean id="date" class="date.Date_">
    <property name="year">
        <bean class="date.Year_">
            <property name="data" value="2015"/>
        </bean>
    </property>
    <property name="month">
        <bean class="date.Month_">
            <property name="data" value="2"/>
        </bean>
    </property>
    <property name="day">
        <bean class="date.Day_">
            <property name="data" value="7"/>
        </bean>
    </property>
</bean>

这样,内部的Bean不能被Spring容器访问,因此不用担心其他程序 修改嵌套的Bean,提高了程序的内聚性,但降低了程序的灵活性。因此只有确定某个Bean实例无需通过Spring容器来访问时,才考虑使用嵌套Bean。

7.6 组合属性注入

public class Date_ {
    private Year_ year=new Year_();
    public Year_ getYear() {
        return year;
    }
    public void setYear(Year_ year) {
        this.year = year;
    }
}
<bean id="next" class="date.Date_">
    <property name="year.data" value="2015"/>
</bean>

7.7 使用抽象Bean

设置属性abstract="true"的Bean是抽象Bean,容器不会创建抽象Bean的实例,也因此,抽象Bean可以没有class属性。


<bean id=" dateTemplate  " abstract="true">

    <!-- 定义依赖注入的属性 -->
    <property name="month" ref="month"/>

</bean>


它主要是用来被继承的。

7.8 使用子Bean

7.8.1 继承自抽象Bean

当我们有大量的Bean要配置到Spring的配置文件中,而这些Bean的大部分配置信息都完全一样,只有少量的信息不一样,这时使用Bean继承是一个很好的办法:

将大部分相同信息配置为Bean模板(抽象Bean)后,将实际的Bean实例配置成为该Bean模板的子Bean即可。

子Bean无法从父Bean继承如下属性:depends-on、autowire、scope、lazy-init,这些属性总是从子Bean中获得,或者采用默认值。子Bean配置可以增加新的配置信息,当子Bean指定的配置信息与父Bean模板信息不一致时,子Bean所制定的配置信息将覆盖父Bean指定的配置信息。


<bean id="month" class="date.Month_">
    <property name="data" value="12"/>
</bean>
<bean id="day" class="date.Day_">
    <property name="data" value="23"/>
</bean>
<bean id="dateTemplate" abstract="true">
    <!-- 定义依赖注入的属性 -->
    <property name="month" ref="month"/>
    <property name="day" ref="day"/>
</bean>
 
<bean id="date" class="date.Date_" parent="dateTemplate">
    <property name="year">
        <bean class="date.Year_">
            <property name="data" value="2015"/>
        </bean>
    </property>

</bean>


如果父Bean配置中有class属性,则子Bean在和父Bean类相同的情况下可以省略掉class属性:


<bean id="dateTemplate" abstract="true" class="date.Date_">
        <!-- 定义依赖注入的属性 -->
        <property name="month" ref="month"/>
        <property name="day" ref="day"/>
    </bean>
   
    <bean id="date" parent="dateTemplate">
        <property name="year">
            <bean class="date.Year_">
                <property name="data" value="2015"/>
            </bean>
        </property>

</bean>


注意,继承自抽象Bean继承只是为了配置参数的复用,并且子Bean的类型不必与抽象Bean的类型(配置了的话)一样。

7.8.2 继承实例bean

这种继承与Java语言的继承一样。

7.9 容器中的工厂Bean

实现了FactoryBean接口的Bean成为工厂Bean,并且该Bean只能做为工厂Bean来使用。


public class PersonFactory implements FactoryBean<Person> {
    private Person person=null;
    @Override
    //返回工厂Bean生成的Java实例
    public Person getObject() throws Exception {
        return person==null? person=new Person():person;
    }
    @Override
    //返回该工厂Bean能生成那种类型的实例
    public Class<? extends Person> getObjectType() {
        return Person.class;
    }
    @Override
    //该工厂Bean所生成的Java实例是否是单例模式
    public boolean isSingleton() {
        return true;
    }

}


配置,和普通bean的配置完全一样:


<bean id="briton" class="factoryBean.PersonFactory"/>


测试:


public static void main(String[] args) throws BeansException, Exception {   
    ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml");
    //虽然请求的FactoryBean的id,但是返回来的却是有FactoryBean生成的实例,而非FactoryBean本身
    Person p1=ctx.getBean("briton", Person.class);
    p1.setName("Tom");p1.setAge(20);
    p1.say();
    Person p2=ctx.getBean("briton", Person.class);
    System.out.println(p1==p2);
    //如需获取FactoryBean本身,指引在bean的id前加上&
    ((PersonFactory)ctx.getBean("&briton")).getObject().say();   

}


由此可见,工厂Bean已经无法作为正常的Bean使用了,客户端请求该工厂Bean的id时,得到是工厂Bean的产品(上面是一个Person)而非工厂Bean的本身。

7.10 获得Bean本身的Id

在前面的程序中,程序总是通过Bean的id从BeanFactory中获取Bean实例。但是现在的需求是,我已经知道了Bean,需要知道配置该Bean时指定的id属性。

BeanNameAware接口提供了setBeanName方法来获取部署在Spring配置文件中的Bean。


public class Chinese implements BeanNameAware {
 
    //保存部署该Bean时指定的id属性
    private String beanName;
    @Override
    public void setBeanName(String beanName) {
        this.beanName=beanName;
    }
    public void info(){
        System.out.println("Chinese 实现类,部署该Bean时指定的id为"+beanName);
    }

}


配置Bean:


<bean id="chinese" class="beanNameAware.Chinese"/>


获取Bean:


public static void main(String[] args) throws BeansException, Exception {   
    ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml");
    Chinese ch=ctx.getBean("chinese", Chinese.class);
    ch.info();

}


从程序中我们看到,和获取、使用普通Bean没有任何区别。从程序执行来看,Spring在实例化该Bean的时候,也调用了该Bean的setBeanName方法。

7.11 depengs-on

该属性用于指定当前bean初始化之前或销毁之前需要强制初始化的bean。该属性只对singleton bean有效。指定多个bean是,多个bean之间可以用逗号,空格,分号来分开。

8. Spring中的Null值

在spring中空值和<null/>是不一样的。

9. XML配置文件的简写

①<property>、<constructor-arg>、<entry>都支持value属性,尽量使用。

②ref也可以是属性。

③使用p命名空间配置属性

xmlns:p="http://www.springframework.org/schema/p"

10. 自动装配bean的属性值

可以通过元素<beans>的default-autowire属性指定,也可以通过<bean>元素的autowire属性

①byName

②byType

寻找和属性的类型相同的bean,找不到,装不上;找到多个,出现异常。

③constructor

④autodetect

再如:

⑤no

不自动装配

11. 分散配置

有两种方法:

PropertyPlaceholderConfigurer是个bean工厂后置处理器的实现,可以将BeanFactory定义中的一些属性值放到另一个单独的标准Java Properties文件中。这就允许用户在部署应用时只需要在属性文件中对一些关键属性(例如数据库URL,用户名和密码)进行修改,而不用对主XML定义文件或容器所用文件进行复杂和危险的修改。

考虑下面的XML配置元数据定义,它用占位符定义了DataSource。我们在外部的Properties文件中配置一些相关的属性。在运行时,我们为元数据提供一个PropertyPlaceholderConfigurer,它将会替换dataSource的属性值。

 <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
  <property name="locations">
  <value>classpath:com/foo/jdbc.properties</value>
  </property>
 </bean>
 <bean id="dataSource" destroy-method="close"
  class="org.apache.commons.dbcp.BasicDataSource">
  <property name="driverClassName" value="${jdbc.driverClassName}"/>
  <property name="url" value="${jdbc.url}"/>
  <property name="username" value="${jdbc.username}"/>
  <property name="password" value="${jdbc.password}"/>
 </bean>

实际的值来自于另一个标准Java Properties格式的文件:

jdbc.driverClassName=org.hsqldb.jdbcDriver

jdbc.url=jdbc:hsqldb:hsql://production:9002

jdbc.username=sa

jdbc.password=root

②使用<context:property-placeholder

但是使用这个的时候必须将命名空间引进来,如下所示:

 <beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:context="http://www.springframework.org/schema/context"
  xsi:schemaLocation="http://www.springframework.org/schema/beans
  http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
  http://www.springframework.org/schema/context
  http://www.springframework.org/schema/context/spring-context-2.5.xsd">

这样我们的bean配置文件就会很简单

在Spring 2.5中,context名字空间可能采用单一元素属性占位符的方式(多个路径提供一个逗号分隔的列表)

<context:property-placeholder location="classpath:com/foo/jdbc.properties"/>

PropertyPlaceholderConfigurer如果在指定的Properties文件中找不到你想使用的属性,它还会在Java的System类属性中查找。这个行为可以通过设置systemPropertiesMode属性来定制,它有三个值:让配置一直覆盖、让它永不覆盖及让它仅仅在属性文件中找不到该属性时才覆盖。请参考PropertiesPlaceholderConfigurer的JavaDoc以获得更多的信息。

Spring应用教程-1的更多相关文章

  1. Spring应用教程-3 依赖关系配置

    注:组件与组件之间的耦合,采用依赖注入管理,但普通的JavaBean属性值,应直接在代码中设置. 1. 注入其他Bean的属性值 我们分析一下,Bean_A的一个属性要依赖Bean_B的一个属性值.这 ...

  2. Spring MVC 教程,快速入门,深入分析

    http://elf8848.iteye.com/blog/875830/ Spring MVC 教程,快速入门,深入分析 博客分类: SPRING Spring MVC 教程快速入门  资源下载: ...

  3. 程序员DD 《Spring boot教程系列》补充

    最近在跟着程序员DD的Spring boot教程系列学习Spring boot,由于年代原因,Spring boot已经发生了一些变化,所以在这里进行一些补充. 补充的知识大多来自评论区,百度,Sta ...

  4. 狗鱼IT教程:推介最强最全的Spring系列教程

    Spring是一个开源框架,Spring是于2003 年兴起的一个轻量级的Java 开发框架,由Rod Johnson创建. 简单来说,Spring是一个分层的JavaSE/EEfull-stack( ...

  5. Spring 官方教程:使用 Restdocs 创建 API 文档

    https://mp.weixin.qq.com/s?__biz=MzU0MDEwMjgwNA==&mid=2247483998&idx=1&sn=6ae5fa795d36b1 ...

  6. Spring 系列教程之容器的功能

    Spring 系列教程之容器的功能 经过前面几章的分析,相信大家已经对 Spring 中的容器功能有了简单的了解,在前面的章节中我们一直以 BeanFacotry 接口以及它的默认实现类 XmlBea ...

  7. Spring 系列教程之自定义标签的解析

    Spring 系列教程之自定义标签的解析 在之前的章节中,我们提到了在 Spring 中存在默认标签与自定义标签两种,而在上一章节中我们分析了 Spring 中对默认标签的解析过程,相信大家一定已经有 ...

  8. Spring 系列教程之默认标签的解析

    Spring 系列教程之默认标签的解析 之前提到过 Spring 中的标签包括默认标签和自定义标签两种,而两种标签的用法以及解析方式存在着很大的不同,本章节重点带领读者详细分析默认标签的解析过程. 默 ...

  9. Spring Security教程(五):自定义过滤器从数据库从获取资源信息

    在之前的几篇security教程中,资源和所对应的权限都是在xml中进行配置的,也就在http标签中配置intercept-url,试想要是配置的对象不多,那还好,但是平常实际开发中都往往是非常多的资 ...

  10. Spring Security教程(八):用户认证流程源码详解

    本篇文章主要围绕下面几个问题来深入源码: 用户认证流程 认证结果如何在多个请求之间共享 获取认证用户信息 一.用户认证流程 上节中提到Spring Security核心就是一系列的过滤器链,当一个请求 ...

随机推荐

  1. 转:LIRe 源代码分析

    1:整体结构 LIRE(Lucene Image REtrieval)提供一种的简单方式来创建基于图像特性的Lucene索引.利用该索引就能够构建一个基于内容的图像检索(content- based ...

  2. HashMap工作原理(转载)

    转载自:http://www.importnew.com/7099.html  HashMap的工作原理是近年来常见的Java面试题.几乎每个Java程序员都知道HashMap,都知道哪里要用Hash ...

  3. 【转】Xcode概览(Xcode 6版):循序渐进认识Xcode

    该系列文章翻译自苹果的Xcode Overview文档,对大部分开发者来说,已经非常熟悉Xcode的功能和特性,不过伴随着iOS 8 SDK的发布,Xcode 6中也有些许调整,所以对该文档进行了翻译 ...

  4. 常见的特殊字符和HTML之间的对应关系~

    No. 文字表記 10進表記 16進表記 文字   Comment 001 " " " """   quotation mark = APL ...

  5. Objective-C在windows开发环境的搭建

    转自 http://www.hdj.me/objective-c-in-windows 安装GNUstep GNUstep Windows Installer提供了Windows平台下的Objecti ...

  6. 每日英语:Success Outside the Dress Code

    Anyone who has felt like the odd duck of the group can take heart from new research from Harvard Bus ...

  7. Navi.Soft30.开放平台.腾讯.开发手册

    1系统简介 1.1功能简述 现在是一个信息时代,并且正在高速发展.以前获取信息的途径非常少,可能只有电视台,收音机等有限的来源,而现在的途径数不胜数,如:QQ,微信,官方网站,个人网站等等 本开发手册 ...

  8. ArcGIS Geodatabase版本控制机制的学习总结

    本文是最近内部的一个学习的自我整理,只有关键信息,如果需要详细了解,请参阅ArcGIS帮助文档: http://resources.arcgis.com/zh-cn/help/main/10.1/in ...

  9. 16.3.1-sp_getapplock

    USE TestSystem BEGIN TRANSACTION test1 EXEC [sp_getapplock] 'AppSourceName' , 'Exclusive' WAITFOR DE ...

  10. solr多核配置

    假设已经配置好了一个单core的solr服务器. solr.xml配置文件 单核和多核主要在solr.xml配置不同.在solr/example中已经有一个名称为multicore的文件夹里面给我们配 ...