spring4——IOC、Bean的配置——20200605-20200607

本文深入解析Spring框架的核心概念,包括依赖注入、面向切面编程、容器管理及Bean配置方式,详细介绍基于XML的配置方法,如属性注入、构造器注入、工厂方法注入等,并探讨Bean的作用域、生命周期及依赖管理。

spring是什么

  • spring是一个开源框架

  • spring为简化企业级应用开发而生。使用spring可以使简单的javaBean实现以前只有EJB才能实现的功能

  • spring是一个IOC(DI)和AOP容器框架

  • 具体描述Spring

    • 轻量级:Spring是非侵入性的——基于Spring开发的应用中的对象可以不依赖于Spring的API
    • 依赖注入DI——控制反转IOC
    • 面向切面编程AOP
    • 容器:spring是一个容器,因为它包含并且管理应用对象的生命周期
    • 框架:spring实现了使用简单的组件配置组合成一个复杂的应用。在spring中可以使用XML和java注解组合这些对象
    • 一站式:在IOC和AOP的基础上可以整合各种企业应用的开源框架和优秀的第三方类库(实际上spring自身也提供了展现层的springMVC和持久层的springJDBC)
  • spring模块

    • Data Access/Integration
      • JDBC ORM OXM JMS Transactions
    • Web
      • WebSocket Servlet Web Portlet
    • AOP
    • Aspects
    • Instrumentation 整合
    • Messaging 消息
    • Core Container
      • Beans Core Context SpEL

spring的bean的配置

IOC和DI

  • IOC:其思想是反转资源获取的方向。传统的资源查找方式要求组件向容器发起请求查找资源。作为回应,容器适时的返回资源。而应用了IOC之后,则是容器主动地将资源推送给它所管理的组件,组件所要做的仅是选择一种合适的方式来接受资源。这种行为也被称为查找的被动形式。
  • DI——IOC 的另一种表述形式:即组件以一些预先定义好的方式(例如:setter方法)接受来自如容器的资源注入。相对于IOC而言,这种表述更直接。

IOC前生——分离接口与实现

  • 需求,生成HTML或PDF格式的不同类型的报表。
    IOC前生——采用工厂设计模式
    IOC——采用反转控制

基于XML的方式配置Bean

内容提要

  • 配置bean——基于XML的方式
    • bean的配置方式:通过全类名(反射)、通过工厂方法(静态工厂方法 & 实例工厂方法)、FactoryBean
    • IOC容器BeanFactory & ApplicationContext概述
    • 依赖注入的方式:属性注入;构造器注入
    • 注入属性值细节
    • 自动转配
    • bean之间的关系:继承;依赖
    • bean的作用域:singleton;prototype;web环境作用域
    • 使用外部属性文件
    • spEL
    • IOC容器中Bean的生命周期
    • Spring4.x新特性:泛型依赖注入

在spring的IOC容器里配置bean

  • 在xml文件中通过bean节点来配置bean
<!--    通过全类名的方式配置bean-->
    <bean id="HelloWorld" class="com.springbeantest.HelloWorld">
    </bean>
  • id:Bean的名称
    • 在IOC容器中必须是唯一
    • 若id没有指定,spring自动将权限定性类名作为Bean的名字
    • id可以指定多个名字,名字之间可用逗号、分号或空格分隔
  • class:bean的全类名,通过反射的方式在IOC容器中创建Bean,所以要求bean中必须有无参的构造器

spring容器

  • 在springIOC容器读取Bean配置创建Bean实例之前,必须对它进行实例化,只有在容器实例化后,才可以从IOC容器中获取Bean实例并使用
  • Spring提供了两种类型IOC容器实现
    • BeanFactory (接口) :IOC容器的基本实现
    • ApplicationContext (接口):提供了更多的高级特性,是BeanFactory的子接口。
    • BeanFactory是Spring框架的基础设施,面向Spring本身;ApplicationContext面向使用Spring框架的开发者,几乎所有的应用场合都直接使用ApplicationContext而非底层的BeanFactory
    • 无论使用何种方式,配置文件是相同的。
ApplicationContext
  • ApplicationContext的主要实现类:
    • ClassPathXmlApplicationContext:从类路径下加载配置文件
    • FileSystemXmlApplicationContext:从文件系统中加载配置文件
  • ConfigurableApplicationContext扩展于ApplicationContext,新增加两个主要方法refresh()和close(),让ApplicationContext具有启动、刷新和关闭上下文的能力 是ApplicationContext的实现类,是ClassPathXmlApplicationContext和FileSystemXmlApplicationContext的父类
  • ApplicationContext在初始化上下文时就实例化所有单例的Bean
  • WebApplicationContext是专门为Web应用而准备的,它允许从相对于Web根目录的路径中完成初始化工作。

从IOC容器中获取Bean

  • 调用ApplicationContext中的getBean()方法
//以id获取bean(唯一)
        HelloWorld helloWorld = (HelloWorld) ctx.getBean("HelloWorld");
        //以类型(可能不唯一)返回IOC容器中的bean,但要求IOC容器中必须只能有一个该类型的bean
        HelloWorld helloWorld2 = (HelloWorld) ctx.getBean(HelloWorld.class);
        

依赖注入的方式

  • spring支持3种依赖注入的方式
    • 属性注入
    • 构造器注入
    • 工厂方法注入(很少使用,不推荐)
属性注入
  • 属性注入即通过setter方法注入bean的属性值或依赖的对象
  • 属性注入使用<property>元素,使用name属性指定Bean的属性名称,value属性或<value>子节点指定属性值
  • 属性注入是实际应用中最常用的注入方式
<bean id="HelloWorld" class="com.springbeantest.HelloWorld">
        <property name="name" value="Spring"></property>
</bean>
构造方法注入
  • 通过构造方法注入bean的属性值或依赖的对象,它保证了bean实例在实例化后就可以使用。
  • 构造器注入在<constructor-arg>元素里声明属性,<constructor-arg>中没有name属性。
<bean id="Car2" class="com.springbeantest.Car">
        <constructor-arg value="Baoma" index="0"></constructor-arg>
        <constructor-arg value="ShangHai" index="1"></constructor-arg>
        <constructor-arg value="240" type="int"></constructor-arg>
</bean>
public Car(String brand, String corp, int maxSpeed) {
        this.brand = brand;
        this.corp = corp;
        this.maxSpeed = maxSpeed;
    }
*字面值
  • 字面值:可用字符串表示的值,可以通过<value>元素标签或value属性进行注入
  • 基本数据类型及其封装类、String等类型都可以采取字面值注入的方式
  • 若字面值中包含特殊字符,可以使用<![CDATA[]]>把字面值包裹起来。
<bean id="Car2" class="com.springbeantest.Car">
        <constructor-arg value="Baoma" index="0"></constructor-arg>
        <constructor-arg index="1">
            <value><![CDATA[<ShangHai>]]></value>
        </constructor-arg>
        <constructor-arg value="240" type="int"></constructor-arg>
</bean>

引用其它Bean

  • 组成应用程序的Bean经常需要互相协作以完成应用程序中的功能。要使Bean能够互相访问,就必须在Bean配置文件中指定对Bean的引用
  • 在Bean的配置文件中,可以通过<ref>元素或ref属性为bean的属性或构造器参数指定对Bean的引用
  • 也可以在属性或构造器里包含对bean的声明,这样的bean称为内部bean
<bean id="person" class="com.springbeantest.Person">
        <property name="name" value="Tom"></property>
        <property name="age" value="24"></property>
<!--        使用ref属性建立bean之间的引用关系-->
        <property name="car" ref="Car2"></property>
    </bean>

内部Bean:

<property name="car" >
            <!-- 内部bean不能被外部引用-->
            <bean class="com.springbeantest.Car">
                <constructor-arg value="Ford" index="0"></constructor-arg>
                <constructor-arg value="Beijing" index="1"></constructor-arg>
                <constructor-arg value="200000" index="2"></constructor-arg>
            </bean>
        </property>
注入参数详解:null值和级联属性
  • 可以使用专用的元素标签<null/>为Bean的字符串或其他对象类型的属性注入null值
  • 和Struts 、Hiberante等框架一样,spring支持级联属性的配置。属性需要先初始化后才可以为级联属性赋值,否则会有异常
<property name="car" ref="Car2"></property>
<property name="car.maxSpeed" value="250"></property>
集合属性
  • 在Spring中可以通过一组内置的xml标签(如<list>, <set,<map>)来配置集合属性
  • 配置java.util.List类型的属性,需要指定<list>标签,在标签里包含一些元素。这些标签可以通过<value>指定简单的常量值,通过<ref>指定对其他Bean的引用,<bean>指定内置bean定义。通过<null/>指定空元素,甚至可以内嵌其他集合
  • 数组的定义和List一样,都使用<list>
  • 配置java.util.Set需要使用标签<set>,定义元素的方法和List一样。
<!--    测试集合属性-->
    <bean id="person3" class="com.springbeantest.beans.collections.Person">
        <property name="name" value="Mike"></property>
        <property name="age" value="27"></property>
        <property name="cars">
            <list>
                <ref bean="Car"/>
                <ref bean="Car2"/>
            </list>
        </property>
    </bean>
  • <map>可以使用多个<entry>作为子标签,每个条目包含一个键和一个值
  • 必须在<key>里定义键
  • 因为键和值的类型没有限制,可以自由的给它们指定<value><ref><bean><null/>元素
  • 可以将<map>的键和值作为<entry>的属性定义:简单常量使用key和value来定义;Bean引用通过key-ref和value-ref属性定义
  • 使用<props>定义java.util.Properties,该标签使用多个<prop>作为子标签,每个<prop>标签必须定义key属性

map:

<map>
     <entry key="AA" value-ref="Car"></entry>
     <entry key="BB" value-ref="Car2"></entry>
</map>

Properties :

public class DataSource {
    private Properties properties;

    @Override
    public String toString() {
        return "DataSource{" +
                "properties=" + properties +
                '}';
    }

    public Properties getProperties() {
        return properties;
    }

    public void setProperties(Properties properties) {
        this.properties = properties;
    }
}
 <bean id="dataSource" class="com.springbeantest.beans.collections.DataSource">
        <property name="properties">
            <props>
                <prop key="user">root</prop>
                <prop key="password">123456</prop>
                <prop key="jdbcUrl">jdbc:mysql:///test</prop>
                <prop key="driverClass">com.mysql.jdbc.Driver</prop>
            </props>
        </property>
    </bean>
使用utility scheme定义集合
  • 使用基本的集合标签定义集合时,不能将集合作为独立的bean定义,导致其它bean无法引用该集合,所以无法在不同bean之间共享集合
  • 可以使用util.schema里的集合标签定义独立的集合bean,需要注意的是,必须在<bean>根元素里添加util.schema定义
<util:list id = "cars">
    <ref bean="Car" />
    <ref bean="Car2" />
</util:list>

<bean id="person5" class="com.springbeantest.beans.collections.Person">
    <property name="name" value="Jack"></property>
    <property name="age" value="29"></property>
    <property name="cars" ref="cars"></property>
</bean>
使用p命名空间
  • 为了简化xml文件的配置,越来越多的xml文件采用属性而非子元素配置信息
  • Spring从2.5版本开始引入了一个新的p命名空间。可以通过<bean>元素属性的方式配置bean的属性。
  • 使用p命名空间后,基于XML的配置方式将进一步简化。
<bean id="person6" class="com.springbeantest.beans.collections.Person"
    p:age ="30" p:name="Queen" p:cars-ref="cars"></bean>
xml配置里的bean自动装配
  • SpringIOC容器可以自动装配Bean,需要做的是在<bean>中的autowire属性里指定自动装配的模式
  • byType(根据类型自动装配):若IOC容器中有多个与目标Bean类型一致的bean,在这种情况下,spring将无法判定哪个bean最合适该属性,所以不能执行自动装配。
    根据bean的类型和当前bean的属性的类型进行自动装配,若IOC容器中有1个以上的类型匹配的bean,则抛异常org.springframework.beans.factory.UnsatisfiedDependencyException

  • byName(根据名字自动装配):必须将目标Bean的名称和属性名设置的完全相同
    根据bean的名字和当前bean的setter风格的属性名进行自动装配,若有匹配的,则进行自动装配,若没有匹配的,则不装配
<!--    自动装配 byName-->
    <bean id="person" class="com.springbeantest.beans.autowire.Person"
          p:name="Tom" autowire="byName"></bean>
  • constructor(根据构造器自动装配):当Bean中存在多个构造器时,这种自动装配方式将会很复杂,不推荐使用。

  • 自动装配的缺点:

    • 在bean配置文件里设置autowire属性进行自动装配将会配置bean的所有属性,然而,若只希望配置个别属性时,autowire属性就不够灵活了。
    • autowire属性要么根据类型装配,要么根据名称自动装配,不能二者兼而有之
    • 一般情况下,在实际的项目中很少使用自动装配功能,因为和自动装配功能带来的好处相比,明确清晰的配置文档更有说服力一些。
继承bean配置
  • spring允许继承bean配置,被继承的bean称为父bean,继承这个父bean的bean叫做子bean
  • 子Bean从父Bean中继承配置,包括Bean的属性配置
  • 子Bean也可以覆盖从父Bean继承过来的配置
  • 父Bean可以作为配置模板,也可以作为Bean实例,若只想把父Bean作为模板,可以设置Bean的abstract属性为true,这样spring就不会实例化这个bean
  • 并不是Bean元素里的所有属性都会被继承,比如:autowire,abstract等。
  • 也可以忽略父Bean的class属性,让子Bean指定自己的类,而共享相同的属性配置,但此时abstract必须设为true。

子bean和父bean配置:

<bean id="beijing" class="com.springbeantest.beans.autowire.Address"
      p:city="Beijing"></bean>
<bean id="address2" parent="beijing" p:street="Wudaokou"></bean>

打印结果:

Address{city='Beijing', street='null'}
Address{city='Beijing', street='Wudaokou'}
依赖bean配置
  • spring允许用户通过depends-on属性设定Bean前置依赖的Bean,前置依赖的Bean会在Bean实例化之前创建好
  • 如果前置依赖于多个Bean,则可以通过逗号,空格或的方式配置Bean的名称

person3依赖于car2,如果没有car2的话,会报错

<!--    bean 依赖-->
    <bean id="person3" class="com.springbeantest.beans.autowire.Person"
          p:name="Jack" p:address-ref="address2" depends-on="car2"></bean>

但是有car2的bean,打印结果car属性是null:

Person{name='Jack', address=Address{city='Beijing', street='Wudaokou'}, car=null}

Bean的作用域

代码测试:

ApplicationContext ctx = new ClassPathXmlApplicationContext("beans-autowire.xml");
Person person = (Person) ctx.getBean("person4");
Person person2 = (Person) ctx.getBean("person4");

System.out.println(person == person2);
  • 默认是singleton :true
  • 设定为prototype:false

使用外部属性文件

  • 在配置文件里配置Bean时,有时需要在Bean的配置里混入系统部署的细节信息(例如:文件路径,数据源配置信息等)。而这些部署细节实际上需要和Bean配置相分离
  • Spring提供了一个PropertyPlaceholderConfigurer的BeanFactory后置处理器,这个处理器允许用户将Bean配置的部分内容外移到属性文件中,可以在Bean配置文件里使用形式为${var}的变量,PropertyPlaceholderConfigurer从属性文件里加载属性,并使用这些属性来替换变量
  • spring还允许在属性文件里使用${propName},以实现属性之间的相互引用。
<!--    导入属性文件-->
<context:property-placeholder location="classpath:db.properties" />
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">">
        <property name="user" value="${user}"></property>
        <property name="password" value="${password}"></property>
        <property name="driverClass" value="driverclass"></property>
        <property name="jdbcUrl" value="${jdbcurl"></property>
    </bean>

db.properties文件:

user=root
password = 123
driverclass = com.sql.jdbc.Driver
jdbcurl = jdbc:mysql:///test

Spring表达式语言:SpEL

  • Spring表达式语言:是一个支持运行时查询和操作对象图的强大的表达式语言。
  • 语法类似于EL: SpEL使用#{…}作为定界符,所有在大框号中的字符都将被认为是SpEL
  • SpEL为bean的属性进行动态赋值提供了便利
  • 通过SpEL可以实现
    • 通过bean的id对bean进行引用
    • 通过方法以及引用对象中的属性
    • 计算表达式的值
    • 正则表达式的匹配
SpEL:字面量
  • 字面量的表示:
    • 整数 #{5}
    • 小数 #{1.5}
    • 科学计数法 #{1e5}
    • 字符串:可以使用单引号或多引号作为字符串的定界符号。#{"cshvjd"}#{'cshvjd'}
    • 布尔值:#{false}
SpEL:引用Bean、属性和方法
  • 引用其它对象<property name="car" value="#{car}"></property>
  • 引用其他对象的属性<property name="address" value="#{car.price}"></property>
  • 调用其他方法,还可以链式操作<property name="name" value="#{car.toString()}"></property>
    方法的连接:<property name="name" value="#{car.toString().toUpperCase()}"></property>
  • 调用静态方法或静态属性:通过T()调用一个类的静态方法,它将返回一个Class Object,然后再调用相应的方法或属性#{T(java.lang.Math).PI}
SpEL:支持的运算符号
  • 算数运算符:+,-,*,/,%,^
  • 加号还可以用作字符串连接
  • 比较运算符:<,>,==,<=,>=,lt, gt。eg,le,ge
  • 逻辑运算符 and,or,not,|
  • if-else运算符:?:
  • if-else的变体
  • 正则表达式: matches

代码测试:

	<bean id="address" class="com.springbeantest.beans.spel.Address"
          p:city="#{'Wuhan'}" p:street="LuoYuRoad"></bean>
    <bean id="car" class="com.springbeantest.beans.spel.Car"
          p:brand="Audi" p:price="500000" p:tyrePerimeter="#{T(java.lang.Math).PI*80}"></bean>
    <bean id="person" class="com.springbeantest.beans.spel.Person">
        <property name="name" value="Jack"></property>
        <property name="city" value="#{address.city}"></property>
        <property name="car" value="#{car}"></property>
        <property name="info" value="#{car.price>50000?'金领':'白领'}"></property>
    </bean>

IOC容器中Bean的生命周期

  • SpringIOC容器可以管理Bean的生命周期,Spring允许在Bean生命周期的特定点执行定制的任务
  • SpringIOC容器对Bean的生命周期进行管理的过程
    • 通过构造器或工厂方法创建Bean实例
    • 为Bean的属性设置值和对其他Bean的引用
    • 调用Bean的初始化方法
    • Bean可以使用了
    • 当容器关闭时,调用Bean的销毁方法
  • 在Bean的声明里设置init-method和 destroy-method属性,为Bean指定初始化和销毁方法。
创建Bean后置处理器
  • Bean后置处理器允许在调用初始化方法前后对Bean进行额外的处理
  • Bean后置处理器对IOC容器里的所有Bean实例逐一处理,而非单一实例,其典型应用是:检查Bean属性的正确性或根据特定的标准更改Bean的属性
  • 对Bean后置处理器而言,需要实现BeanPostProcessor接口。在初始化方法被调用前后,Spring将把每个Bean实例分别传递给该接口的两个方法
    • postProcessBeforeInitialization()
    • postProcessAfterInitialization()
  • Bean后置处理器的作用:
    • 可以通过实现BeanPostProcessor接口,并具体提供上面的两个方法,来构造自己的Bean后置处理器
    • 方法里的参数:
      • bean:bean本身
      • beanName:IOC容器配置的bean名字
      • 返回值:是实际上返回给用户的那个Bean,注意,可以在以上两个方法中修改返回的bean,甚至返回一个新的Bean
public interface BeanPostProcessor {
    @Nullable
    default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

    @Nullable
    default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }
}
添加Bean后置处理器后Bean的生命周期
  • 通过构造器或工厂方法创建Bean实例
  • 为Bean的属性设置值和对其他Bean的引用
  • 将Bean实例传递给Bean后置处理器的postProcessBeforeInitialization方法
  • 调用Bean的初始化方法
  • 将Bean实例传递给Bean后置处理器的postProcessAfterInitialization方法
  • Bean可以使用了
  • 当容器关闭时,调用Bean的销毁方法

代码测试:

public class Main {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("beans-properties.xml");

//        System.out.println(ctx.getBean("car"));
        System.out.println("=======================");
        System.out.println(ctx.getBean("car2"));
        ctx.close();
    }
}
class MyBeanPostProcessor implements BeanPostProcessor{
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessBeforeInitialization: " + bean + "," + beanName);
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessAfterInitialization: " + bean + "," + beanName);
        return bean;
    }
}

配置:

<!--    配置bean的后置处理器:不需要配置id,IOC容器自动识别是一个BeanPostProcessor -->
    <bean class="com.springbeantest.beans.cycle.MyBeanPostProcessor"></bean>

结果:

postProcessBeforeInitialization: Address{city='Wuhan', street='LuoYuRoad'},address
postProcessAfterInitialization: Address{city='Wuhan', street='LuoYuRoad'},address
postProcessBeforeInitialization: Car{brand='Audi', price=500000.0, tyrePerimeter=251.32741228718345},car
postProcessAfterInitialization: Car{brand='Audi', price=500000.0, tyrePerimeter=251.32741228718345},car
postProcessBeforeInitialization: Person{name='Jack', car=Car{brand='Audi', price=500000.0, tyrePerimeter=251.32741228718345}, city='Wuhan', info='金领'},person
postProcessAfterInitialization: Person{name='Jack', car=Car{brand='Audi', price=500000.0, tyrePerimeter=251.32741228718345}, city='Wuhan', info='金领'},person
Car's constructing
setBrand ...
postProcessBeforeInitialization: Car{brand='Cycle'},car2
init...
postProcessAfterInitialization: Car{brand='Cycle'},car2
=======================
Car{brand='Cycle'}
destroy...

通过调用工厂方法创建Bean——静态工厂方法

  • 调用静态工厂方法创建Bean是将对象创建的过程封装到静态方法中。当客户端需要对象时,只需要简单的调用静态方法,而不用关心对象创建的细节
  • 要声明通过静态方法创建的bean,需要在Bean的class属性里指定拥有该工厂的方法的类,同时在factory-method属性里指定工厂方法的名称,最后,使用construor-arg元素为工厂方法传递方法参数

代码测试:

<!--    通过静态工厂方法来配置bean,注意不是配置静态工厂方法实例,而是配置bean实例-->
<!--    class属性:指向静态工厂方法的全类名
        factory-method:指向静态工厂方法的名字
        constructor-arg:如果工厂方法需要传入参数,则使用该标签类配置参数
        -->
    <bean id="car1" class="com.springbeantest.beans.factory.StaticCarFactory"
        factory-method="getCar">
        <constructor-arg value="audi"/>
    </bean>
/*
静态工厂方法:直接调用某一个类的静态方法就可以返回Bean的实例

 */
public class StaticCarFactory {
    private static Map<String , Car> cars = new HashMap<>();

    static {
        cars.put("audi",new Car("audi",3000000));
        cars.put("ford",new Car("ford",4000000));
    }

    //静态工厂方法
    public static Car getCar(String name) {
        return cars.get(name);
    }
}

通过调用工厂方法创建Bean——实例工厂方法

  • 实例工厂方法:将对象的创建过程封装到另外一个对象实例的方法里。当客户端需要请求对象时,只需要简单的调用该实例方法而不需要关心对象的创建细节
  • 要声明通过实例工厂方法创建的bean
    代码测试:
    • 在Bean的factoty-bean属性里指定拥有该工厂方法的Bean
    • 在factory-method属性中指定该工厂方法的名称
    • 使用construor-arg元素为工厂方法传递方法参数
<!--    实例工厂方法-->
    <!--    配置工厂的实例-->
    <bean id="carFactory" class="com.springbeantest.beans.factory.InstanceCarFactory"></bean>
    <!--    通过示例工程的方法来配置bean-->
    <bean id="car2" factory-bean="carFactory" factory-method="getCar">
        <constructor-arg value="ford"/>
    </bean>
/*
实例工厂方法:需要创建工厂本身,再调用工厂的实例方法返回bean的实例
 */
public class InstanceCarFactory {
    private static Map<String , Car> cars = null;

    public InstanceCarFactory(){
        cars = new HashMap<>();
        cars.put("audi",new Car("audi",3000000));
        cars.put("ford",new Car("ford",4000000));

    }
    public Car getCar(String brand){
        return cars.get(brand);
    }
}

通过FactoryBean创建Bean

<!--    FactoryBean
        class指向FactoryBean的quanleim
        property:配置FactoryBean的属性
        但实际返回的实例却是FactoryBean的getObject()方法返回的实例
-->
    <bean id="cars" class="com.springbeantest.beans.factory.CarFactoryBean">
        <property name="brand" value="BMW"></property>
    </bean>
package com.springbeantest.beans.factory;

import com.springbeantest.beans.spel.Car;
import org.springframework.beans.factory.FactoryBean;

public class CarFactoryBean implements FactoryBean<Car> {
    private String brand;

    public void setBrand(String brand) {
        this.brand = brand;
    }

    @Override
    public Car getObject() throws Exception {
        return new Car(brand,5000000);
    }

    @Override
    public Class<?> getObjectType() {
        return Car.class;
    }

    @Override
    public boolean isSingleton() {
        return true;
    }
}

基于注解的方式配置Bean

在classpath中扫描组件

  • 组件扫描(component scanning):Spring能够从classpath下自动扫描,侦测和实例化具有特定注解的组件
  • 特定组件包括
    • @Component:基本注解,标识了一个受Spring管理的组件
    • @Respository:标识持久层组件
    • @Service:标识服务层(业务层)组件
    • @Controller:标识表现层组件
  • 对于扫描到的组件,Spring有默认的命名策略:使用非限定类名,第一个字母小写。也可以在注解中通过value属性值标识组件的名称
  • 当在组件类上使用了特定的注解之后,还需要在Spring的配置文件中声明 <context:component-scan>
    • base-package属性指定一个需要扫描的基类包,Spring容器将会扫描这个基类包里及其子包中所有类
    • 当需要扫描多个包时,可以用逗号分隔。
    • 如果仅需要扫描特定的类而非基类包下的所有类,可使用resource-pattern属性过滤特定的类,例如<context:component-scan base-package="com.springbeantest.beans.annotation" resource-pattern="repository/*.class"> </context:component-scan>
    • <context:include-filter>:子节点标识要包含的目标类
    • <context:exclude-filter>:子节点标识要排除在外的目标类
    • <context:component-scan>下可以拥有若干个 <context:include-filter><context:exclude-filter>子节点。
    • <context:include-filter><context:exclude-filter>子节点支持多种类型的过滤表达式
类别实例说明
annotationcom.atguigu.XxxAnnotation所有标注了XxxAnnotation的类。该类型采用目标类是否标注了某个注解进行过滤
assinablecom.atguigu.XxxService所有继承或扩展了XxxService 的类。该类型采用目标类是否继承或扩展某个特定类进行过滤
aspectjcom.atguigu…"Service+所有类名以Service结束的类以及继承或扩展它们的类。该类型采用AspectJ表达式进行过滤
regexcom.\atguigu.anno…*所有com.atguigu.anno包下的类。该类型采用正则表达式根据类的类名进行过滤
customcom.atguigu.XxxTypeFilter采用XxxTypeFilter通过代码的方式定义过滤规则。该类必须实现org.springframework.core.type.TypeFilter 接口

组件装配

  • <context:component-scan>元素还会自动注册AutowiredAnnotationBeanPostProcessor实例,该实例可自动装配具有@Autowired @Resource @Inject 注解的属性
  • @Autowired 注解自动装配具有兼容类型的单个Bean属性
    • 构造器,普通字段(即使是非public),一切具有参数的方法都可以应用@Autowired注解
    • 默认情况下,所有使用@Autowired注解的属性都需要被设置。当Spring找不到匹配的Bean装配属性时,会抛出异常,若某一属性允许不被设置,可以设置@Autowired注解的required属性为false设置required属性为false之后,即便找不到某个属性,也可以作为null来处理,而不是直接报错
    • 默认情况下,当IOC容器中存在多个类型兼容的Bean时,通过类型的自动装配将无法工作,此时可以在@Qualifier注解里提供Bean的名称。Spring允许对方法的入参标注@Qualifier 以指定注入Bean的名称@Autowired
      @Qualifier(“userRepositoryImpl”)
      private UserRepository userRepository; 或
      public void setUserRepository(@Qualifier(“userRepositoryImpl”) UserRepository userRepository) {
      this.userRepository = userRepository;
      }
    • @Autowired 注解也可以应用在数组类型的属性上,此时Spring将会把所有匹配的Bean进行自动转配。
    • @Autowired 注解也可以应用在集合属性上,此时Spring读取该集合的类型信息,然后自动装配所有与之兼容的Bean。
    • @Autowired 注解用在java.util.Map上时,若该Map的键值为String,那么Spring将自动装配与之Map值类型兼容的Bean,此时Bean的名称作为键值。
  • Spring还支持@Resource @Inject 注解,这两个注解和 @Autowired注解的功能类似
    • @Resource注解要求提供一个Bean名称的类属性,若该属性为空,则自动采用标注处的变量或方法名作为Bean的名称
    • @Inject和@Autowired注解一样也是按类型匹配注入的Bean,但没有required属性
    • 建议使用@Autowired注解

Spring4.x新特性:泛型依赖注入

Spring4.x可以为子类引入子类对应的泛型类型的成员变量的引用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值