spring配置总结——beans配置部分
最近看了一下尚硅谷 spring4 视频,在这做下学习笔记,共勉。首先看两个概念:IOC(Inversion of Control):其思想是反转资源获取的方向。传统的资源查找方式要求组件向容器发起请求查找资源。作为回应,容器适时地返回资源。而应用了IOC之后,则是容器主动地将资源推送给它所管理的组件,组件所要做的仅仅是选择一种合适的方式接收资源。这种方式也被称为查找的被动形式。DI(Depend
最近看了一下尚硅谷 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.spELSpring表达式语言(简称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的标准的路径资源。
更多推荐
所有评论(0)