JAVAWEB开发之Spring详解之——Spring的入门以及IOC容器装配Bean(xml和注解的方式)、Spring整合web开发、整合Junit4测试

Spring框架学习路线

  • Spring的IOC
  • Spring的AOP,AspectJ
  • Spring的事务管理,三大框架的整合

Spring框架概述

什么是Spring?

 Spring是分层的JavaSE/EE full-stack(一站式)轻量级开源框架。
所谓分层:
  • SUN提供的EE的三层结构:web层、业务层、数据访问层(也称持久层,集成层)。
  • Struts2是web层基于MVC设计模式框架。
  • Hibernate是持久的一个ORM的框架。
所谓一站式:Spring框架有对三层的每层解决方案。
  • web层:Spring MVC
  • 持久层:JDBC Template
  • 业务层:Spring的Bean管理
以IoC(Inverse of Control 反转控制)和AOP(Aspect Oriented Programming 面向切面编程为内核)
官网:http://www.springsource.org/
Spring的出现是为了取代EJB的臃肿、低效、脱离现实

Spring的核心

  • IOC:(Inverse of Control 反转控制)  所谓的控制反转就是将对象的创建权交给Spring完成。
  • AOP:Aspect Oriented Programming 面向切面编程 是面向对象的延伸,不是替换面向对象,是用来解决OO中的一些问题。
  • DI:依赖注入(即在Spring创建对象的时候 注入对象的属性)
Spring的版本:Spring3.x和Spring4.x  Spring4需要整合hibernate4. 所以一般使用Spring3.

EJB:企业级JavaBean

  • 2002 : Expert One-to-One J2EE Design and Development 
  • 2004 : Expert One-to-One J2EE Development without EJB (EE开发真正需要使用的内容.)

使用Spring的好处:

(1) 方便耦合,简化开发
    Spring就是一个大工厂,可以将所有对象创建和依赖关系维护,交给Spring管理。
(2) AOP编程的支持
    Spring提供面向切面编程,可以方便的实现对程序进行权限拦截、运行监控等功能。
(3)声明式事务的支持
    只需要通过配置就可以完成对事务的管理,而无需手动编程。
(4)方便程序的测试
    Spring对Junit支持,可以通过注解方便的测试Spring程序。
(5)方便集成各种优秀框架
    Spring不排斥各种优秀的开源框架,其内部提供了对各种优秀框架(如Struts、Hibernate、MyBatis、Quartz等)的直接支持
(6) 降低JavaEE API的使用难度
    Spring对JavaEE开发中非常难用的一些API(JDBC、JavaMail、远程调用等),都提供了封装,使这些API应用难度大大降低。

Spring体系结构

Spring框架是一个分层框架,它包含一系列的功能要素并被分为大约20个模块。这些模块分为Core Container、Data Access/Integration、Web、AOP(Aspect Oriented Programming)、Instrumentation和测试部分,如下图所示:

Spring IOC控制反转快速入门示例

大致流程:
  • 下载Spring最新开发包。
  • 复制Spring开发jar包到工程。
  • 理解IOC控制反转和DI依赖注入。
  • 编写Spring核心配置文件。
  • 在程序中读取Spring配置文件,通过Spring框架获得Bean,完成相应的操作。

 (1) 下载Spring开发包

官方下载Spring3.x最新开发版本
网址:http://www.springsource.org/download/community
需要开发包和开发依赖包:
spring-framework-3.2.0.RELEASE-dist.zip — Spring开发包
  * docs :spring框架api和规范
  * libs :spring开发的jar包
  * schema :XML的约束文档.
spring-framework-3.0.2.RELEASE-dependencies.zip —  Spring开发中的依赖包

(2) 创建web工程引入相应jar包

包括核心包和日志有关的包
核心包:
   
  • spring-beans-3.2.0.RELEASE.jar
  • spring-Context-3.3.0.RELEASE.jar
  • spring-core-3.2.0.RELEASE.jar
  • spring-expression-3.2.0.RELEASE.jar
日志有关的包:
  • com.springsource.org.apache.commons.logging-1.1.1.jar 用于整合其他的日志的包(类似Hibernate中slf4j)   
  • com.springsource.org.apache.log4j-1.2.15.jar  log4j的包
注意:commons-logging日志整合包以及log4j的包在Spring的依赖包中
提示:spring3.0.X 版本 asm jar包 已经被合并到 spring core包中

(3) 创建测试类。

在HelloTest类中使用He'llService类对象
传统方式:HelloService helloService=new HelloService();

IOC  Inverse of Control 反转控制概念,就是将原本在程序中手动创建HelloService对象的创建权,交由Spring框架管理,简单说,就是创建HelloService对象控制权被反转到了Spring框架。

(4)创建Spring配置文件

 在src下创建Spring的核心配置文件applicationContext.xml,将HelloService的创建交由容器管理。
引入XML约束:在解压后的开发包中搜索xsd-config.xml引入beans约束

配置如下图所示:

注意:DI与IOC的区别
IOC:控制反转,将对象的创建权交给Spring管理。
DI:依赖注入,在Spring创建对象的过程中,把对象依赖的属性注入到类中。

(5) 加载Spring框架配置文件

ApplicationContext应用上下文,加载Spring框架配置文件(两种方式):
加载classpath下:
   new  ClassPathXmlApplicationContext("applicationContext.xml");
加载磁盘路径下:
   new FileSystemXmlApplicationContext("applicationContext.xml");
通过getBean方法获得Spring容器管理Bean对象

BeanFactory和ApplicationContext区别:


区别大致如下:
ApplicationContext类继承了BeanFactory。
BeanFactory采取延迟加载,第一次getBean时才会加载这个类。
ApplicationContext类加载配置文件的时候,创建所有的类。
ApplicationContext对BeanFactory进行了扩展,提供了更多的功能。如下:
  • 国际化处理。
  • 事件传递。
  • Bean自动装配。
  • 各种不同应用层的Context实现。
BeanFactory的使用方法如下:
BeanFactory factory = new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));
HelloService helloService = (HelloService) factory.getBean("helloService");
helloService.sayHello();
注意:在BeanFactory加载配置文件时也分为classpath路径和磁盘路径(即ClassPathResource和FileSystemResource)

MyEclipse解决Spring配置文件无法提示的问题

方案一: 联网下载 
  • http://www.springframework.org/schema/beans/spring-beans.xsd 
方案二: 采用本地schema配置
  • Myeclipse window-preferences- 搜索xml catalog
  • 选中User Specified Entries -- Add 操作
  • location 浏览选中 解压spring 包中 schema\beans\spring-beans-3.2.xsd
  • 修改Key type 为 Schema location
  • key 修改为 http://www.springframework.org/schema/beans/spring-beans.xsd
  • 点击OK
如下图所示:

Spring底层IOC的原理

在开发中一般由web层调用业务层业务层调用持久层
  • 面向对象:最传统的web层调用业务层代码:UserService userService=new UserService(); 这种最原始的方式不具备扩展性。
  • 面向接口:按照面向对象的面向接口的方式编程 将UserService提取为一个接口,可以实现接口提供各种真实实现类Impl 即第二个阶段:UserService userService=new UserServiceImpl(); 将程序具体的实现编写到程序中,根据需求切换底层的实现,虽然使程序具备了扩展性。但是在切换底层实现时需要修改源代码,造成程序紧密耦合。
  • OCP原则—工厂模式:按照Java的OCP原则,即open-close原则:扩展功能尽量不要修改源程序,提供新的方法属性的形式扩展其功能,意思就是对扩展是开放的对修改是关闭的。可以使用工厂模式进行扩展。
public class BeanFactory{
   public UserService getUserService(){
       return new UserServiceImpl(); 
   }
}
即把程序与实现类的耦合转成与工厂的耦合。与实现类完成解耦合的形式:
BeanFactory factory= ......;
UserService service=factory.getUserService();
为了解除与工厂的耦合,在利用反射在工厂内部动态的生成对象。
public class BeanFactory{
   public UserService getUserService(){
        // 反射+配置文件
       return Class.forName(类名).newInStance(); 
   }
}
xml、properties:className=cn.test.service.UserServiceImpl

Spring快速入门程序示例:

在web项目中导入jar包,并在src下新建log4j.properties日志配置文件和ApplicationContext.xml

log4j.properties
[plain]  view plain  copy
 
  1. ### direct log messages to stdout ###  
  2. log4j.appender.stdout=org.apache.log4j.ConsoleAppender  
  3. log4j.appender.stdout.Target=System.err  
  4. log4j.appender.stdout.layout=org.apache.log4j.PatternLayout  
  5. log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n  
  6.   
  7. ### direct messages to file mylog.log ###  
  8. log4j.appender.file=org.apache.log4j.FileAppender  
  9. log4j.appender.file.File=c\:mylog.log  
  10. log4j.appender.file.layout=org.apache.log4j.PatternLayout  
  11. log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n  
  12.   
  13. ### set log levels - for more verbose logging change 'info' to 'debug' ###  
  14.   
  15. log4j.rootLogger=off, stdout   

为了方便测试,暂时将日志关闭
src下的applicationContext.properties
[html]  view plain  copy
 
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  4.     xsi:schemaLocation="  
  5. http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">  
  6.     <!-- demo1快速入门 -->  
  7.     <!-- 通过一个<bean>标签设置类的信息,通过id属性为类起个标识 -->  
  8.     <bean id="userService" class="lx.test.spring.demo1.HelloServiceImpl">  
  9.        <!-- 使用<property>标签注入属性:使用这种方式注入的属性必须要有setter方法 -->  
  10.        <property name="info" value="入门示例"/>  
  11.     </bean>  
  12. </beans>  
为了测试磁盘路径的资源获取方式 并在工程根目录下新建applicationContext.xml,,如下所示:
[html]  view plain  copy
 
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  4.     xsi:schemaLocation="  
  5. http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">  
  6.     <!-- demo1快速入门 -->  
  7.     <!-- 通过一个<bean>标签设置类的信息,通过id属性为类起个标识 -->  
  8.     <bean id="userService" class="lx.test.spring.demo1.HelloServiceImpl">  
  9.        <!-- 使用<property>标签注入属性:使用这种方式注入的属性必须要有setter方法 -->  
  10.        <property name="info" value="入门示例(磁盘路径)"/>  
  11.     </bean>  
  12. </beans>  
HelloService
[java]  view plain  copy
 
  1. package lx.test.spring.demo1;  
  2.   
  3. /** 
  4.  * 入门案例 
  5.  *  
  6.  *  
  7.  */  
  8. public interface HelloService {  
  9.     public void sayHello();  
  10. }  
HelloServiceImpl
[java]  view plain  copy
 
  1. package lx.test.spring.demo1;  
  2.   
  3. /** 
  4.  * 入门案例的实现类 
  5.  */  
  6. public class HelloServiceImpl implements HelloService {  
  7.     private String info;  
  8.   
  9.     public void setInfo(String info) {  
  10.         this.info = info;  
  11.     }  
  12.   
  13.     public void sayHello() {  
  14.         System.out.println("Hello Spring..." + info);  
  15.     }  
  16.   
  17. }   
新建入门测试类SpringTest1
[java]  view plain  copy
 
  1. package lx.test.spring.demo1;  
  2.   
  3. import java.io.IOException;  
  4.   
  5. import org.junit.Test;  
  6. import org.springframework.beans.factory.BeanFactory;  
  7. import org.springframework.beans.factory.xml.XmlBeanFactory;  
  8. import org.springframework.context.ApplicationContext;  
  9. import org.springframework.context.support.ClassPathXmlApplicationContext;  
  10. import org.springframework.context.support.FileSystemXmlApplicationContext;  
  11. import org.springframework.core.io.ClassPathResource;  
  12. import org.springframework.core.io.FileSystemResource;  
  13. import org.springframework.core.io.Resource;  
  14.   
  15. public class SpringTest1 {  
  16.   
  17.     @Test  
  18.     // 传统方式  
  19.     public void demo1() {  
  20.         // 造成程序紧密耦合  
  21.         HelloService helloService = new HelloServiceImpl();  
  22.         helloService.sayHello();  
  23.     }  
  24.   
  25.     @Test  
  26.     // Spring开发  
  27.     public void demo2() {  
  28.         // 创建一个工厂类  
  29.         ApplicationContext applicationContext = new ClassPathXmlApplicationContext(  
  30.                 "applicationContext.xml");  
  31.         HelloService helloService = (HelloService) applicationContext  
  32.                 .getBean("userService");  
  33.         helloService.sayHello();  
  34.     }  
  35.   
  36.     @Test  
  37.     // 加载磁盘路径下的配置文件  
  38.     public void demo3() {  
  39.         ApplicationContext applicationContext = new FileSystemXmlApplicationContext(  
  40.                 "applicationContext.xml");  
  41.   
  42.         HelloService helloService = (HelloService) applicationContext  
  43.                 .getBean("userService");  
  44.         helloService.sayHello();  
  45.     }  
  46.   
  47.     @Test  
  48.     // 使用BeanFactory加载  
  49.     public void demo4() throws IOException {  
  50.         // ClassPathResource FileSystemResource 两种方式  
  51.   
  52.         // BeanFactory beanFactory = new XmlBeanFactory(new FileSystemResource("applicationContext.xml"));  
  53.           
  54.         // Resource resource= new FileSystemResource("applicationContext.xml");  
  55.         // F:\myEclipse_project\myspring3_day01\applicationContext.xml  
  56.         // System.out.println(resource.getFile().getAbsolutePath());  
  57.         BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource(  
  58.                 "applicationContext.xml"));  
  59.   
  60.         HelloService helloService = (HelloService) beanFactory  
  61.                 .getBean("userService");  
  62.         helloService.sayHello();  
  63.     }  
  64.   
  65. }  
依次测试运行结果如下:

IOC容器装配Bean(XML配置方式)

Spring框架实例化Bean的方式

有三种实例化Bean的方式:构造方法实例化(默认无参数)、静态工厂实例化、实例工厂实例化
方式一:使用类构造器实例化(默认无参数)
<bean id=“personService" class="cn.test.bean.impl.PersonServiceImpl"/>
方式二:使用静态工厂实例化(简单工厂模式)
<bean id="personService" class="cn.test.factory.PersonServiceFactory" factory-method="createPersonService" />
public class PersonServiceFactory {
      public  static PersonService createPersonService(){
                return new PersonServiceImpl();
      }
}
方式三:使用实例工厂方法实例化(工厂方法模式)
<bean id="personServiceFactory" class="cn.test.factory.PersonServiceFactory" />
<bean id="personService" factory-bean="personServiceFactory" factory-method="createPersonService" />
public class PersonServiceFactory {
       public  PersonService createPersonService(){
                     return new PersonServiceImpl();
       }
}
示例代码如下:
applicationContext.xml
[html]  view plain  copy
 
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  4.     xsi:schemaLocation="  
  5. http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">  
  6.     <!-- demo2 Bean实例化的三种方式 -->  
  7.     <!-- 默认情况下使用的就是无参数的构造方法 -->  
  8.     <bean name="bean1" class="lx.test.spring.demo2.Bean1" />  
  9.   
  10.     <!-- 第二种使用静态工厂实例化 -->  
  11.     <bean id="bean2" class="lx.test.spring.demo2.Bean2Factory" factory-method="getBean2" />  
  12.   
  13.     <!-- 第三种使用实例工厂实例化 -->  
  14.     <bean id="bean3" factory-bean="bean3Factory" factory-method="getBean3" />  
  15.     <bean id="bean3Factory" class="lx.test.spring.demo2.Bean3Factory" />  
  16. </beans>  
Bean1
[java]  view plain  copy
 
  1. package lx.test.spring.demo2;  
  2.   
  3. /** 
  4.  * 使用无参数的构造方法实例化 
  5.  */  
  6. public class Bean1 {  
  7.     public Bean1() {  
  8.         System.out.println("Bean1默认的无参构造...");  
  9.     }  
  10. }  
Bean2
[java]  view plain  copy
 
  1. package lx.test.spring.demo2;  
  2.   
  3. /** 
  4.  * 使用静态工厂方法实例化 
  5.  *  
  6.  */  
  7. public class Bean2 {  
  8.   
  9. }  
Bean2Factory
[java]  view plain  copy
 
  1. package lx.test.spring.demo2;  
  2.   
  3. /** 
  4.  * Bean2的静态工厂 
  5.  */  
  6. public class Bean2Factory {  
  7.     public static Bean2 getBean2() {  
  8.         System.out.println("静态工厂获得Bean2的方法...");  
  9.         return new Bean2();  
  10.     }  
  11. }  
Bean3
[java]  view plain  copy
 
  1. package lx.test.spring.demo2;  
  2.   
  3. /** 
  4.  * 使用实例工厂实例化 
  5.  */  
  6. public class Bean3 {  
  7.   
  8. }  
Bean3Factory
[java]  view plain  copy
 
  1. package lx.test.spring.demo2;  
  2.   
  3. /** 
  4.  * 使用实例工厂 
  5.  */  
  6. public class Bean3Factory {  
  7.     public Bean3 getBean3() {  
  8.         System.out.println("Bean3实例工厂的getBean3()方法...");  
  9.         return new Bean3();  
  10.     }  
  11. }  
SpringTest2
[java]  view plain  copy
 
  1. package lx.test.spring.demo2;  
  2.   
  3. import org.junit.Test;  
  4. import org.springframework.context.ApplicationContext;  
  5. import org.springframework.context.support.ClassPathXmlApplicationContext;  
  6.   
  7. /** 
  8.  * Bean的实例化测试 
  9.  */  
  10. public class SpringTest2 {  
  11.   
  12.     @Test  
  13.     // 无参数的构造方法实例化  
  14.     public void demo1() {  
  15.         ApplicationContext applicationContext = new ClassPathXmlApplicationContext(  
  16.                 "applicationContext.xml");  
  17.         Bean1 bean1 = (Bean1) applicationContext.getBean("bean1");  
  18.         System.out.println(bean1);  
  19.     }  
  20.       
  21.   
  22.     @Test  
  23.     // 无参数的构造方法实例化  
  24.     public void demo2() {  
  25.         ApplicationContext applicationContext = new ClassPathXmlApplicationContext(  
  26.                 "applicationContext.xml");  
  27.         Bean2 bean2 = (Bean2) applicationContext.getBean("bean2");  
  28.         System.out.println(bean2);  
  29.     }  
  30.       
  31.   
  32.     @Test  
  33.     // 无参数的构造方法实例化  
  34.     public void demo3() {  
  35.         ApplicationContext applicationContext = new ClassPathXmlApplicationContext(  
  36.                 "applicationContext.xml");  
  37.         Bean3 bean3 = (Bean3) applicationContext.getBean("bean3");  
  38.         System.out.println(bean3);  
  39.     }  
  40.       
  41. }  
依次测试结果如下:



发现每次调用获取ApplicationContext对象时都会重新全部加载配置中所有的Bean类

Bean的其他配置

id和name的区别

 Bean的命名id属性和name属性:
  • 一般情况下,装配一个Bean时,通过指定一个id属性作为Bean的名称。
  • id属性在IOC容器中必须是唯一的。
  • id的命名要满足XML对ID属性的命名规范:必须以字母开头,可以使用字母、数字、连字符、下划线、句号、冒号。
  • 如果Bean的名称中含有特殊字符,就需要使用name属性:例如 <bean name="person" class="cn.test.bean.person"/>
  • 因为name属性可以相同,所以后出现Bean会覆盖之前出现的同名的Bean。

Bean的作用域

在<bean>标签上的scope属性指对象的范围 取值可以有以下几种:
  • singleton: 单例的。在Spring IOC容器中仅存在一个Bean实例,Bean以单例方式存在。
  • prototype: 多例的。 每次从容器中调用Bean时,都会返回一个新的实例,即每次调用getBean()时,相当于执行new XxxBean()。
  • request: 每次HTTP请求都会创建一个新的Bean,该作用域仅适用于WebApplicationContext环境。相当于在web开发中创建了一个对象,并将这个对象存入request域范围,request.setAttribute();
  • session:  同一个HTTP Session共享一个Bean,不同Session使用不同Bean,仅适用于WebApplicationContext环境。相当于在web开发中,创建了一个对象,将这个对象存入session范围,即session.setAttribute();
  • globalSession: 一般用于Porlet应用环境,该作用域仅适用于WebApplicationContext环境。Porlet指的是分布式开发,如果不是Porlet环境,globalSession等同于session。
实际开发中主要使用singleton,prototype。
程序示例如下:
ApplicationContext.xml
[html]  view plain  copy
 
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  4.     xsi:schemaLocation="  
  5. http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">  
  6.     <!-- Bean的作用范围 -->  
  7.     <bean id="customer" class="lx.test.spring.demo3.Customer" scope="prototype" />  
  8.     <bean id="product" class="lx.test.spring.demo3.Product"  
  9.         init-method="setup" destroy-method="teardown">  
  10.         <property name="name" value="空调" />  
  11.     </bean>  
  12. </beans>  
Customer
[java]  view plain  copy
 
  1. package lx.test.spring.demo3;  
  2.   
  3. public class Customer {  
  4.     public Customer() {  
  5.         System.out.println("Customer类被实例化...");  
  6.     }  
  7. }  
Product
[java]  view plain  copy
 
  1. package lx.test.spring.demo3;  
  2.   
  3. public class Product {  
  4.     private String name;  
  5.   
  6.     public void setName(String name) {  
  7.         this.name = name;  
  8.     }  
  9.   
  10.     public void setup() {  
  11.         System.out.println("Product初始化方法执行...");  
  12.     }  
  13.   
  14.     public void teardown() {  
  15.         System.out.println("Product销毁的方法执行...");  
  16.     }  
  17.   
  18.     @Override  
  19.     public String toString() {  
  20.         return "Product [name=" + name + "]";  
  21.     }  
  22.   
  23. }  
测试类SpringTest3
[java]  view plain  copy
 
  1. package lx.test.spring.demo3;  
  2.   
  3. import org.junit.Test;  
  4. import org.springframework.context.ApplicationContext;  
  5. import org.springframework.context.support.ClassPathXmlApplicationContext;  
  6.   
  7. /** 
  8.  * Bean的作用范围 
  9.  */  
  10. public class SpringTest3 {  
  11.     @Test  
  12.     // 测试scope  
  13.     public void demo1() {  
  14.         ApplicationContext applicationContext = new ClassPathXmlApplicationContext(  
  15.                 "applicationContext.xml");  
  16.         Customer c1 = (Customer) applicationContext.getBean("customer");  
  17.         System.out.println(c1);  
  18.   
  19.         Customer c2 = (Customer) applicationContext.getBean("customer");  
  20.         System.out.println(c2);  
  21.     }  
  22.   
  23.     @Test  
  24.     // 测试初始化和销毁方法  
  25.     public void demo2() {  
  26.         ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext(  
  27.                 "applicationContext.xml");  
  28.         Product p1 = (Product) applicationContext.getBean("product");  
  29.         System.out.println(p1);  
  30.         applicationContext.close();  
  31.     }  
  32. }  
运行结果:

Spring容器中Bean的生命周期

配置Bean的初始化和销毁的方法:Spring初始化或销毁bean时,有时需要做一些处理工作,因此Spring可以在创建和拆卸bean的时候调用bean的两个生命周期中的方法

 注意:
销毁方法只对单例范围的bean有效,即只有单例范围的bean在销毁时调用配置到销毁方法。
web容器中会自动调用销毁方法,但是main()函数或测试用例需要手动调用,必须关闭工厂才能销毁bean。
Spring容器中Bean生命周期图解:

bean的生命周期大致分为11个步骤:
1. instantiate bean  对象实例化。
2. populate properties  封装属性。
3. 如果Bean实现BeanNameAware接口 执行setBeanName。
4. 如果Bean实现BeanFactoryAware 或者ApplicationContextAware接口设置工厂setBeanFactory或者上下文对象setApplicationContext。
5.  如果存在类实现BeanPostProcessor(后处理Bean),执行PostProcessBeforeInitialization。
6. 如果Bean实现InitializingBean 执行afterPropertiesSet。
7. 调用<bean init-method="init"> 指定初始化方法init。
8.  如果存在类实现BeanPostProcessor(处理Bean),执行postProcessAfterInitialization。
9. 执行业务逻辑处理。
10. 如果Bean实现DisposableBean接口 则执行destroy方法。
11. 调用<bean destroy-method="customerDestroy"> 指定销毁方法customerDestroy。
程序示例如下:
applicationContext.xml
[html]  view plain  copy
 
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  4.     xsi:schemaLocation="  
  5. http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">  
  6.   
  7.     <!-- Bean的生命周期 -->  
  8.     <bean id="customerService" class="lx.test.spring.demo4.CustomerServiceImpl"  
  9.         init-method="setup" destroy-method="teardown">  
  10.         <property name="name" value="张三" />  
  11.     </bean>  
  12.     <bean class="lx.test.spring.demo4.MyBeanPostProcessor" />  
  13.   
  14. </beans>  
CustomerService
[java]  view plain  copy
 
  1. package lx.test.spring.demo4;  
  2.   
  3. public interface CustomerService {  
  4.     public void add();  
  5.     public void find();  
  6. }  
CustomerServiceImpl
[java]  view plain  copy
 
  1. package lx.test.spring.demo4;  
  2.   
  3. import org.springframework.beans.BeansException;  
  4. import org.springframework.beans.factory.BeanNameAware;  
  5. import org.springframework.beans.factory.DisposableBean;  
  6. import org.springframework.beans.factory.InitializingBean;  
  7. import org.springframework.context.ApplicationContext;  
  8. import org.springframework.context.ApplicationContextAware;  
  9.   
  10. public class CustomerServiceImpl implements CustomerService, BeanNameAware,  
  11.         ApplicationContextAware, InitializingBean, DisposableBean {  
  12.     private String name;  
  13.   
  14.     public void setName(String name) {  
  15.         System.out.println("第二步:属性的注入.");  
  16.         this.name = name;  
  17.     }  
  18.   
  19.     public CustomerServiceImpl() {  
  20.         super();  
  21.         System.out.println("第一步:实例化类.");  
  22.     }  
  23.   
  24.     public void add() {  
  25.         System.out.println("添加客户...");  
  26.     }  
  27.   
  28.     public void find() {  
  29.         System.out.println("查询客户...");  
  30.     }  
  31.   
  32.     public void setBeanName(String name) {  
  33.         System.out.println("第三步:注入配置的类的名称" + name);  
  34.     }  
  35.   
  36.     public void setApplicationContext(ApplicationContext applicationContext)  
  37.             throws BeansException {  
  38.         System.out.println("第四步:注入ApplicationContext" + applicationContext);  
  39.     }  
  40.   
  41.     public void afterPropertiesSet() throws Exception {  
  42.         System.out.println("第六步:属性的设置后执行...");  
  43.     }  
  44.   
  45.     public void setup() {  
  46.         System.out.println("第七步:调用手动设置的初始化方法...");  
  47.     }  
  48.   
  49.     public void destroy() throws Exception {  
  50.         System.out.println("第十步:调用销毁的方法...");  
  51.     }  
  52.   
  53.     public void teardown() {  
  54.         System.out.println("第十一步:调用手动销毁的方法...");  
  55.     }  
  56. }  
MyBeanPostProcessor
[java]  view plain  copy
 
  1. package lx.test.spring.demo4;  
  2.   
  3. import java.lang.reflect.InvocationHandler;  
  4. import java.lang.reflect.Method;  
  5. import java.lang.reflect.Proxy;  
  6.   
  7. import org.springframework.beans.BeansException;  
  8. import org.springframework.beans.factory.config.BeanPostProcessor;  
  9.   
  10. public class MyBeanPostProcessor implements BeanPostProcessor {  
  11.     /** 
  12.      * bean: 实例对象 beanName:在配置文件中配置的类的标识 
  13.      */  
  14.     public Object postProcessBeforeInitialization(Object bean, String beanName)  
  15.             throws BeansException {  
  16.         System.out.println("第五步:初始化之前执行...");  
  17.         return bean;  
  18.     }  
  19.   
  20.     public Object postProcessAfterInitialization(final Object bean,  
  21.             String beanName) throws BeansException {  
  22.         System.out.println("第八步:初始化后执行...");  
  23.         // 动态代理  
  24.         if (beanName.equals("customerService")) {  
  25.             Object proxy = Proxy.newProxyInstance(bean.getClass()  
  26.                     .getClassLoader(), bean.getClass().getInterfaces(),  
  27.                     new InvocationHandler() {  
  28.                         // 调用目标方法的时候,调用invoke方法  
  29.                         public Object invoke(Object proxy, Method method,  
  30.                                 Object[] args) throws Throwable {  
  31.                             if ("add".equals(method.getName())) {  
  32.                                 System.out.println("权限检验...");  
  33.                                 Object result = method.invoke(bean, args);  
  34.                                 return result;  
  35.                             }  
  36.                             return method.invoke(bean, args);  
  37.                         }  
  38.                     });  
  39.             return proxy;  
  40.         }  
  41.         return bean;  
  42.     }  
  43.   
  44. }  
SpringTest4
[java]  view plain  copy
 
  1. package lx.test.spring.demo4;  
  2.   
  3. import org.junit.Test;  
  4. import org.springframework.context.support.ClassPathXmlApplicationContext;  
  5.   
  6. public class SpringTest4 {  
  7.   
  8.     @Test  
  9.     // Bean完整的生命周期  
  10.     public void demo1() {  
  11.         ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext(  
  12.                 "applicationContext.xml");  
  13.         CustomerService customerService = (CustomerService) applicationContext  
  14.                 .getBean("customerService");  
  15.         customerService.add();  
  16.         customerService.find();  
  17.   
  18.         applicationContext.close();  
  19.     }  
  20. }  
运行结果:

Bean中属性的注入

依赖注入Bean的属性
对于类成员变量,注入方式有三种:
  • 构造方法(构造器)注入。
  • 属性setter方法注入。
  • 接口注入。
如下所示:

Spring只支持构造器和Setter方法注入。

依赖注入Bean属性—构造方法注入

使用构造方法注入,在Spring配置文件中,通过<constructor-arg>设置注入的属性(可以通过index或者type注入)

注意:也可以使用<constructor-arg name="name" value="宝马"> 普通属性时value 对象属性为ref

依赖注入Bean属性—setter方法注入

使用setter方法注入,在Spring配置文件中,通过<property>设置注入的属性

以上设置的只是普通属性,还可以使用<property>引入其他Bean


如果bean对应的类中有与对象相关的成员变量时,可以使用ref替代value属性。

名称空间p: 注入属性(属于setter注入)

  • 使用p命名空间。
  • 为了简化XML文件配置,Spring2.5开始引入一个新的p名称空间。
  • p:<属性名>="xxx"  引入常量值。
  • p:<属性名>-ref="xxx" 引用其他Bean对象。

SpEL注入

Spring3.0 创建了一种新的方式用以配置对象的注入(set注入或者构造参数注入),便是SpEL(Spring Expression Language ) Spring表达式语言,对依赖注入进行简化。
语法:#{ 表达式 } 例如: <bean id="" value="#{表达式}" />
基础特性:SpEL 使用#{ ... }作为定界符,所有大括号中的字符都将被认为是SpEL。
(1)  字面量的表示
1>整数:  <property name="count" value="#{5}">
2>小数:  <property name="frequency" value="#{89.7}">
3>科学计数法: <property name="capacity" value="#{1e4}">
4>String可以使用单引号或者双引号作为字符串的定界符号。
<property name=" name " value= "#{'Chuck'}" />
<property name=' name ' value= '#{"Chuck"}' />
5>Boolean:  <property name="enabled" value="#{false}"/>

(2)  引用Bean,属性和方法
1> 引用其他对象
<bean id="saxophone"  value="com.xxx.xxx.Xxx" />
<bean ...>
       <property name="instrument" value="#{saxophone}"
</bean>
 通过id:"saxophone"  将对象注入到instrument属性中,这与下面的配置是一样的:
<property name="instrument" ref="saxophone"/>
2> 引用其他对象的属性
<bean id="carl"  class="com.springinaction.springidol.Instrumentalist">
  <property name="
song" value="#{kenny.song}" />
</bean>

kenny 是 Bean Id 而 song 是属性的名称,这样配置就等同于写了如下一段代码:
Instrumentalist carl = new Instrumentalist();
carl.setSong(kenny.getSong());
3> 调用别的对象的其它方法,并取得返回值。
<property name="song" value="songSelector.selectSong()"/>
调用了BeanId为"songSelector"的对象的selectSong()方法,并将返回值注入到song属性中。或者还可以进行链式操作。如:<property name="song" value="songSelector.selectSong().toUpperase()" />
 在链式操作中,如果songSelector.selectSong()返回null的还会抛出异常,为了避免异常。我们要使用 ?. 表达式。这样如果songSelector.selectSong()为null就不会再调用后面的方法了。如下所示:
<property name="song" value="songSelector.selectSong()?.toUpperCase()"/>
4>调用静态方法
我们已经知道如何通过一个对象调用它的方法了,但是如何调用一个静态方法呢? 用T{}。它将返回一个Class Object,然后我们再调用相应的方法即可:
<property name="multiplier" value="T(java.lang.Math).PI"/>

(3) SPEL支持的运算符号
1> 算数运算符: +,-,*,/,%,^
<property name="adjustedAmount" value="#{counter.total + 42}"/>
<property name="adjustedAmount" value="#{counter.total - 20}"/>
<property name="
circumference" value="#{2 * T(java.lang.Math).PI * circle.radius}"/>
<property name="average" value="#{counter.total / counter.count}"/>
<property name="
remainder" value="#{counter.total % counter.count}"/>
<property name="
area" value="#{T(java.lang.Math).PI * circle.radius ^ 2}"/>
加号还可以用作连接字符串
<property name="fullName" value="#{performer.firstName + ' ' + performer.lastName}"/>
2>比较运算符:<,>,==,<=,>=,lt,gt,eq,le,ge
<property name="equal" value="#{counter.total == 100}"/>
注意:不可以使用<和>号,因为在xml中它有特殊的含义,可以使用lt和gt代替
<property name="hasCapacity" value="#{counter.total le 100000}"/>
3> 逻辑运算符:and,or,not,|
<property name="largeCircle" value="#{shape.kind == 'circle' and shape.perim eter gt 10000} "/>
<property name="outOfStock" value="#{!product.available}"/>
<property name="
outOfStock" value="#{not product.available}"/>
4> If-else 运算符:?: (ternary), ?: (Elvis)
〇最基本的 ?:(这如同我们在使用 EL 表达式语言):
<property name="instrument" value="#{songSelector.selectSong() == 'Jingle Bells' ? piano : ' Jingle Bells '}"/>
〇变体的 ?:
<property name="song" value="#{kenny.song != null ? kenny.song : 'Greensleeves'}"/>
上下两种是同一语义,但下面的明显简洁
<property name="song" value="#{kenny.song ?: 'Greensleeves'}"/>
5> 正则表达式
<property name="validEmail" value="#{admin.email matches '[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,4}'}"/>
表达式返回逻辑值,如果匹配返回true,否则返回false

SPEL对集合的支持:
——环境
有实体City定义如下:
package com.habuma.spel.cities;
public class City {
   private String name;
   private String state;
   private int population;
}

XML中有如下定义:
<util:list id="cities">
<bean class="
com.habuma.spel.cities.City" p:name="Chicago" p:state="IL" p:population="2853114"/>
<bean class="com.habuma.spel.cities.City" p:name="Atlanta" p:state="GA" p:population="537958"/>
<bean class="com.habuma.spel.cities.City" p:name="
Dallas" p:state="TX" p:population="1279910"/>
<bean class="com.habuma.spel.cities.City" p:name="
Houston" p:state="TX" p:population="2242193"/>
<bean class="com.habuma.spel.cities.City" p:name="
Odessa" p:state="TX" p:population="90943"/>
<bean class="com.habuma.spel.cities.City" p:name="
El Paso" p:state="TX" p:population="613190"/>
<bean class="com.habuma.spel.cities.City" p:name="
Jal" p:state="NM" p:population="1996"/>
<bean class="com.habuma.spel.cities.City"  p:name="
Las Cruces" p:state="NM" p:population="91865"/>
</util:list>
——1、获取Collection中的某个对象
1> 通过下标访问,如:<property name="chosenCity" value="#{cities[2]}"/>
我们就会获得 population 为"1279910"的 city(记住下标从 0 开始),对象下标可以通过变量指定,如下:
<property name="chosenCity" value="#{cities[T(java.lang.Math).random() * cities.size()]}"/>
2> 如果对象是从Map集合中获得,可以指定key值,如下所示:
<property name="chosenCity" value="#{cities['Dallas']}"/>
3> Bean对象也可以通过key访问properties的值,如下所示:
<util:properties id="settings" location="classpath:settings.properties"/>
<property name="
accessToken" value="#{settings['twitter.accessToken']}"/>
4> 对象可以通过下标获取String串中的某个字符
 'This is a test'[3]
——2、获取 Collection 中的子集-通过条件筛选(注意新对象是一个新的 Collection)
1>筛选子集(.?[])
<property name="bigCities" value="#{cities.?[population gt 100000]}"/>
2>获取第一个(.^[])
<property name="aBigCity" value="#{cities.^[population gt 100000]}"/>
3>获取最后一个(.$[])
<property name="aBigCity" value="#{cities.$[population gt 100000]}"/>
——3、集合的投影(.![])
如果想获得所有城市的名称组成的列表,可用如下操作
<property name="cityNames" value="#{cities.![name]}"/>
将返回"Chicago", "Atlanta", "Dallas"
也可以组合两个列,如下:
<property name="cityNames" value="#{cities.![name + ', ' + state]}"/>
将返回"Chicago, IL", "Atlanta, GA", and "Dallas, TX".
—— 4、将投影和筛选结合
<property name="cityNames" value="#{cities.?[population gt 100000].![name +', ' + state]}"/>
 实例代码如下:
Car
[java]  view plain  copy
 
  1. package lx.test.spring.demo5;  
  2.   
  3. public class Car {  
  4.     private String name;  
  5.     private Double price;  
  6.   
  7.     public Car() {  
  8.         super();  
  9.     }  
  10.   
  11.     public Car(String name, Double price) {  
  12.         super();  
  13.         this.name = name;  
  14.         this.price = price;  
  15.     }  
  16.   
  17.     @Override  
  18.     public String toString() {  
  19.         return "Car [name=" + name + ", price=" + price + "]";  
  20.     }  
  21.   
  22. }  
Car2
[java]  view plain  copy
 
  1. package lx.test.spring.demo5;  
  2.   
  3. public class Car2 {  
  4.     private String name;  
  5.     private Double price;  
  6.   
  7.     public void setName(String name) {  
  8.         this.name = name;  
  9.     }  
  10.   
  11.     public void setPrice(Double price) {  
  12.         this.price = price;  
  13.     }  
  14.   
  15.     @Override  
  16.     public String toString() {  
  17.         return "Car2 [name=" + name + ", price=" + price + "]";  
  18.     }  
  19.   
  20. }  
Person
[java]  view plain  copy
 
  1. package lx.test.spring.demo5;  
  2.   
  3. public class Person {  
  4.     private String name;  
  5.     private Car2 car2;  
  6.     public void setName(String name) {  
  7.         this.name = name;  
  8.     }  
  9.     public void setCar2(Car2 car2) {  
  10.         this.car2 = car2;  
  11.     }  
  12.     @Override  
  13.     public String toString() {  
  14.         return "Person [name=" + name + ", car2=" + car2 + "]";  
  15.     }  
  16. }  
PersonInfo
[java]  view plain  copy
 
  1. package lx.test.spring.demo5;  
  2.   
  3. public class PersonInfo {  
  4.     private String name;  
  5.   
  6.     public String getName() {  
  7.         return name;  
  8.     }  
  9.   
  10.     public void setName(String name) {  
  11.         this.name = name;  
  12.     }  
  13.   
  14.     public String showName() {  
  15.         return name;  
  16.     }  
  17. }  
applicationContext.xml
[html]  view plain  copy
 
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3.     xmlns:p="http://www.springframework.org/schema/p"  
  4.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  5.     xsi:schemaLocation="  
  6. http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">  
  7.   
  8.     <!-- Bean的属性注入 -->  
  9.     <!-- 构造方法注入 -->  
  10.     <bean id="car1_01" class="lx.test.spring.demo5.Car">  
  11.         <constructor-arg name="name" value="宝马" />  
  12.         <constructor-arg name="price" value="1000000" />  
  13.     </bean>  
  14.     <bean id="car1_02" class="lx.test.spring.demo5.Car">  
  15.         <constructor-arg index="0" type="java.lang.String"  
  16.             value="奔驰" />  
  17.         <constructor-arg index="1" type="java.lang.Double"  
  18.             value="2000000" />  
  19.     </bean>  
  20.       
  21.     <!-- setter方法: <property>或p名称空间 -->  
  22.     <bean id="car2_01" class="lx.test.spring.demo5.Car2">  
  23.        <property name="name" value="五菱"/>  
  24.        <property name="price" value="10000"/>  
  25.     </bean>  
  26.     <bean id="car2_02" class="lx.test.spring.demo5.Car2">  
  27.        <property name="name" value="#{'开瑞优优'}"/>  
  28.        <property name="price" value="#{8000}"/>  
  29.     </bean>  
  30.     <bean id="car2_03" class="lx.test.spring.demo5.Car2" p:name="面包车" p:price="15000"/>  
  31.       
  32.     <!-- ref:注入成员对象 -->  
  33.     <bean id="person_01" class="lx.test.spring.demo5.Person">  
  34.        <property name="name" value="老子"/>  
  35.        <property name="car2" ref="car2_01"/>  
  36.     </bean>  
  37.     <!-- p命名空间写法 -->  
  38.     <bean id="person_02" class="lx.test.spring.demo5.Person" p:name="上帝" p:car2-ref="car2_02"/>  
  39.     <!-- SPEL写法 -->  
  40.     <bean id="person_03" class="lx.test.spring.demo5.Person">  
  41.        <property name="name" value="#{personInfo.showName()}"/>  
  42.        <property name="car2" value="#{car2_03}"/>  
  43.     </bean>  
  44.     <bean id="personInfo" class="lx.test.spring.demo5.PersonInfo">  
  45.        <property name="name" value="张三"/>   
  46.     </bean>  
  47.   
  48. </beans>  
SpringTest5
[java]  view plain  copy
 
  1. package lx.test.spring.demo5;  
  2.   
  3. import org.junit.Test;  
  4. import org.springframework.context.ApplicationContext;  
  5. import org.springframework.context.support.ClassPathXmlApplicationContext;  
  6.   
  7. public class SpringTest5 {  
  8.     @Test  
  9.     public void demo1() {  
  10.         ApplicationContext applicationContext = new ClassPathXmlApplicationContext(  
  11.                 "applicationContext.xml");  
  12.         Car car = (Car) applicationContext.getBean("car1_01");  
  13.         Car car1_02 = (Car) applicationContext.getBean("car1_02");  
  14.         System.out.println(car);  
  15.         System.out.println(car1_02);  
  16.     }  
  17.   
  18.     @Test  
  19.     public void demo2() {  
  20.         ApplicationContext applicationContext = new ClassPathXmlApplicationContext(  
  21.                 "applicationContext.xml");  
  22.         Car2 car2_01 = (Car2) applicationContext.getBean("car2_01");  
  23.         Car2 car2_02 = (Car2) applicationContext.getBean("car2_02");  
  24.         Car2 car2_03 = (Car2) applicationContext.getBean("car2_03");  
  25.         System.out.println(car2_01);  
  26.         System.out.println(car2_02);  
  27.         System.out.println(car2_03);  
  28.     }  
  29.   
  30.     @Test  
  31.     public void demo3() {  
  32.         ApplicationContext applicationContext = new ClassPathXmlApplicationContext(  
  33.                 "applicationContext.xml");  
  34.         Person person_01 = (Person) applicationContext.getBean("person_01");  
  35.         Person person_02 = (Person) applicationContext.getBean("person_02");  
  36.         Person person_03 = (Person) applicationContext.getBean("person_03");  
  37.         System.out.println(person_01);  
  38.         System.out.println(person_02);  
  39.         System.out.println(person_03);  
  40.     }  
  41.   
  42. }  
运行结果如下:


  集合类型的属性注入

 (1) List 数组

 (2)Set 集合

(3) Map

(3)Properties

使用多个XML配置文件

方式一:可以在创建ApplicationContext对象时传入多个配置文件。
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans1.xml", "beans2.xml");
方式二:可以在配置文件中通过<import>引入其他配置文件
<import resource="classpath:bean2.xml"/>
  实例代码如下:
在src下新建两个Spring的配置文件

CollectionBean
[java]  view plain  copy
 
  1. package lx.test.spring.demo6;  
  2.   
  3. import java.util.List;  
  4. import java.util.Map;  
  5. import java.util.Properties;  
  6. import java.util.Set;  
  7.   
  8. public class CollectionBean {  
  9.     private List<String> list;  
  10.     private Set<String> set;  
  11.     private Map<String, Integer> map;  
  12.     private Properties properties;  
  13.   
  14.     public void setList(List<String> list) {  
  15.         this.list = list;  
  16.     }  
  17.   
  18.     public void setSet(Set<String> set) {  
  19.         this.set = set;  
  20.     }  
  21.   
  22.     public void setMap(Map<String, Integer> map) {  
  23.         this.map = map;  
  24.     }  
  25.   
  26.     public void setProperties(Properties properties) {  
  27.         this.properties = properties;  
  28.     }  
  29.   
  30.     @Override  
  31.     public String toString() {  
  32.         return "CollectionBean [list=" + list + ",\n set=" + set + ",\n map=" + map  
  33.                 + ",\n properties=" + properties + "]";  
  34.     }  
  35.   
  36. }  
SpringTest6
[java]  view plain  copy
 
  1. package lx.test.spring.demo6;  
  2.   
  3. import org.junit.Test;  
  4. import org.springframework.context.ApplicationContext;  
  5. import org.springframework.context.support.ClassPathXmlApplicationContext;  
  6.   
  7.   
  8. public class SpringTest6 {  
  9.     @Test  
  10.     public void demo1(){  
  11.         ApplicationContext applicationContext = new ClassPathXmlApplicationContext(  
  12.                 "applicationContext.xml");  
  13.         CollectionBean collectionBean = (CollectionBean) applicationContext.getBean("collectionBean");  
  14.         System.out.println(collectionBean);  
  15.     }  
  16. }  
applicationContext.xml
[html]  view plain  copy
 
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  4.     xsi:schemaLocation="  
  5. http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">  
  6.   
  7.     <import resource="classpath:applicationContext2.xml" />  
  8. </beans>  
applicationContext2.xml
[html]  view plain  copy
 
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3.     xmlns:p="http://www.springframework.org/schema/p" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  4.     xsi:schemaLocation="  
  5. http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">  
  6.   
  7.     <!-- 集合属性的注入 -->  
  8.     <bean id="collectionBean" class="lx.test.spring.demo6.CollectionBean">  
  9.         <!-- 注入List集合 -->  
  10.         <property name="list">  
  11.             <list>  
  12.                 <value>武藤兰</value>  
  13.                 <value>桐谷静香</value>  
  14.             </list>  
  15.         </property>  
  16.   
  17.         <!-- 注入Set集合 -->  
  18.         <property name="set">  
  19.             <set>  
  20.                 <value>小泽</value>  
  21.                 <value>苍老师</value>  
  22.             </set>  
  23.         </property>  
  24.         <!-- 注入Map集合 -->  
  25.         <property name="map">  
  26.             <map>  
  27.                 <entry key="小咪咪" value="123" />  
  28.                 <entry key="小胡子 " value="456" />  
  29.             </map>  
  30.         </property>  
  31.   
  32.         <property name="properties">  
  33.             <props>  
  34.                 <prop key="username">root</prop>  
  35.                 <prop key="password">123456</prop>  
  36.             </props>  
  37.         </property>  
  38.     </bean>  
  39.   
  40. </beans>  
运行测试类

IOC容器装配Bean(注解方式)

Spring注解装配Bean

Spring2.5引入使用注解去定义Bean:
@Component描述Spring框架中Bean

 需要在配置文件中引用Context的Schema名称空间,在解压后的dist包中搜索 xsd-config.html文件,打开后找到context的名称空间约束如下所示:

配置如下所示:

如果不使用XML注册Bean 单纯使用注解声明Bean的话,不需要使用<context:annotation-config>标签,只需要配置自动扫描即可。<context:annotation-config>标签仅仅适用于XML和注解混搭使用时才需要的。
除了@Component外,Spring提供了3个功能和@Component等效的注解,如下所示:
  • @Repository用于对DAO实现类进行标注。
  • @Service用于对Service实现类进行标注。
  • @Controller用于对Controller实现类进行标注。
以上三个注解是为了让标注类本身的用途清晰,Spring在后续的版本会对其增强。

自动装配Bean

使用@Autowired进行自动注入,使用@Service标注业务类,@Repository标注DAO。@Autowired默认按照类型进行注入,如果存在两个相同的Bean类型相同,则按照名称注入。@Autowired注入时可以针对成员变量或者setter方法

注意:如果在使用注解标识Bean的情况下,如果没有显式的指定Bean的name名称,那么在使用applicationContext获取Bean对象时,它的name默认是这个Bean类名称的驼峰式写法,并且需要指定是哪个类,如下所示:

通过@Autowired的required属性,设置一定要找到匹配的Bean,如果设置为true,一旦找不到所匹配的Bean类型就会抛出异常,默认是true。如果设置成false的话,即使搜索不到所匹配的Bean类也不会报错。
使用@Qualifier指定注入Bean的名称,必须注意的是使用@Qualifier指定Bean名称后,注解Bean必须指定相同的名称,如下图所示:

对于普通属性使用@Value,另外Spring提供对JSR-250中定义@Resource标准注解的支持,@Resource和@Autowired注解功能类似,@Autowired和@Qualifier结合使用等价于@Resource。@Qualifier意思是按照名称进行注入。

指定Bean的初始化和销毁方法

Spring初始化Bean或销毁Bean时,有时需要作一些处理工作,因此Spring可以在创建和拆卸Bean的时候调用Bean的两个生命周期方法。如下图所示:

Bean的作用范围@Scope

使用注解配置的Bean和<bean>的配置一样,默认作用范围都是singleton,@Scope注解用于指定Bean的作用范围。

示例代码如下:
UserDao
[java]  view plain  copy
 
  1. package spring3.annotation.demo1;  
  2.   
  3. import org.springframework.stereotype.Repository;  
  4.   
  5. @Repository("userDao")  
  6. public class UserDao {  
  7.   
  8. }  
UserService
[java]  view plain  copy
 
  1. package spring3.annotation.demo1;  
  2.   
  3. import javax.annotation.PostConstruct;  
  4. import javax.annotation.PreDestroy;  
  5. import javax.annotation.Resource;  
  6.   
  7. import org.springframework.beans.factory.annotation.Autowired;  
  8. import org.springframework.beans.factory.annotation.Qualifier;  
  9. import org.springframework.beans.factory.annotation.Value;  
  10. import org.springframework.context.annotation.Scope;  
  11. import org.springframework.stereotype.Component;  
  12. import org.springframework.stereotype.Service;  
  13.   
  14. /** 
  15.  * 注解的方式装配Bean 
  16.  */  
  17. // @Component、@Service以及@Repository的功能就是注册Bean类  
  18. // 相当于XML中的如下配置  
  19. // <bean id="userService" class="spring3.annotation.demo1.UserService" />  
  20.   
  21. // @Component(value = "userService")  
  22. @Service  
  23. @Scope  
  24. public class UserService {  
  25.     // @Value注解是注入Bean类中的普通属性 相当于XML中的<property name="" value="">  
  26.     @Value(value = "annotationInfo")  
  27.     private String info;  
  28.   
  29.     // @Autowired(required=true)  
  30.     // @Qualifier("userDao")  
  31.     // 注意:@Autowired和@Qualifier结合相当于@Resource  
  32.     @Resource(name = "userDao")  
  33.     private UserDao userDao;  
  34.   
  35.     public void sayHello() {  
  36.         System.out.println("Hello Spring Annotation..." + info);  
  37.     }  
  38.   
  39.     @PostConstruct  
  40.     // @PostConstruct相当于 XML中<bean> 的属性 init-method=""  
  41.     public void setup() {  
  42.         System.out.println("初始化...");  
  43.     }  
  44.   
  45.     @PreDestroy  
  46.     // @PreDestroy相当于XML中<bean>的属性 destroy-method=""  
  47.     public void teardown() {  
  48.         System.out.println("销毁...");  
  49.     }  
  50.   
  51. }  
SpringTest1
[java]  view plain  copy
 
  1. package spring3.annotation.demo1;  
  2.   
  3. import org.junit.Test;  
  4. import org.springframework.context.support.ClassPathXmlApplicationContext;  
  5.   
  6. // 注解的方式  
  7. public class SpringTest1 {  
  8.     @Test  
  9.     public void demo1() {  
  10.         ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext(  
  11.                 "applicationContext.xml");  
  12.   
  13.         UserService userService = (UserService) applicationContext  
  14.                 .getBean("userService",UserService.class);  
  15.         System.out.println(userService);  
  16.         UserService userService2 = (UserService) applicationContext  
  17.                 .getBean("userService",UserService.class);  
  18.         System.out.println(userService2);  
  19.         applicationContext.close();  
  20.     }  
  21. }  
applicationContext.xml
[html]  view plain  copy
 
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"  
  4.     xsi:schemaLocation="  
  5. http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd  
  6. http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">  
  7.   
  8.     <context:component-scan base-package="spring3.annotation.demo1" />  
  9. </beans>  
注意:<context:component-scan base-package="">会扫描当前包下的所有类的注解以及所有子包的类注解。
运行结果如下:

Spring3.0提供使用Java类提供Bean定义信息

Spring3.0以JavaConfig为核心,提供使用Java类定义Bean信息的方法。
  • @Configuration指定POJO类为Spring提供Bean定义信息
  • @Bean提供一个Bean定义信息

如果在Spring的配置文件中配置了<context:component base-package="">按照包进行注解扫描的属性标签,则无需再手动加载配置类。否则需要手动加载@Configuration配置类。手动加载配置类如下所示:
  • Spring提供AnnotationConfigApplicationContext用于加载使用@Configuration配置注解工厂类。
  • register方法用于向注解上下文对象添加一个配置类。
  • refresh刷新容器以应用这些注册的配置类。

如果采用了手动加载@Configuration配置类的情况,即使没有Spring配置文件也能照常运行。
示例代码如下:
Car
[java]  view plain  copy
 
  1. package spring3.annotation.demo2;  
  2.   
  3. public class Car {  
  4.     private String name;  
  5.     private Double price;  
  6.   
  7.     public void setName(String name) {  
  8.         this.name = name;  
  9.     }  
  10.   
  11.     public void setPrice(Double price) {  
  12.         this.price = price;  
  13.     }  
  14.   
  15.     @Override  
  16.     public String toString() {  
  17.         return "Car [name=" + name + ", price=" + price + "]";  
  18.     }  
  19.   
  20. }  
Product
[java]  view plain  copy
 
  1. package spring3.annotation.demo2;  
  2.   
  3. public class Product {  
  4.     private String name;  
  5.     private Double price;  
  6.   
  7.     public void setName(String name) {  
  8.         this.name = name;  
  9.     }  
  10.   
  11.     public void setPrice(Double price) {  
  12.         this.price = price;  
  13.     }  
  14.   
  15.     @Override  
  16.     public String toString() {  
  17.         return "Product [name=" + name + ", price=" + price + "]";  
  18.     }  
  19. }  
BeanConfig
[java]  view plain  copy
 
  1. package spring3.annotation.demo2;  
  2.   
  3. import org.springframework.context.annotation.Bean;  
  4. import org.springframework.context.annotation.Configuration;  
  5.   
  6. @Configuration  
  7. public class BeanConfig {  
  8.   
  9.     @Bean(name = "car")  
  10.     public Car showCar() {  
  11.         Car car = new Car();  
  12.         car.setName("大众");  
  13.         car.setPrice(200000d);  
  14.         return car;  
  15.     }  
  16.   
  17.     @Bean(name = "product")  
  18.     public Product initProduct() {  
  19.         Product product = new Product();  
  20.         product.setName("空调");  
  21.         product.setPrice(3000d);  
  22.         return product;  
  23.     }  
  24.   
  25. }  
applicationContext.xml
[html]  view plain  copy
 
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"  
  4.     xsi:schemaLocation="  
  5. http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd  
  6. http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">  
  7.   
  8.     <context:component-scan base-package="spring3.annotation.demo2" />  
  9. </beans>  
SpringTest2
[java]  view plain  copy
 
  1. package spring3.annotation.demo2;  
  2.   
  3. import org.junit.Test;  
  4. import org.springframework.context.annotation.AnnotationConfigApplicationContext;  
  5. import org.springframework.context.support.ClassPathXmlApplicationContext;  
  6.   
  7. public class SpringTest2 {  
  8.     @Test  
  9.     // 加载XML配置文件 (配置了进行自动扫描注解类)  
  10.     public void demo1() {  
  11.         ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext(  
  12.                 "applicationContext.xml");  
  13.         Car car = (Car) applicationContext.getBean("car");  
  14.         Product product = (Product) applicationContext.getBean("product");  
  15.         System.out.println(car);  
  16.         System.out.println(product);  
  17.     }  
  18.   
  19.     @Test  
  20.     // 不使用Spring的配置文件,手动注册config类  
  21.     public void demo2() {  
  22.         AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();  
  23.         applicationContext.register(BeanConfig.class);  
  24.         applicationContext.refresh(); // 刷新容器以应用这些注册的配置类  
  25.         Car car = (Car) applicationContext.getBean("car");  
  26.         Product product = (Product) applicationContext.getBean("product");  
  27.         System.out.println(car);  
  28.         System.out.println(product);  
  29.     }  
  30. }  
运行结果:

传统XML配置和注解配置混合使用

如果混合使用,一般使用XML注册Bean 进行Bean的管理,使用注解进行属性的注入。混合使用配置方法如下:
1、引入context命名空间
2、在配置文件中添加<context:annotation-config>标签
注意:单独使用注解声明注册Bean的话只需要配置扫描的标签,混合使用时只需要使用<context:annotation-config>
示例代码如下:
CustomerDao
[java]  view plain  copy
 
  1. package spring3.annotation.demo3;  
  2.   
  3. public class CustomerDao {  
  4.   
  5. }  
 OrderDao
[java]  view plain  copy
 
  1. package spring3.annotation.demo3;  
  2.   
  3. public class OrderDao {  
  4.   
  5. }  
CustomerService
[java]  view plain  copy
 
  1. package spring3.annotation.demo3;  
  2.   
  3. import org.springframework.beans.factory.annotation.Autowired;  
  4. import org.springframework.beans.factory.annotation.Qualifier;  
  5.   
  6. public class CustomerService {  
  7.     private CustomerDao customerDao;  
  8.     @Autowired  
  9.     @Qualifier("orderDao")  
  10.     private OrderDao orderDao;  
  11.       
  12.     public void setCustomerDao(CustomerDao customerDao) {  
  13.         this.customerDao = customerDao;  
  14.     }  
  15.     @Override  
  16.     public String toString() {  
  17.         return "CustomerService [customerDao=" + customerDao + ", orderDao="  
  18.                 + orderDao + "]";  
  19.     }  
  20.       
  21.   
  22. }  
applicationContext2.xml
[html]  view plain  copy
 
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"  
  4.     xsi:schemaLocation="  
  5. http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd  
  6. http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">  
  7.   
  8.     <context:annotation-config />  
  9.     <bean id="customerDao" class="spring3.annotation.demo3.CustomerDao" />  
  10.     <bean id="orderDao" class="spring3.annotation.demo3.OrderDao" />  
  11.   
  12.     <bean id="customerService" class="spring3.annotation.demo3.CustomerService">  
  13.         <property name="customerDao" ref="customerDao" />  
  14.         <!-- <property name="orderDao" ref="orderDao" /> -->  
  15.     </bean>  
  16.   
  17. </beans>  
SpringTest3
[java]  view plain  copy
 
  1. package spring3.annotation.demo3;  
  2.   
  3. import org.junit.Test;  
  4. import org.springframework.context.ApplicationContext;  
  5. import org.springframework.context.support.ClassPathXmlApplicationContext;  
  6.   
  7.   
  8. public class SpringTest3 {  
  9.     @Test  
  10.     public void demo1() {  
  11.         ApplicationContext applicationContext = new ClassPathXmlApplicationContext(  
  12.                 "applicationContext2.xml");  
  13.         CustomerService customerService = (CustomerService) applicationContext  
  14.                 .getBean("customerService");  
  15.         System.out.println(customerService);  
  16.     }  
  17. }  
运行结果如下:

多种装配Bean方式比较

Spring整合web开发

正常整合Servlet和Spring是没有问题的,但是每次执行Servlet的时候都会加载Spring配置,加载Spring环境。
解决方法:在Servlet的init方法中加载Spring配置文件,这种方法虽然可以解决每次请求都会加载Spring配置的问题,但是只能应用于当前的Servlet,其他的Servlet无法使用。所以最好的方法是将加载的信息内容放到ServletContext中。ServletContext对象是全局对象,在服务器启动的时候创建的,在创建ServletContext的时候就加载Spring环境。
ServletContextListener:用于监听ServletContext对象的创建和销毁的。
web应用中使用Spring的步骤如下:
1、导入响应的jar包
导入Spring开发基本的jar包:spring-beans-3.2.0.RELEASE.jar、spring-context-3.2.0.RELEASE.jar、spring-core-3.2.0.RELEASE.jar、spring-expression-3.2.0.RELEASE.jar
导入日志相关jar包:commons-logging-1.1.1.jar、com.springsource.org.apache.log4j-1.2.15.jar
导入Spring web开发的jar包:spring-web-3.2.0.RELEASE.jar
2、配置web.xml
将Spring容器初始化,交由web容器负责。
配置核心监听器ContextLoaderListener(ContextLoaderListener实现了ServletContextListener接口)。
配置全局参数contextConfigLocation,用于指定Spring框架的配置文件的位置。

3、获得WebApplicationContext对象
因为Spring容器已经交由web容器初始化和管理。
获得WebApplicationContext对象,需要依赖ServletContext对象。通常在Servlet中完成
WebApplicationContext applicationContext=WebApplicationContextUtils.getWebApplicationContext(getServletContext());
还可以用另外一种方式进行获取
WebApplicationContext applicationContext=(WebApplicationContext)getServletContext().getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
示例代码如下:


UserService
[java]  view plain  copy
 
  1. package spring3.web.service;  
  2.   
  3. public class UserService {  
  4.     public void sayHello() {  
  5.      System.out.println("Hello Spring web...");  
  6.     }  
  7. }  
UserServlet
[java]  view plain  copy
 
  1. package spring3.web.servlet;  
  2.   
  3. import java.io.IOException;  
  4.   
  5. import javax.servlet.ServletException;  
  6. import javax.servlet.http.HttpServlet;  
  7. import javax.servlet.http.HttpServletRequest;  
  8. import javax.servlet.http.HttpServletResponse;  
  9.   
  10. import org.springframework.web.context.WebApplicationContext;  
  11. import org.springframework.web.context.support.WebApplicationContextUtils;  
  12.   
  13. import spring3.web.service.UserService;  
  14.   
  15. public class UserServlet extends HttpServlet {  
  16.   
  17.     public void doGet(HttpServletRequest request, HttpServletResponse response)  
  18.             throws ServletException, IOException {  
  19.         /*ApplicationContext applicationContext = new ClassPathXmlApplicationContext( 
  20.         "applicationContext.xml");*/  
  21.         WebApplicationContext applicationContext=WebApplicationContextUtils.getWebApplicationContext(getServletContext());  
  22.           
  23.         UserService userService=(UserService) applicationContext.getBean("userService");  
  24.         userService.sayHello();  
  25.     }  
  26.   
  27.     public void doPost(HttpServletRequest request, HttpServletResponse response)  
  28.             throws ServletException, IOException {  
  29.   
  30.         doGet(request, response);  
  31.     }  
  32.   
  33. }  
web.xml
[html]  view plain  copy
 
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  3.     xmlns="http://java.sun.com/xml/ns/javaee"  
  4.     xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"  
  5.     id="WebApp_ID" version="3.0">  
  6.   
  7.    <listener>  
  8.     <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>  
  9.    </listener>  
  10.    <servlet>  
  11.       <servlet-name>UserServlet</servlet-name>  
  12.       <servlet-class>spring3.web.servlet.UserServlet</servlet-class>  
  13.    </servlet>  
  14.   
  15.   <servlet-mapping>  
  16.     <servlet-name>UserServlet</servlet-name>  
  17.     <url-pattern>/user</url-pattern>  
  18.   </servlet-mapping>  
  19.   <context-param>  
  20.     <param-name>contextConfigLocation</param-name>  
  21.     <param-value>classpath:applicationContext.xml</param-value>  
  22.   </context-param>  
  23.   <welcome-file-list>  
  24.     <welcome-file>index.jsp</welcome-file>  
  25.   </welcome-file-list>  
  26. </web-app>  
applicationContext.xml
[html]  view plain  copy
 
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  4.     xsi:schemaLocation="  
  5. http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">  
  6.     <bean id="userService" class="spring3.web.service.UserService" />  
  7.   
  8. </beans>  
log4j.properties
[plain]  view plain  copy
 
  1. ### direct log messages to stdout ###  
  2. log4j.appender.stdout=org.apache.log4j.ConsoleAppender  
  3. log4j.appender.stdout.Target=System.err  
  4. log4j.appender.stdout.layout=org.apache.log4j.PatternLayout  
  5. log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n  
  6.   
  7. ### direct messages to file mylog.log ###  
  8. log4j.appender.file=org.apache.log4j.FileAppender  
  9. log4j.appender.file.File=c\:mylog.log  
  10. log4j.appender.file.layout=org.apache.log4j.PatternLayout  
  11. log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n  
  12.   
  13. ### set log levels - for more verbose logging change 'info' to 'debug' ###  
  14.   
  15. log4j.rootLogger=info, stdout   
访问Servlet 后台打印如下:

使用Junit测试Spring程序

导入Spring test测试jar包,需要导入spring-test-3.2.0.RELEASE.jar

示例代码如下:将applicationContext.xml中的命名空间改为Context的命名空间。导入整合Junit的jar包

你可能感兴趣的:(JAVAWEB开发之Spring详解之——Spring的入门以及IOC容器装配Bean(xml和注解的方式)、Spring整合web开发、整合Junit4测试)