spring配置总结——beans配置部分

最近看了一下尚硅谷 spring4 视频,在这做下学习笔记,共勉。

首先看两个概念:

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

DI(Dependency Injection):——IOC的另一种表述方式:即组件以一些预先定义好的方式(例如:setter方法)接收来自如容器的资源注入。相对于IOC而言,这种表述更直接。

配置Bean包含以下内容:

   1. 配置形式:基于XML文件方式;基于注解的方式

    2.Bean的配置方式:通过全类名(反射)、通过工厂方法(静态工厂方法、实例工厂方法)、FactoryBean

   3. IOC容器BeanFactory$ApplicationContext概述。

    4.依赖注入方式:属性注入;构造器注入;

   5. 注入属性的细节

    6.自动装配

    7.bean之间的关系:继承;依赖;

   8.bean的作用域:singleton;prototype;WEB环境作用域;

   9. 使用外部属性文件;

    10.spEL

   11. IOC容器中Bean的生命周期

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

接下来我们一点点的来看。

1.基于XML文件方式配置bean

<!-- 
    bean配置:
        class:bean的全类名,通过反射的方式在IOC容器中创建Bean,所以要求Bean中必须有无参的构造器。 
        id:标识容器中的bean,id唯一。
-->
<bean id="helloWorld" class="com.atguigu.spring.beans.HelloWorld">
    <property name="name" value="Spring"></property>
</bean>

  2.Bean的配置方式:通过全类名(反射)、通过工厂方法(静态工厂方法、实例工厂方法)、FactoryBean

通过静态工厂方法创建Bean

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

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

	<!-- 通过静态工厂方法来配置bean,注意不是配置静态工程方法实例,而是配置bean实例 -->
	<!-- 
		class属性:指向静态工程方法的全类名。
		factor-method:执行静态方法的名字。
		constructor-arg:如果工程方法需要传入参数,则使用constructor-arg来配置参数
	 -->
	<bean id="car" class="com.atguigu.spring.beans.factory.StaticCarFactory" factory-method="getCar">
		<constructor-arg value="aodi"></constructor-arg>
	</bean>
/**
 * 静态工厂方法:直接调用摸一个类的静态方法就可以返回Bean的实例
 * @author adminitrator
 *
 */
public class StaticCarFactory {
	private static Map<String,Car> cars = new HashMap<>();
	static {
		cars.put("aodi", new Car("aodi", "shanghai", 88888));
		cars.put("baoma", new Car("baoma", "shanghai", 88888));
		cars.put("ford", new Car("ford", "shanghai", 88888));
	}
	//静态工厂方法
	public static Car getCar(String name){
		return cars.get(name);
	}
}

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

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

要声明通过实例工厂方法创建的Bean

    在bean的factory-bean属性里指定拥有该工厂方法的Bean

    在factory-method属性里指定该工厂方法的名称

    使用<constructor-arg>元素为工厂方法传递方法参数

	<!-- 配置工厂的实例 -->
	<bean id="carFactory" class="com.atguigu.spring.beans.factory.InstanceCarFactory" >
	</bean>
	<!-- 通过实例工厂方法来配置bean -->
	<!-- 
		factory-bean:指向实例工厂的bean
		factory-method:指向静态工厂方法的名字
		constructor-arg:如果工厂方法需要传入参数,则使用constructor-arg来配置参数
	 -->
	<bean id="car2" factory-bean="carFactory" factory-method="getCar">
		<constructor-arg value="ford"></constructor-arg>
	</bean>
/**
 * 实例工厂方法:实例工厂方法,即先需要创建工厂本身,在调用工厂的实例方法来放回bean的实例。
 * @author adminitrator
 *
 */
public class InstanceCarFactory {
	private Map<String,Car> cars = null;
	public InstanceCarFactory() {
		cars = new HashMap<>();
		cars.put("aodi",new Car("aodi","shanghai",555));
		cars.put("ford",new Car("ford","shanghai",555));
	}
	public Car getCar(String brand){
		return cars.get(brand);
	}
}

实现FactoryBean接口在SpringIOC容器中配置Bean

Spring中由两种类型的Bean,一种是普通的Bean,另一种是工厂Bean,即FactoryBean

工厂Bean跟普通Bean不同,其返回的对象不是指定的一个实例,其返回的是该工厂Bean的getObject方法所返回的对象。

	<!-- 通过FactoryBean来配置Bean的实例
		class:指向factoryBean的全类名
		property:配置的是factoryBean的属性
		
		但是实际返回的实例却是FactoryBean的getObject方法返回的实例。
	 -->
	<bean id="car" class="com.atguigu.spring.beans.factorybean.CarFactoryBean">
		<property name="brand" value="BMW"></property>
	</bean>
/**
 * 自定义factoryBean 需要实现FactoryBean接口
 * @author adminitrator
 *
 */
public class CarFactoryBean implements FactoryBean<Car>{
	private String brand;
	public void setBrand(String brand) {
		this.brand = brand;
	}
	@Override
	public Car getObject() throws Exception {
		// TODO Auto-generated method stub
		return new Car(brand,"shangshia",5999);
	}

	@Override
	public Class<?> getObjectType() {
		return Car.class;
	}
	@Override
	public boolean isSingleton() {
		// TODO Auto-generated method stub
		return true;
	}

}


3.IOC容器BeanFactory$ApplicationContext概述。

Spring容器

在Spring IOC容器 读取bean配置创建实例之前,不需对它进行初始化,只有容器实例化后,才可以从IOC容器中获取Bean实例并使用。

Spring提供了两种类型的IOC容器实现。

    BeanFactory:IOC容器的基本实现。

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

    BeanFactory是Spring框架的基础设施,面向Spring本身。

    ApplicationContext面向使用Spring框架的开发者,几乎所有的应用场合都直接使用applicationContext而非底层的BeanFactory

    无论使用何种方式,配置文件都是相同的。

ApplicationContext的主要实现类:

    ClassPathXMLApplicationContext:从类路径下加载配置文件

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

ConfigurableApplicationContext扩展于ApplicationContext,新增加两个主要方法:refresh()和close(),让ApplicationContext具有启动、刷新和关闭上下文的能力。

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

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

从IOC容器中获取Bean:调用ApplicationContext的getBean()方法。

4.依赖注入方式:属性注入;构造器注入;

属性注入即通过setter方法注入Bean的属性值或依赖的对象。

属性注入使用<property>元素,使用name属性指定Bean的属性名,value属性或者<value>子节点指定属性值。

属性注入是实际应用中最常用的注入方式

在Spring的IOC容器里配置Bean,在XML文件中通过bean节点来配置bean。

<bean id="helloWorld" class="com.atguigu.spring.beans.HelloWorld">
    <property name="name" value="Spring"></property>
</bean>
public class HelloWorld {
	private String name;

	public void setName(String name) {
		this.name = name;
		System.out.println("set name....");
	}
}

构造器注入

通过构造方法注入bean的属性值或依赖的对象,它保证了Bean实例在实例化后就可以使用。

构造器注入在<constructor-arg>元素里声明属性,<constructor-arg>没有name属性。

按索引破匹配入参:

<bean id="car" class="com.atguigu.spring.beans.Car">
    <constructor-arg index="0" value="aodi" />
    <constructor-arg index="1" value="shagnhai" />
    <constructor-arg index="2" value="49000></constructor-arg>
</bean>

按类型匹配入参:

<bean id="car" class="com.atguigu.spring.beans.Car">
    <constructor-arg type="java.lang.String" value="aodi" />
    <constructor-arg type="java.lang.String" value="shagnhai" />
    <constructor-arg type="int" value="599" />
</bean>
public class Car {
	private String brand;
	private String corp;
	private double pricve;
	private int maxSpeed;
	public Car(String brand, String corp, double pricve) {
		super();
		this.brand = brand;
		this.corp = corp;
		this.pricve = pricve;
	}
	
	public Car(String brand, String corp, int maxSpeed) {
		super();
		this.brand = brand;
		this.corp = corp;
		this.maxSpeed = maxSpeed;
	}
}

5. 注入属性的细节

字面值:可用字符串表示的值,可以通过<value>标签或者value属性进行注入。

基本数据类型及其封装类、String等类型都可以采用字面值注入的方式。

若字面值包含特殊字符,可以用<![CDATA[]]>把字面值包裹起来

<bean id="car" class="com.atguigu.spring.beans.Car">
    <constructor-arg index="0" value="aodi" />
    <!-- 如果字面量包含特殊字符可以使用<![CDATA[]]>包裹起来 -->
    <!-- 属性值也可以使用value子节点进行配置 -->
    <constructor-arg index="1">
        <value><![CDATA[String]]></value>
    </constructor-arg>
    <constructor-arg type="double" value="30000" />
</bean

引用其他Bean

在Bean的配置文件中,可以通过<ref>元素或ref属性为Bean的属性或构造器参数指定对Bean的引用。

<bean id="car" class="com.atguigu.spring.beans.Car">
    <constructor-arg index="0" value="aodi" />
    <constructor-arg index="1" value="shagnhai" />
    <constructor-arg index="2" value="49000></constructor-arg>
</bean>
<bean id="person" class="com.atguigu.spring.beans.Person">
    <property name="name" value="Tom"></property>
    <property name="age" value="24"></property>
     <property name="car" ref="car"> </property>
</bean>

也可以在属性或构造器里包含Bean的生命,这样的Bean称为内部Bean。

当Bean实例仅仅给一个特定的属性使用时,可以将其声明为内部Bean。内部Bean声明直接包含在<property>或<constructor-arg>元素里,不需要设置任何id或name属性。

内部Bean不能使用在任何其他的地方。

<bean id="person" class="com.atguigu.spring.beans.Person">
    <property name="name" value="Tom"></property>
    <property name="age" value="24"></property>
     <property name="car">
           <bean class="com.atguigu.spring.beans.Car">
                <constructor-arg value="Ford"></constructor-arg>
                    <constructor-arg value="shanghai"></constructor-arg>
                    <constructor-arg value="1999"></constructor-arg>
            </bean>
    </property>
</bean>

null值和级联属性

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

和Struts、hibernate等框架一样,Spring支持级联属性的配置。

    <bean id="person2" class="com.atguigu.spring.beans.Person">
    <constructor-arg value="Jerry"></constructor-arg>
    <constructor-arg value="39"></constructor-arg>
    <!-- 为person的car属性赋值null -->
    <!-- <constructor-arg><null/></constructor-arg> -->
    <constructor-arg ref="car"></constructor-arg>
    <!-- 为级联属性赋值 ,注意:属性需要初始化,后才可以为级联属性赋值,否则报异常,和Struts2不同 -->
    <property name="car.maxSpeed" value="38"></property>
    </bean>
集合属性

在Spring中可以通过一组内置的xml标签(例如:<list>,<set>或<map>)来配置集合属性。

配置java.lang.List类型属性,需要制定<list>标签,在标签里包含一些元素。这些元素可以通过<value>指定点单的常量值,通过<ref>指定对其他Bean的引用。通过<bean>指定内置bean定义。通过<null/>指定空元素。甚至其他结合。

数组的定义和List一样,都是用<list>

配置java.util.Set需要使用<set>标签。定义元素的方法和List一样。

java.util.Map通过<map>标签定义,<map>标签可以使用多个<entry>作为字标签。每个条目包含一个键和一个值。必须在

必须在<key>标签里定义键

因为键和值得类型没有限制,所以可自由的为他们指定<value>、<ref>、<bean>和<null/>元素。

可以将M安排的键和值作为<entry>的属性定义:简单常量使用key和value来定义;Bean引用通过key-ref和value-ref属性定义。

使用<props>定义java.lang.Properties,该标签使用多个<prop>作为子标签,每个<prop>标签必须定义key属性。

	<!-- 测试如何配置集合属性 -->
	<bean id="person3" class="com.atguigu.spring.beans.collection.Person">
		<property name="name" value="tome"></property>
		<property name="age" value="34"></property>
		<property name="cars">
			<!-- 使用list节点为list标签属性 -->
			<list>
				<ref bean="car" />
				<ref bean="car2" />
				<bean class="com.atguigu.spring.beans.Car">
					<constructor-arg value="Ford"></constructor-arg>
					<constructor-arg value="shanghai"></constructor-arg>
					<constructor-arg value="1999"></constructor-arg>
				</bean>
			</list>
		</property>
	</bean>
	
    <!-- 配置map属性值 -->
<bean id="newPerson" class="com.atguigu.spring.beans.collection.NewPerson"><property name="name" value="rose"></property><property name="age" value="28"></property><property name="cars"><!-- 使用map节点及map的entry子节点配置map类型的成员变量 --><map><entry key="car" value-ref="car"></entry><entry key="car1" value-ref="car2"></entry><!-- <entry><key></key><value></value></entry> --></map></property></bean><!-- 配置properties属性值 --><bean id="dataSource" class="com.atguigu.spring.beans.collection.DataSource"><!-- 使用props和prop子节点来为properties属性赋值 --><property name="properties"><props><prop key="username" >root</prop><prop key="password">root</prop><prop key="jdbcurl">jdbc:mysql://test</prop><prop key="driverClass">com.mysql.jdbc.Driver</prop></props></property></bean>

使用Utility scheme 定义集合

可以使用util scheme里的集合表面定义独立的集合bean.需要注意的是,必须在<beans>根元素里添加util scheme定义。


	<!-- 配置独立的集合bean,以供多个bean可以引用,引入util命名空间 -->
	<util:list id="cars">
	
		<ref bean="car"></ref>
		<ref bean="car2"/>
	</util:list>

使用P命名空间

Spring从2.5之后开始引入了一个新的P命名空间,可以通过<bean>元素属性的方式配置Bean的属性。

使用P命名空间后,基于Xml配置方式将进一步简化。

	<!-- 通过p命名空间为bean的属性赋值,主要先导入p命名空间,相对于传统的方式更加简洁 -->
	<bean id="person5" class="com.atguigu.spring.beans.collection.Person" p:name="toma"
		p:age="33" p:cars-ref="cars"></bean>
   6.自动装配

XML配置里的Bean自动装配(白话:类中的成员变量不用指定赋值,通过配置IOC自动根据XML配置的byType或byName找到匹配的引用并赋值。)

Spring IOC容器可以自动装配Bean,需要做的仅仅是在<bean>的autowire属性里指定自动装配的模式

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

byName(根据名称自动装配):必须将目标Bean的名称和属性名设置的完全相同。

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

	<bean id="address" class="com.atguigu.spring.beans.autowire.Address" p:city="Beijing" p:street="Huilongugna" ></bean>
	<bean id="car" class="com.atguigu.spring.beans.autowire.Car" p:brand="aodi" p:price="44"></bean>
	<!-- 可以使用autowire属性指定自动装配的方式,
		byNmae 根据bean的名字和当前bean的setter风格属性名进行自动装配,若有匹配的则进行自动装配,若没有匹配的则不装配。
		byType 根据bean的类型和当前bean的类型进行自动装配,若IOC中有一个以上的类型匹配的bean,则抛异常。
	 -->
	<bean id="person" class="com.atguigu.spring.beans.autowire.Person" p:name="hao" autowire="byName"></bean>

XML配置里的Bean自动装配的缺点

在Bean配置文件中设置autowire属性进行自动装配将会装配Bean的所有属性。然而,若只希望装配个别属性时,autowire属性就不够灵活了。

autowire属性要么根据类型自动装配,要么你根据名称自动装配,不能两者兼而有之。

一般情况下,在实际的项目中很少使用自动装配的功能,因为和自动装配功能所带来的好处比起来,明确清晰的配置文档更有说服力。

    7.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:加上属性abstract=true,表示抽象bean,不能被IOC容器实例化,只能用来被继承配置
        若某一个bean的class属性没有指定,则该bean必须是一个抽象bean -->
	
    <bean id="address"  p:city="Beiing" p:street="Wudaokao" abstract="true"></bean>
    <bean id="address2" class="com.atguigu.spring.beans.autowire.Address" parent="address" p:street="dazhongsi"></bean>

依赖Bean的配置

Spring允许用户通过depends-on属性设定Bean前置依赖的bean,前置以来的bean在本bean实例化之前创建好

如果前置依赖于多个bean,则可以通过逗号,空格或的方式配置Bean的名称

8.bean的作用域:singleton;prototype;WEB环境作用域

在Spring中,可以在<bean>元素的scope属性里设置Bean的作用域。

默认情况下,Spring只为每个在IOC容器里声明的Bean创建唯一一个实例,整个IOC容器范围内都能共享该实例:所有后续的getBean()调用和Bean引用都将返回这个唯一的Bean实例,该做用于称为Singleton,它是所有Bean的默认作用域。

类别 说明
singleton

在SpringIOC容器中仅存在一个Bean实例,

Bean以单实例的方式存在

prototype 每次调用getBean()时都会返回一个新的实例
request

每次HTTP请求都会创建一个新的Bean,该作用域仅适用于

WebApplicationContext环境

session

同一个HTTP Session共享一个Bean,不同的HTTP Session使用

不同的Bean。该作用域仅适用于WebApplicationContext环境。

<bean id="car" class="com.atguigu.spring.beans.autowire.Car" scope="prototype" p:brand="aodi" p:price="888"></bean>
9. 使用外部属性文件

在配置文件中配置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="jdbcUrl" value="${jdbcUrl}"></property>
		<property name="driverClass" value="${driverClass}"></property>
	</bean>

db.properties文件内容

user=root
password=root
driverClass=com.mysql.jdbc.Driver
jdbcUrl=jdbc:mysql:///test
10.spEL

Spring表达式语言(简称Spel):是一个支持运行时查询和操作对象图的强大表达式语言。

语言类似于EL:SpEL使用#{..}作为定界符,所有在大括号中的字符都将被认为是SpEL

SpEL为Bean的属性进行动态赋值提供了便利

通过SpEL可以实现:

    通过bean的id对bean进行引用

    调用方法以及引用对象中的属性

    计算表达式的值

    正则表达式的匹配

SpEL字面量

字面量的表示:

    整数:<property name="count" value="#{5}"/>

    小数:<property name="count" value="#{7.7}"/>

    科学计数法:<property name="count" value="#{1e4}"/>

    String可以使用单引号或者双引号作为字符串的定界符<property name="count" value="#{'Chuck'}"/>或者<property name="count" value='#{"Chuck"}'/>

    Boolean:<property name="count" value="#{false}"/>

SpEl;引用Bean、属性和方法

引用其他对象:

<!-- 使用spel来引用其他的bean -->
<property name="car" value="#{car}"></property>

引用其他对象的属性:

<!-- 使用spel来引用其他bean的属性 -->
<property name="city" value="#{address.city}"></property>

调用其他方法,还可以链式操作:

<!-- 通过value属性和SpEL配置suffix属性值为另一个Bean的方法的返回值-->
<property name="suffix" value="#{sequenceGenerator.toString()}"></property>

<!-- 方法的连缀-->
<property name="suffix" value="#{sequenceGenerator.toString()}"></property>

调用静态方法或静态属性:通过T()调用一个类的静态方法,它将返回一个Class Object,然后在调用相应的方法或属性。

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

SpEL支持的运算符号

算术运算符:+,-,*,/,%,^

<property name="amount" value="#{counter.total + 40}"></property>
<property name="amount" value="#{counter.total - 40}"></property>
<property name="amount" value="#{2 * T(java.lang.Math).PI + circle.readius}"></property>
<property name="amount" value="#{counter.total / counter.count}"></property>
<property name="amount" value="#{counter.total % counter.count}"></property
<property name="amount" value="#{T(java.lang.Math).PI * circle.radius ^ 2}"></property

加号还可以用作字符串连接:

<property name="string" value="#{performer.firstname + '' + performer.lastname}"></property>
比较运算符:<,>,== ,>=,<=,lt,gt,eq,le,ge
<property name="equal" value="#{counter.count == 100}"></property>
<property name="hasCapacity" value="#{counter.count le 10000}"></property>

逻辑运算符:and,or,not,|

<property name="largeCircle" value="#{shape.kind == 'circle' and shape.permeter gt 1000}"></property>
<property name="outOfStock" value="#{!product.available}"></property>
<property name="outOfStock" value="#{not product.available}"></property>

if-else运算符: ?:(ternary),?:(Elivis)

<property name="outOfStock" value="#{songSelector.selectSong() == 'Jinle Bells'?'piano:'Jinle Bells'}"></property>

if-else的变体:

<property name="outOfStock" value="#{kenny.song ?:'Greensleeves'}"></property>

正则表达式:

<property name="outOfStock" value="#{admin.email matches '[a-zA-Z0-9._%+-]+\\.[a-zA-Z]{2,4}'}"></property>
11. IOC容器中Bean的生命周期

Spring IOC容器可以管理Bean的生命周期,Spring允许在Bean生命周期的特定点执行定制的任务。

SpringIOC容器对Bean的生命周期进行管理的过程:

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

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

    调用Bean的初始化方法

    Bean可以使用了

    当容器关闭时,调用Bean的销毁方法

在Bean的声明里设置init-method和destroy-method属性,为Bean指定初始化和销毁方法。

	<bean id="car" class="com.atguigu.spring.beans.cycle.Car"
		init-method="init" 
		destroy-method="destroy">
		<property name="brand" value="aodi"></property>
	</bean>

创建Bean后置处理器

Bean后置处理器允许在调用初始化方法前后对Bean进行额外的处理

Bean后置处理器对IOC容器里的所有Bean实例逐一处理,而非单一实例。典型的应用是:检查Bean属性的正确性或根据特定的标准更改Beande属性。

对Bean后置处理器而言,需要实现org.springframework.beans.factory.config.BeanPostProcessor接口。在初始化方法被调用前后,Spring经把每个Bean实例分贝传递给上述接口的以下两个方法:

	/**
	 * Apply this BeanPostProcessor to the given new bean instance <i>before</i> any bean
	 * initialization callbacks (like InitializingBean's {@code afterPropertiesSet}
	 * or a custom init-method). The bean will already be populated with property values.
	 * The returned bean instance may be a wrapper around the original.
	 * <p>The default implementation returns the given {@code bean} as-is.
	 * @param bean the new bean instance
	 * @param beanName the name of the bean
	 * @return the bean instance to use, either the original or a wrapped one;
	 * if {@code null}, no subsequent BeanPostProcessors will be invoked
	 * @throws org.springframework.beans.BeansException in case of errors
	 * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet
	 */
	@Nullable
	default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}

	/**
	 * Apply this BeanPostProcessor to the given new bean instance <i>after</i> any bean
	 * initialization callbacks (like InitializingBean's {@code afterPropertiesSet}
	 * or a custom init-method). The bean will already be populated with property values.
	 * The returned bean instance may be a wrapper around the original.
	 * <p>In case of a FactoryBean, this callback will be invoked for both the FactoryBean
	 * instance and the objects created by the FactoryBean (as of Spring 2.0). The
	 * post-processor can decide whether to apply to either the FactoryBean or created
	 * objects or both through corresponding {@code bean instanceof FactoryBean} checks.
	 * <p>This callback will also be invoked after a short-circuiting triggered by a
	 * {@link InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation} method,
	 * in contrast to all other BeanPostProcessor callbacks.
	 * <p>The default implementation returns the given {@code bean} as-is.
	 * @param bean the new bean instance
	 * @param beanName the name of the bean
	 * @return the bean instance to use, either the original or a wrapped one;
	 * if {@code null}, no subsequent BeanPostProcessors will be invoked
	 * @throws org.springframework.beans.BeansException in case of errors
	 * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet
	 * @see org.springframework.beans.factory.FactoryBean
	 */
	@Nullable
	default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}

    添加Bean后置处理器后的Bean的生命周期:

SpringIOC容器对Bean的生命周期进行管理的过程:

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

    为Bean的属性设置值和堆其他Bean的引用

    将Bean实例传递给Bean后置处理器的PostProcessBeforeInitialization方法

    调用Bean的初始化方法

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

    Bean可以使用了

    当容器关闭时,调用Bean的销毁方法

	<!--
		实现BeanProcessor的接口,并具体提供
		public Object postProcessBeforeInitialization(Object bean, String beanName):init-method之前被调用
		Object postProcessAfterInitialization(Object bean, String beanName):ini-method 之后被调用
		的实现。
		
		bean:bean实例本身
		beanName:IOC容器配置的bean的名字。
		
		返回值:是实际返回给用户的那个Bean,注意:可以在以上两个方法中修改返回的bean,甚至返回一个新的bean。
	 -->
	 <!--  配置bean的后置处理器:不需要配置id,IOC容器自动识别是一个BeanPostProcessor -->
	<bean class="com.atguigu.spring.beans.cycle.MyBeanPostProcessor"></bean>
public class MyBeanPostProcessor implements BeanPostProcessor {

	@Override
	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		// TODO Auto-generated method stub
		System.out.println("postProcessBeforeInitialization:" + bean + beanName);
		return bean;
	}

	@Override
	public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		// TODO Auto-generated method stub
		System.out.println("postProcessAfterInitialization:" + bean + beanName);
		Car car = new Car();
		car.setBrand("Ford");
		//在这里可以偷梁换柱 换掉原来的bean
		
		return car;
	}
	
}

配置形式:基于注解的方式(基于注解配置Bean;基于注解来装配Bean的属性)

在classpath中扫描组件

组件扫描(component scanning):Spring能够从classpath下自动扫描,侦测和实例化具有特定注解的组件。

特定组件包括:

    @Component:基于注解;标识了一个受Spring管理的组件

    @Repository:标识持久层组件

    @Service:标识服务层(业务层)组件

    @Controller:标识表现层组件

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

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

    base-package属性指定一个需要扫描的基类包,Spring容器将会扫描这个基类包里及其子包中得所有类。

    当需要扫描多个包是,可以使用逗号分隔。

    如果仅希望扫描特定的类而非基包下的所有类,可以使用resource-pattern属性过滤特定的类,示例:

	<!-- 指定Spring IOC 容器扫描的包 -->
	<!-- 可以通过resource-pattern指定扫描的资源 -->
	<context:component-scan 
	base-package="com.atguigu.spring.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>子节点支持多种类型的过滤表达式:

类别 示例 说明
annotation com.atguigu.XxxAnnotation

所有标注了XxxAnnotation注解的的类。

该类型采用目标类是否标注了某个注解进行过滤

assinable com.atguigu.XxxService

所有继承或扩展XxxService的类。

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

aspectj com.atguigu.*Service+

所有类名以Service结束的类及继承或扩展它们的类。

该类型采用AspectJ表达式进行过滤。

regex com.\atguigu.\anno.\*

所有com.atguigu.anno包下的类。

该类型采用正则表达式根据类名进行过滤。

custom com.atguigu.XxxTypeFilter

采用XxxTypeFilter通过代码的方式定义过滤规则。

该类必须实现org.springframework.core.type.TypeFilter接口。

	<!--  context:exclude-filter 子节点指定排除哪些指定表达式的组件-->
	<!--  context:include-filter 子节点指定包含哪些表达式的组件,该子节点需要use-default-filters 配合使用
			默认的use-default-filters值为true:表示默认包含component,repository,service,controller范围。
	-->
	<context:component-scan 
	    base-package="com.atguigu.spring.beans.annotation"
	    use-default-filters="false">
            <!-- 除了repository注解标注的类之外的 -->
            <context:exclude-filter type="annotation" 
			expression="org.springframework.stereotype.Repository"/>
            <!-- 只包含repository注解标注的
		<context:include-filter type="annotation" 
				expression="org.springframework.stereotype.Repository" /> -->
	</context:component-scan> 

        <context:component-scan 
		base-package="com.atguigu.spring.beans.annotation" use-default-filters="false">
		<!-- 除了userRepository接口及其实现类之外的 -->
		<context:exclude-filter type="assignable" 
			expression="com.atguigu.spring.beans.annotation.repository.UserRepository"/>
		<!-- 只包含userRepository接口及其实现类
		<context:include-filter type="assignable" 
                    expression="com.atguigu.spring.beans.annotation.repository.UserRepository"/> -->
	</context:component-scan>  -->

组件装配

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

@Autowired注解自动装配具有兼容类型的单个Bean属性

    构造器,普通字段(即使是非public),一切由参数的方法都可以用用@Autowired注解

    默认情况下,所有使用@Autowired注解的属性都需要被设置,当Spring找不到匹配的Bean转配属性时,会抛出异常,若某一属性允许不被设置,可以设置@Autowired注解的required属性为false。  

    默认情况下,当IOC容器里存在多个类型兼容的Bean时,通过类型的自动装配将无法工作。此时可以在@Qualifier注解里提供Bean的名称。Spring允许对方法的入参标注@Qualifier已指定注入Bean的名称

    @Autowired注解也可以应用在数组类型上,此时Spring将会把所有匹配的Bean进行装配。

    @Autowired注解也可以应用到集合属性上此时Spring读取该集合的类型信息,然后自动 装配的多有与之兼容的Bean。

    @Autowired注解用在java.util.Map上是,若该Map的键值为String,那么SPring将自动装配与之Map值类型兼容的Bean,此时Bean的名称称为键值。(PPT上写的不是很清楚?暂时打个问号吧?)

Spring还支持@Resource和Inject注解。这两个注解和@Autowired注解的功能类似:

    @Resource注解要求提供一个Bean名称的属性,若该属性为空,则自动采用标注出的变量或方法名作为Bean的名称。、

    @Inject和@Autowired注解一样也是按类型匹配注入的Bean,但是没有required属性

    建议使用@Autowired注解。

Tips:@Autowired先按类型注入,然后按照名称注入,都无法找到唯一的一个实现类则报错。

          @Resource先按名字注入,再按类型注入,都无法找到唯一的一个出现异常。

整合多个配置文件

Spring允许通过<import>将多个配置文件引入到一个文件中,进行配置文件的集成。这样在启动Spring容器时,仅需要指定这个合并好的配置文件就可以。

import元素的resource属性支持Spring的标准的路径资源。



猜你喜欢

转载自blog.csdn.net/panamera918/article/details/80968753