基础1:IOC、DI、Bean

本文深入探讨Spring框架中的IOC(控制反转)和DI(依赖注入)概念,讲解Bean的配置方式、容器类型、依赖注入策略、作用域、生命周期管理等核心知识点。同时,介绍了如何使用注解简化配置,以及Spring4.x中的新特性。

IOC&DI

IOC(Inversion of Control),其思想是反转资源获取的方向。传统的资源查找方式要求组件向容器发起请求查找资源,作为回应呢,容器适时的返回资源,而应用了IOC之后,则是容器主动的将资源推送给它所管理的组件,组件所要做的仅仅是选择一种合适的方式来接受资源,这种行为也被称为查找的被动形式。

DI(Dependency Injection),IOC的另一种表达方式:即组件以一些预先定义好的方式,例如:setter方法,接受来自如容器的资源注入。

配置Bean

 

 

Bean配置方式

通过全类名(反射)、通过工厂方法(静态工厂方法&实例工厂方法)、FactoryBean

IOC容器

BeanFactory、ApplicationContext

依赖注入方式

属性注入、构造器注入

注入属性值细节

 

自动转配

 

Bean之间的关系

继承、依赖

Bean的作用域

singleton、prototype、web环境作用域

使用外部属性文件

 

spEL

 

IOC容器中Bean的生命周期

 

Spring4.x新特性

泛型依赖注入

配置Bean-知识点1:Bean整体配置思路

整体配置思路就2个:基于XML文件的方式、基于注解的方式

id标识容器中的Bean,id必须是唯一的。

class是类的全类名,通过反射的方式在IOC容器中创建Bean,所以要求Bean中必须有无参数的构造器。

配置Bean-知识点2:Spring容器

在Spring IOC容器读取Bean配置并创建Bean实例之前,必须对它进行实例化,只有在容器实例化之后,才可以从IOC容器里获取Bean实例并使用。

Spring提供了2种类型的IOC容器:

①BeanFactory:IOC容器的基本实现;

②ApplicationContext:提供了更多的高级特性,是BeanFactory的子接口;

总结:BeanFactory是Spring框架的基础设施,面向Spring本身;ApplicationContext面向使用Spring框架的开发者,因此大多数场景都直接使用ApplicationContext,而不是底层的BeanFactory,无论哪种方式,其配置文件都是一样的。

配置Bean-知识点3:ApplicationContext

ApplicationContext的主要的实现类:

①ClassPathXmlApplicationContext:从类路径下加载配置文件;

②FileSystemXmlApplicationContext:从文件系统中加载配置文件;

注意事项:

①ConfigurableApplicationContext扩展了Application-
Context,新增2个方法:refresh()和close()方法,从而让ApplicationContext具有启动、刷新、关闭上下文的能力。

②ApplicationContext在初始化上下文时,就实例化所有单例的Bean。

③WebApplicationContext是专门为Web应用而准备的,允许从相对于web根目录的路径中完成初始化工作。

配置Bean-知识点4:依赖注入方式

3种依赖注入方式:属性注入、构造器注入、工厂方法注入(不推荐)。

①属性注入本质是通过setter方法注入Bean的属性值/依赖的对象。属性注入使用<property/>元素,使用name属性来指定Bean的属性名,value属性/<value/>子节点指定属性值。

这种属性注入是应用最广泛的注入方式。

当我把setName注释掉之后,系统报错,也从侧面证明其是用过setter方法来设置属性值的:

注意:

系统也能正常执行,这说明:Spring先获取name属性值,然后在属性值的基础上再添加set前缀,例如:name=name22,其实在Bean中并没有name22这个属性,但还是能执行成功,说明Spring关心的是setXXXX中的XXXX,而不是Bean中具体的某个属性名

②构造方法注入是通过构造方法注入Bean的属性值/依赖对象,保证了Bean实例在实例化后就可以使用。构造器注入在<constructor-arg/>元素里声明属性name、index、type来说明参数值。

 

配置Bean-知识点5:字面值

在知识点4中学习了依赖注入方式,但是,在设置value属性时,则还有另外的知识点。

字面值:可用字符串表示的值,可以通过<value/>子标签或value属性进行注入,其中基本数据类型及其封装类、String等类型都可以采取字面值注入的方式,但是,如果字面值中包含特殊字符,则必须使用<![CDATA[字面值]]>把字面值包裹起来。

配置Bean-知识点6:引用其它Bean

要使Bean能够互相访问,就必须在Bean配置文件中指定对Bean的引用。在Bean的配置文件中,可以通过<ref/>标签或者ref属性来为Bean的属性或构造器参数指定对某个Bean的引用。

这种在属性或者构造器里包含的Bean的声明,这样的Bean称为内部Bean。内部Bean,不管有没有id属性,都无法被外部引用,只能被内部使用。

配置Bean-知识点7:null值和级联属性

针对null值,可以使用专用的<null/>标签为Bean的字符串或其他对象类型的属性来注入null值。

Spring也支持级联属性

这里在使用级联属性时,必须首先初始化属性car,然后才能为级联属性car.weight赋值,否则会出现异常。

配置Bean-知识点8:集合属性

Spring可以通过一组内置的XML标签,例如<list/>、<set/>、<map/>来配置集合属性。

初始化java.util.List类型的属性,需要使用<list/>标签,在标签内包含一些元素,而这些元素可以通过<value/>指定简单的常量值,也可以通过<ref/>指定对其他Bean的引用,也可以通过<bean/>指定内置Bean定义,也可以通过<null/>指定空元素,甚至可以内嵌其他集合。

初始化数组类型的属性跟List一样,都使用<list/>。

初始化java.util.Set类型的属性,需要使用<set/>标签,定义元素的方法与<list/>一样。

初始化java.util.Map类型的属性,需要使用<map/>标签定义,<map/>标签内部包含多个<entry/>子标签,每一个<entry/>子标签只能包含一个键盘和一个值;在<key/>标签里定义键,因为键和值的类型没有限制,因此可以自由地为键和值使用<value/>、<ref/>、<bean/>、<null/>元素,当然,也可以将Map的键和值作为<entry/>的属性来定义:简单常量使用key和value来定义,Bean引用通过key-ref和value-ref属性来定义。

初始化java.util.Properties类型的属性,可以使用<props/>标签来定义,该标签内部包含多个<prop>作为子标签,每个<prop>标签必须定义key属性。

配置Bean-知识点9:使用utility scheme定义集合

使用基本的集合标签来定义集合时,不能将集合作为独立的Bean定义,进而导致其他Bean无法引用该集合,所以无法在不同Bean之间共享集合,为了解决这个问题,可以使用util schema里的集合标签定义独立的集合Bean,需要注意的是,必须在<beans>根元素里添加util schema定义。

说白了就是通过util schema来把集合独立出来,作为一个共享资源来被其他Bean使用。

 

配置Bean-知识点10:使用p命名空间

为了简化XML文件的配置,越来越多的XML文件采用属性,而不是子元素来配置信息。因此,从Spring2.5开始引入了一个新的命名空间p,来通过<bean>元素属性的方式配置Bean的属性,因此,在使用p命名空间之后,基于XML的配置方式将进一步简化。

通过截图,我们可以返现,P命名空间可以大幅度减少开发人员代码量。

配置Bean-知识点11:自动装配

XML配置里的Bean自动装配,指的是Spring IOC容器可以自动装配Bean,这里的自动装配你可以理解为把XXX-ref=YYYY这种显示配置给删掉,然后IOC容器自己来完成这块工作,而我们需要做的仅仅是在<bean>的autowire属性里指定自动装配的模式,autowire取值范围如下:

①byType根据类型自动装配:若IOC容器中有多个与目标Bean类型一致的Bean,这种情况下,Spring将无法判定哪个Bean最适合该属性,所以不能执行自动装配;

核心在于,假如当前Bean中定义了一个XXXX类型的变量,那么,自动装配的时候,就去查找class=”XXXX”的<bean/>,如果能找到且只有1个,则自动装配,如果没找到/IOC容器有2个及以上的类型匹配的Bean,则抛出异常。

②byName根据名称自动装配:必须将目标Bean的名称,与属性名设置的完全相同;

核心在于,假如当前Bean中定义了一个setXXXX的方法,那么,自动装配的时候,就去查找id=”XXXX”的<bean/>,如果能找到且只有1个,则自动装配,如果没找到/IOC容器有2个及以上的id匹配的Bean,则抛出异常。

③constructor通过构造器自动装配:当Bean中存在多个构造器时,这种自动装配方式将会很复杂,因此不推荐使用。

自动装配的缺点在于:

①在Bean配置文件里设置autowire属性进行自动装配将会装配Bean的所有属性,然而,如果只希望装配个别几个属性时,autowire则不够灵活。

②autowire属性,要么根据类型自动装配,要么根据名称自动装配,只能二选一,不能同时选择。

③实际开发中,自动装配用的很少,因为明确清晰的配置会减少不必要问题,进而减少为了解决这些问题而花费的时间、精力等。

配置Bean-知识点12:bean之间的关系

Bean之间的关系就2种:继承、依赖。

①继承:这里的继承,指的是Spring配置上的继承,而不是JAVA语法上的继承。Spring允许继承<bean/>的配置,被继承的<bean/>称为父<bean/>,继承这个父<bean/>的<bean/>称为子<bean/>。

子<bean/>从父<bean/>中继承配置,包括<bean/>的属性配置,当然,子<bean/>也可以覆盖从父<bean/>继承过来的配置,需要注意的是,并不是父<bean/>里所有属性都会被继承,比如autowire、abstract就不会被继承;子<bean/>也可以忽略父<bean/>的class属性,让子<bean/>指定自己的类,而共享相同的属性配置,但前提是父<bean/>的abstract=true。

父<bean/>可以作为配置模板,也可以作为<bean/>实例,如果只想把父<bean/>作为模板,则可以设置<bean/>的abstract属性为true,这样Spring将不会实例化该<bean/>。

注意:当某个<bean/>的abstract=true时,可以不填写class属性。

②依赖:Spring允许用户通过depends-on属性来设定Bean前置依赖的Bean,前置依赖的Bean会在当前Bean实例化之前提前创建好。如果前置依赖于多个Bean,则可以通过逗号或者空格方式来配置Bean的名称。

注意:我在People中定义了变量food,但我在XML中并没有为food设置p:food-ref,所以在println中food=null,因此这里的“依赖”指的是实例的创建,而不是实例的创建 + 注入。

注入动作是额外的,需要通过p或者<property/>来注入。

配置Bean-知识点13:bean的作用域

Spring IOC容器中,针对<bean/>默认都是单例的,即工程中通过id来获取的JAVA实例都是同一个实例。

为了适应不同场景下对实例的要求,这里涉及到bean的作用域scope问题,在<bean/>中有scope属性,该属性取值范围如下:

①prototype原型:容器初始化时不创建Bean的实例,而是在每次请求时都创建一个新的Bean实例,并返回。即什么时候用,就什么时候新建一个bean实例并返回给调用者,每次调用,每次新new一个实例,每次都不通。

②request:request只用于web程序,通常是和XmlWeb-

ApplicationContext共同使用。即XmlWebApplicationContext 会为每个HTTP请求创建一个全新的RequestPrecessor对象,当请求结束后,该对象的生命周期即告结束,如同java web中request的生命周期。当同时有100个HTTP请求进来的时候,容器会分别针对这10个请求创建10个全新的RequestPrecessor实例,且他们相互之间互不干扰,简单来讲,request可以看做prototype的一种特例。

③session:session只用于web程序,通常是和XmlWeb-

ApplicationContext共同使用。对于web应用来说,放到session中最普遍的就是用户的登录信息,对于这种放到session中的信息,Spring容器会为每个独立的session创建属于自己的全新的UserPreferences实例,比request scope的bean会存活更长的时间,其他的方面没区别。

④singleton单例:默认值,容器初始化时创建bean实例,在整个容器的生命周期内只创建一个bean,单例的。

配置Bean-知识点14:使用外部属性文件

在XML配置文件里配置Bean时,有时需要在Bean的配置里混入系统部署的信息(例如:文件路径、数据源配置信息等),而这些部署细节实际上需要和Bean配置相分离(通俗来讲就是你XML不可能满足我全部的配置要求,这就需要我新建其他格式的文件来配置这些要求)。

为了解决这种情况,Spring提供了一个PropertyPlaceholderConfigurer的BeanFactory后置处理器,这个处理器允许用户将Bean配置的一部分内容迁移到属性文件properties中,然后可以在bean配置XML文件中使用形式为${var}的变量,PropertyPlaceholderConfigurer从属性文件里去加载属性,并使用这些属性来替换变量。

Spring还允许在属性文件中使用${propName},来实现属性文件之间的相互引用。

这里需要使用context命名空间来完成该功能:

配置Bean-知识点15:SpEL

Spring表达式语言,简称SpEL,是一个支持运行时查询、操作对象图的强大的表达式语言,SpEL使用#{XXXX}来作为定界符,XXXX就是SpEL内容,SpEL为<bean/>属性的动态赋值提供了便利,通过SpEL可以实现如下效果:

通过<bean/>的id来对bean进行引用、调用方法以及引用对象中的属性、计算表达式的值、正则表达式匹配。

SpELDemo{age=12, fraction=85.7, name='ZhangSan', address='USA', enabled=false, weight=100, pi='3.141592653589793', foolName='apple', carName='1.5', carWeight=4000, carWeightHeavy=true, carHeigth=true, carFactory='HongQi', carWidth='2M', car=Car{length='5.5', width='2', heigh='1.5', weight=2000}, food=Food{name='apple'}}

配置Bean-知识点16:IOC容器中Bean的生命周期方法

Spring IOC容器可以管理Bean的生命周期,Spring允许在Bean生命周期的特定时间节点执行个人定制的任务。Spring IOC容器对Bean的生命周期进行管理的过程:

①通过构造器或者工厂方法创建Bean实例;

②为Bean的属性设置值以及对其他Bean的引用;

③调用Bean的初始化方法,初始化方法可以在<bean/>的init-method属性来指定初始化方法;

④Bean可以使用;

⑤当容器关闭时,调用Bean的销毁方法,销毁方法可以在<bean/>的destroy-method属性来指定销毁方法;

配置Bean-知识点17:创建Bean的后置处理器

Bean后置处理器,允许在调用初始化方法init-method前后对Bean进行额外的处理。Bean后置处理器对IOC容器里的所有Bean实例逐一处理,而非单一实例,典型应用就是检查Bean属性的正确性或者根据特定的标准更改Bean的属性。

对Bean后置处理器而言,需要实现BeanPostProcessor接口,在初始化方法init-method被调用前后,Spring将把每个Bean实例分别传递给上述接口的以下2个方法:

postProcessAfterInitialization

postProcessBeforeInitialization

当添加Bean后置处理器后,Spring IOC容器对Bean的生命周期进行管理的过程如下:

①通过构造器或工厂方法创建Bean实例;

②为Bean的属性设置值和对其他Bean的引用;

③将Bean实例传递给Bean后置处理器的postProcessBeforeInitialization方法;

④调用Bean的init-method指定的方法;

⑤将Bean实例传递给Bean后置处理器的postProcessAfterInitialization方法;

⑥Bean可以使用;

⑦当容器关闭时,调用Bean 的destroy-method指定的方法;

注意:

①后置处理器在配置<bean/>的时候,不需要配置id属性,因为IOC容器自动识别是一个PostProcessor处理器;

②这里的beanname取自<bean/>的id属性。

配置Bean-知识点18:通过自定义工厂方法配置Bean

通过工厂方法配置Bean,可以分为2类:

①静态工厂方法:调用静态工厂方法创建Bean是将对象创建的过程封装到静态方法中。当客户端需要对象时,只需要简单地调用静态方法,而不用关心创建对象的细节。

要声明通过静态方法创建的Bean,需要在Bean的class属性里指定拥有该工厂方法的类,同时再factory-method属性里指定工厂方法的名称,最后再使用<constrctor-arg/>元素来为该方法传递方法参数。

注意:

这里在使用<constrctor-arg/>时,是基于静态工厂方法getProduct的,而不是new Product()的。

另外,class指向的工厂方法类ProductStaticFactory,但在getBean的时候强制类型转换的则是Product。

②实例工厂方法:将对象的创建过程封装到另外一个对象实例的方法里。当客户端需要请求对象时,只需要简单的调用该实例方法而不需要关心对象的创建细节。

要声明通过实例工厂方法创建的Bean,步骤如下:

  1. 在bean的factory-bean属性里指定拥有该工厂方法的Bean;
  2. 在factory-method属性里指定该工厂方法的名称;
  3. 使用construtor-arg元素来为工厂方法传递方法参数;

配置Bean-知识点19:通过FactoryBean配置Bean

知识点18的工厂类,是开发人员自定义的工厂类,但FactoryBean则是Spring自带的工厂类。FactoryBean相比于自定义工厂类的优点就是:方便使用其他已经定义好的Bean。

配置Bean-知识点20:基于注解方式来配置Bean

从知识点1~知识点19,虽然相比于过去,IOC配合XML文件减轻了很多工作量,但是,这个XML敲起来,真的很繁琐,例如编写id,class中编写全类名,还等其他各种属性。

为了进一步简化配置,让开发者把更多精力放到开发上,而不是配置上,Spring使用了注解方式来取代XML配置。

使用注解来取代XML配置,无外乎2个方面:

①基于注解配置Bean;

②基于注解来装配Bean的属性;

配置Bean-知识点21:基于注解配置Bean

现在说一下Spring注解的几个重点:

①在classpath中扫描组件:组件扫描指的是Spring能够从classpath下自动扫描,来侦测、实例化具有特定注解的组件。这些特定注解包括:

@Component:标识一个受Spring管理的组件;

@Repository:标识持久层组件;

@Service:标识服务层组件;

@Controller:标识表现层组件;

对于这些被扫描到的组件,Spring有默认的命名策略:使用非限定类名,第一个字母小写,也可以在注解中通过value属性值来标识组件的名称。

当在组件类上使用了特定的注解之后,还需要在Spring的配置文件中声明<context:component-scan>:

1>对base-package属性指定一个需要扫描的基类包,这时Spring容器将会扫描这个基类包以及子包中的所有类,当需要扫描多个包时,可以用逗号进行分隔;

2>如果仅仅希望扫描特定的类,而非基包下的所有类,可使用resource-pattern属性来过滤特定的类;

3><context:include-filter/>子节点表示要包含的目标类;

4><context:exclude-filter/>子节点表示要排除在外的目标类;

5><context:component-scan>下可以包含多个<context:include-filter/>和<context:exclude-filter/>子节点;

<context:include-filter/>和<context:exclude-filter/>子节点能支持多种类型的过滤表达式:

类别

说明

示例

annotation

所有标注了XXXAnnotation的类。该类型采用目标类是否标注了某个注解来进行过滤

com.suntj.XXXAnnotation

assignable

 

所有继承或扩展XXXService的类。该类型采用目标类是否继承或者扩展某个特定类进行过滤

com.suntj.XXXService

aspectj

所有类名以Service结束的类以及继承或扩展它们的类。该类型采用AspectJ表达式进行过滤

com.suntj.*Service+

regex

所有xx.xxx.xx包下的类。该类型采用正则表达式根据类的类名进行过滤。

com.\suntj.\anno\.*

custom

采用XXXTypeFilter通过代码的方式定义过滤规则。该类必须实现com.springframework.core.type.TypeFilter接口。

com.suntj.XXXTypeFilter

annotation

+++++++++++++++++++++++++++++++++++++++++++++++++++++++

assignable

配置Bean-知识点22:基于注解来装配Bean的属性

<context:component-scan/>元素还会自动注册Autowired-
AnnotationBeanPostProcessor实例,该实例可以自动装配具有@Autowired、@Resource、@Inject注解的属性。

@Autowired注解:自动装配具有兼容类型的单个Bean属性。具体细节如下:

  1. 构造器、普通字段(即使是非public)、一切具有参数的方法都可以应用@Autowired注解;
  2. 默认情况下,所有使用@Autowired注解的属性都需要被初始化,但是,当Spring找不到匹配的Bean来装配属性时,会抛出异常,如果想要某一属性允许不被初始化,可以设置@Autowired注解的required属性为false;
  3. 默认情况下,当IOC容器里存在多个类型兼容的Bean时,通过类型的自动装配将无法工作,此时可以在@Qualifier注解里提供Bean的名称,Spring允许对方法的入参标注@Qualifier来指定注入的Bean名称(当然,也可以使用属性名与value属性名来匹配);
  4. @Autowired注解也可以用在数组类型的属性上,此时Spring将会把所有匹配的Bean进行自动装配;
  5. @Autowired注解也可以用在集合属性上,此时Spring读取该集合的类型信息,然后自动装配所有与之兼容的Bean;
  6. @Autowired注解也可以用在java.util.Map上,如果该Map的key值是String,则Spring将自动装配与之Map值类型兼容的Bean,此时的Bean的名称就作为Map的key值,而Bean就是Map的value值;

package com.suntj.spring.annotation.component;

import com.suntj.spring.annotation.controller.TestController;

import com.suntj.spring.annotation.repository.TestRespository;

import com.suntj.spring.annotation.service.ITestService;

import com.suntj.spring.annotation.service.TestService;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.beans.factory.annotation.Qualifier;

import org.springframework.stereotype.Component;

@Component

public class TestComponent {

    @Autowired(required = false)

    private TestController tController;

    private TestRespository testRespository;

    @Autowired

    public void setTestRespository(TestRespository testRespository) {

        this.testRespository = testRespository;

    }

    /**

     * 我这里引用的是一个接口ITestService

     * 而该接口有2个实现类:TestService、TestService2

     * 要想解决取舍问题,目前有2个解决方法:

     * 方法1:ITestService变量的名字,与其中2个Service中某个value相同,那么Spring就会根据变量名去匹配;

     * 方法2:使用@Qualifier注解来明确匹配哪个Bean,里面填写value值;

     * */

    private ITestService iTestService;

    @Autowired

    public void setiTestService(

            @Qualifier("TestService")

            ITestService iTestService) {

        this.iTestService = iTestService;

    }

    public void out(){

        if(null != tController){

            tController.out();

        }

        testRespository.out();

        iTestService.out();

        System.out.println("TestComponent out.....");

    }

}

配置Bean-知识点23:泛型依赖注入

Spring4.X中可以为子类注入子类对应的泛型类型的成员变量的引用;

配置Bean-知识点24:所编写的XML代码

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

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

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

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

       xsi:schemaLocation="http://www.springframework.org/schema/beans

       http://www.springframework.org/schema/beans/spring-beans.xsd

       http://www.springframework.org/schema/util

   http://www.springframework.org/schema/util/spring-util-3.0.xsd

       http://www.springframework.org/schema/context

       http://www.springframework.org/schema/context/spring-context-4.0.xsd">

    <!-- 指定Spring IOC容器扫描的包

         resource-pattern="component/*.class"指的是,仅仅扫描component子包下的所有类

     -->

    <context:component-scan

            base-package="com.suntj.spring.annotation">

        <!-- 不包含org.springframework.stereotype.Component注解的类

        <context:exclude-filter

                type="annotation"

                expression="org.springframework.stereotype.Component"/>

         -->

        <!-- 只包含org.springframework.stereotype.Component注解的类

            如果使用自定义的filter,还需要把use-default-filters设置为false,意思是,不用Spring自带的filter,

            要用context:include-filter指定的filter

            <context:include-filter>需要use-default-filters属性一起配合使用

        <context:include-filter

                type="annotation"

                expression="org.springframework.stereotype.Repository"/>

         -->

        <!-- 只包含com.suntj.spring.annotation.service.ITestService实现类

        <context:include-filter

                type="assignable"

                expression="com.suntj.spring.annotation.service.ITestService"/>

         -->

    </context:component-scan>

<!-- 基于context命名空间,借助PropertyPlaceholderConfigurer来读取properties文件中的信息 -->

    <context:property-placeholder location="classpath:db.properties"/>

    <bean id="dataSource" class="com.suntj.spring.bean.DataSource"

        p:user="${user}" p:ip="${ip}" p:password="${password}" p:port="${port}"></bean>

    <bean id="persion" class="com.suntj.spring.bean.Persion">

        <property name="name" value="ZhangSan"/>

        <property name="age" value="30" />

        <property name="address" value="China" />

        <!-- 这是普通的Bean引用-->

        <property name="car" ref="car"/>

        <!-- 级联属性,即car的weight属性 -->

        <property name="car.weight" value="3600"/>

        <!-- 这是内部Bean

        <property name="car">

            <bean class="com.suntj.spring.bean.Car">

                <constructor-arg index="0" value="2m"/>

                <constructor-arg index="1" value="1.5m"/>

                <constructor-arg index="2" value="1.5m"/>

            </bean>

        </property>

        -->

        <!-- 设置为null值

        <property name="car"><null/></property>

         -->

    </bean>

    <bean id="car" class="com.suntj.spring.bean.Car">

        <constructor-arg index="0" value="2m"/>

        <constructor-arg index="1" value="1.5m"/>

        <constructor-arg index="2" value="1.5m"/>

    </bean>

    <bean id="car2" class="com.suntj.spring.bean.Car">

        <constructor-arg type="java.lang.String" >

            <value><![CDATA[<2m>]]></value>

        </constructor-arg>

        <constructor-arg type="java.lang.String" value="1.5m"/>

        <constructor-arg type="int" value="2000"/>

    </bean>

    <!-- 通过p命名空间,来为Bean属性赋值

    <bean id="zhangsan" class="com.suntj.spring.bean.Student">

        <property name="name" value="ZhangSan"/>

        <property name="age" value="11"/>

        <property name="telphone" value="166****1584"/>

    </bean>

    <bean id="lisi" class="com.suntj.spring.bean.Student">

        <property name="name" value="LiSi"/>

        <property name="age" value="12"/>

        <property name="telphone" value="177****1584"/>

    </bean>

    -->

    <bean id="zhangsan" class="com.suntj.spring.bean.Student"

        p:age="11"  p:name="ZhangSan"  p:telphone="166****1584">

    </bean>

    <bean id="lisi" class="com.suntj.spring.bean.Student"

        p:name="LiSi" p:age="12" p:telphone="177****1584">

    </bean>

    <!-- 利用util schema来设置独立的集合 -->

    <util:list id="studentes">

        <ref bean="zhangsan"/>

        <ref bean="lisi"/>

        <bean class="com.suntj.spring.bean.Student">

            <property name="name" value="WangWu"/>

            <property name="age" value="13"/>

            <property name="telphone" value="188****1584"/>

        </bean>

    </util:list>

    <util:map id="teachers">

        <entry key="Jack" value-ref="zhangsan"/>

        <entry key="Lorry" value-ref="lisi"/>

    </util:map>

    <util:properties id="teacherPro">

        <prop key="Jack">Ha_Fo</prop>

        <prop key="Lorry">Qing_Hua</prop>

    </util:properties>

 

    <bean id="teacher" class="com.suntj.spring.bean.Teacher"

        p:studentes-ref="studentes" p:teacherPro-ref="teacherPro" p:teachers-ref="teachers">

        <!-- 初始化java.util.List类型的属性

        <property name="studentes" ref="studentes">

            <list>

                <ref bean="zhangsan"/>

                <ref bean="lisi"/>

                <bean class="com.suntj.spring.bean.Student">

                    <property name="name" value="WangWu"/>

                    <property name="age" value="13"/>

                    <property name="telphone" value="188****1584"/>

                </bean>

            </list>

        </property>

        -->

        <!-- 初始化java.util.Map类型的属性

        <property name="teachers" ref="teachers">

            <map>

                <entry key="Jack" value-ref="zhangsan"/>

                <entry key="Lorry" value-ref="lisi"/>

            </map>

        </property>

         -->

        <!-- 初始化java.util.Properties类型的属性

        <property name="teacherPro" ref="teacherPro">

            <props>

                <prop key="Jack">Ha_Fo</prop>

                <prop key="Lorry">Qing_Hua</prop>

            </props>

        </property>

         -->

    </bean>

    <bean id="autowireA" class="com.suntj.spring.bean.AutowireA" p:name="AutowireA"/>

    <bean id="autowireB" class="com.suntj.spring.bean.AutowireB" p:name="AutowireB"/>

    <bean id="Tautowire" class="com.suntj.spring.bean.Autowire" autowire="byType"/>

    <!-- 通过parent属性来继承parent的配置,这里只重写了name属性,其他属性与parent一致 -->

    <bean id="parent" class="com.suntj.spring.bean.Parent"  abstract="true"

          p:name="parent">

    </bean>

    <bean id="children" class="com.suntj.spring.bean.Parent" parent="parent"

          p:name="children">

    </bean>

    <!-- 依赖 -->

    <bean id="food" class="com.suntj.spring.bean.Food"

          p:name="apple">

    </bean>

    <bean id="people" class="com.suntj.spring.bean.People"

          depends-on="food">

    </bean>

 

    <!-- SpEL表达式举例 -->

    <bean id="car3" class="com.suntj.spring.bean.Car">

        <property name="weight" value="2000"/>

        <property name="length" value="5.5"/>

        <property name="width" value="2"/>

        <property name="heigh" value="1.5"/>

    </bean>

    <bean id="spELDemo" class="com.suntj.spring.bean.SpELDemo">

        <!--             SpEL表示字面值              -->

        <!-- 整数 -->

        <property name="age" value="#{12}"/>

        <!-- 小数 -->

        <property name="fraction" value="#{85.7}"/>

        <!-- 科学计数法 -->

        <property name="weight" value="#{1e2}"/>

        <!-- 字符串:注意单双引号 -->

        <property name="name" value="#{'ZhangSan'}"/>

        <property name="address" value='#{"USA"}'/>

        <!-- 布尔值 -->

        <property name="enabled" value="#{false}"/>

        <!--             SpEL引用Bean、属性、方法              -->

        <!-- 引用其他对象:通过使用SpEL表达式来注入food实例,可以替换ref属性 -->

        <property name="food" value="#{food}"/>

        <!-- 引用其他对象的属性,即便是private修饰的属性 -->

        <property name="foolName" value="#{food.name}"/>

        <!-- 调用其他方法、其他方法的链式操作 -->

        <property name="car" value="#{car3}"/>

        <property name="carName" value="#{car3.getHeigh().toString()}"/>

        <!-- 支持算数运算符:+  -  *  / % ^ -->

        <property name="carWeight" value="#{car3.getWeight() * 2}"/>

        <!-- 连接字符串:用+来连接字符串 -->

        <property name="carWidth" value="#{T(java.lang.String).valueOf(car3.getWidth().toString())  + 'M'}"/>

        <!-- 比较运算法:>  <  ==  >=  <=  lt  gt  eq   le  ge -->

        <property name="carWeightHeavy" value="#{car3.getWeight() > 100}"/>

        <!-- 逻辑运算符:and  or  not  | -->

        <property name="carHeigth" value="#{car3.getHeigh().equals('1.5')  and car3.getWeight() == 2000}"/>

        <!-- if-else运算符: XXX?YYY:ZZZZ    XXX?:ZZZZ    -->

        <property name="carFactory" value="#{car3.getWeight() == 2000 ? 'HongQi':'XueFuLan'}"/>

        <!-- 正则表达式:matches等等 -->

        <!-- 调用静态方法或者静态属性:必须通过T()来调用一个类的静态方法,T()方法返回一个Object,然后再去调用该Object的静态方法和属性 -->

        <property name="pi" value="#{T(java.lang.String).valueOf(T(java.lang.Math).PI)}"/>

    </bean>

    <!-- Bean的生命周期中自定义函数 -->

    <bean id="beanLife" class="com.suntj.spring.bean.BeanLife"

         init-method="init" destroy-method="destroy">

        <property name="name" value="bean-life-cycle"/>

    </bean>

    <!-- 配置后置处理器

    <bean class="com.suntj.spring.bean.MyBeanPostProcess">

    </bean>

     -->

    <!-- 通过静态工厂方法来配置bean,不是配置静态工厂方法实例,而是配置bean实例

        class属性指向静态工厂方法所属的全类名com.suntj.spring.bean.ProductStaticFactory

        factory-method属性指向静态工厂方法的名字

        constructor-arg:如果工厂方法需要传入参数,则使用该属性来配置参数,注意是工厂方法需要参数就要配置该属性,至于构造函数无所谓;

     -->

    <bean id="productByStatic" class="com.suntj.spring.bean.ProductStaticFactory"

          factory-method="getProduct">

        <constructor-arg type="java.lang.String" value="product_static"/>

    </bean>

    <!-- 通过实例工厂方法来配置bean,需要创建工厂本身,再去调用工厂的实例方法来返回bean实例

        factory-bean属性指向实例工厂方法所属的bean

        factory-method属性指向实例工厂方法的名字

        constructor-arg:如果工厂方法需要传入参数,则使用该属性来配置参数,注意是工厂方法需要参数就要配置该属性,至于构造函数无所谓;

    -->

    <!-- 第一步:先配置实例工厂Bean -->

    <bean id="productInstanceFactory" class="com.suntj.spring.bean.ProductInstanceFactory">

    </bean>

    <!-- 第二步:通过实例工厂方法来配置Bean -->

    <bean id="product" factory-bean="productInstanceFactory" factory-method="getProduct">

        <constructor-arg type="java.lang.String" value="product_instance"/>

    </bean>

    <!-- 通过FactoryBean来配置bean实例

         class属性指向FactoryBean的全类名com.suntj.spring.bean.ProductFactoryBean

         property配合的是FactoryBean的属性

         最后还是调用的FactoryBean.getObject方法

     -->

    <bean id="productByFactoryBean"

          class="com.suntj.spring.bean.ProductFactoryBean">

        <property name="productName" value="product_factorybean"/>

    </bean>

</beans>

 

 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值