根据个人学习情况,筛选出特别关注的信息,完整内容请看原版,仅仅是个人学习笔记。
本章节内容非常之多,可能需要耗时2日时间掌握。
目录
7-2-2) inclue-filter和exclue-filter包含和不包含过滤器的使用
7-3-2) 使用@Autowired的required属性
7-3-3) 使用@Qualifier指定注入Bean的名称
7-4) Bean生命过程方法PostConstruct和PreDestory
8-2-1)通过@Configuration类直接启动Spring容器
8-2-2)通过XML配置component-scan扫描加载启动
8-2-3)通过@Configuration配置类引用XML配置信息
8-3)基于GroovyDSL的配置(自行学习研究,暂未整理)
一)Spring容器启动流程
1)Spring启动首先读取应用程序提供的Bean配置信息;
2)在Spring容器中生成一份相应的Bean注册表;
3)根据注册表实例化Bean,装配好Bean之间的依赖关系
4)把准备就绪的Bean放入Spring容器的Bean缓存池中,以供外出的应用程序进行调用
二)Bean基本配置
2-1)Bean的命名
2-1-1)ID的命名
<bean id="car" class="com.smart.simple.Car">
id在IoC容器中必须唯一,必须以字母开始,后面是字母、数字、连字符、下划线、句号、冒号等完整结束的符号,逗号和空格是非法的。
2-1-2)Name的命名
<bean name="#car1" class="com.smart.simple.Car">
name属性没有字符限制,几乎可以使用任何字符。允许出现多个name相同的<bean>,后续出现一样的name名称会覆盖前面同名的bean,为了避免无意间Bean覆盖的隐患,尽量使用id命名bean。
2-1-3)匿名
<bean class="com.smart.simple.Car">
<bean class="com.smart.simple.Car">
<bean class="com.smart.simple.Car">
第一个Bean通过getBean("com.smart.simple.Car")获得;
第二个Bean通过getBean("com.smart.simple.Car#1")获得;
第三个Bean通过getBean("com.smart.simple.Car#2")获得。
一般而言,匿名<bean>在通过内部Bean为外层Bean提供注入值时使用。
三)依赖注入
Spring支持属性注入和构造函数注入、工厂方法注入方式。
3-1)属性注入
Java的属性变量名都以小写字母开头,也满足变量的前两个字母全部大写或全部小写的要求。
以下为错误示例:
/** Foo类 **/
public class Foo{
private String iDCard;
public void setIDCard(String iDCard){
this.iDCard = iDCard;
}
}
/** Spring配置文件 **/
//省略XML头部
.....................................................
<bean id="foo" class="com.XXXX.XXXX.Foo">
<property name="iDCard" value="123100">
</bean>
当启动Spring容器,配置文件中非法的属性名iDCode找不到对应的Setter方法。原因为我们在编写Foo的iDCode变量名后,通过IDE的代码自动生成setIDCard()属性设置方法,由于命名规范问题导致对应不上方法。
纠正方案:
/** Spring配置文件 **/
//省略XML头部
.....................................................
<bean id="foo" class="com.XXXX.XXXX.Foo">
<!-- IDCard对应setIDCard()属性设置方法 -->
<property name="IDCard" value="123100">
</bean>
3-2)构造函数注入
3-2-1)按类型匹配入参
/** Car类 **/
public class Car{
....................
public Car(String brand, double price) {
this.brand = brand;
this.price = price;
}
}
/** Spring配置文件 **/
<bean id="car" class="com.XXXX.XXXX.Car">
<constructor-arg type="java.lang.String">
<value>红旗CA71</value>
</constructor-arg>
<constructor-arg type="java.lang.double">
<value>200000</value>
</constructor-arg>
</bean>
注意:Spring的配置文件采用和元素标签顺序无关的策略,通过type属性为Spring提供判断配置项和构造函数入参对应关系。原因为Java反射机制并不会记住构造函数的入参名,因此无法通过指定构造函数的入参名进行构造函数注入的配置,只能通过入参类型和索引信息间接确定构造函数配置项和入参的对应关系。
3-2-2)按索引匹配入参
/** Car类 **/
public class Car{
....................
public Car(String brand, String maxSpeed,double price) {
this.brand = brand;
this.maxSpeed = maxSpeed;
this.price = price;
}
public Car(String brand, String maxSpeed,int count) {
this.brand = brand;
this.maxSpeed = maxSpeed;
this.count = count;
}
}
由于brand和maxSpeed入参类型都是String,所以Spring无法确定type为String的<constructor-arg>对应的入参参数,可以通过显示指定参数的索引消除不确定性。
如果参数数目相同而类型不同,则需要联合使用索引index和使用类型type匹配入参。
/** Spring配置文件 **/
<bean id="car" class="com.XXXX.XXXX.Car">
<!-- 索引从0开始 -->
<constructor-arg index="0" type="java.lang.String" value="红旗CA71" />
<constructor-arg index="1" type="java.lang.String" value="280" />
<constructor-arg index="2" type="java.lang.double" value="200000" />
</bean>
3-2-3)自身类型反射匹配入参
/** Boss 类 **/
public Boss(String name, String num, Car car) {
this.name= name;
this.num= num;
this.car= car;
}
/** Spring配置文件 **/
<bean id="boss" class="com.xxxx.xxxx.Boss">
<constructor-arg>
<value>John</value>
</constructor-arg>
<constructor-arg>
<value>2</value>
</constructor-arg>
<constructor-arg>
<ref bean="car" />
</constructor-arg>
</bean>
<bean id="car" class="com.XXXX.XXXX.Car" />
3-2-4)循环依赖问题
/** Car类的构造函数依赖于boss实例 **/
public class Car{
....................
public Car(String brand, Boss boss) {
this.brand = brand;
this.boss = boss;
}
}
/** Boss类的构造函数依赖于car实例 **/
public class Boss {
public Boss(String name, Car car) {
this.name= name;
this.car= car;
}
}
假设在Spring配置文件中按照以下构造函数注入,就会存在循环依赖,Spring容器无法成功启动。
/** Spring配置文件 **/
<bean id="boss" class="com.xxxx.xxxx.Boss">
<constructor-arg index="0" value="John"/>
<constructor-arg index="1" ref="car"/>
</bean>
<bean id="car" class="com.XXXX.XXXX.Car">
<constructor-arg index="0" value="红旗A6"/>
<constructor-arg index="1" ref="boss"/>
</bean>
解决方式,将构造函数注入调整为属性注入方式即可。
3-3)工厂方法注入
在个别遗留系统或第三方类库中,会遇到工厂方法,这时可以使用Spring工厂方法注入的方式进行配置。工厂类负责创建一个或多个目标类实例,工厂类方法一般以接口或抽象类变量的形式返回目标类实例。
3-3-1)非静态工厂方法
/** CaFactory工厂类,仅负责创建Carl类型的对象 **/
public class CarFactory {
public Car createHongQiCar(){
Car car = new Car();
car.setBrand("红旗QQ");
return car;
}
}
由于CarFactory工厂类的工厂方法不是静态的,所以首先需要定义一个工厂类的Bean,然后通过factory-bean引用工厂类实例,最后通过factory-method指定对应的工厂类方法。
/** Spring配置文件 **/
......................
<bean id="carFactory" class="com.xxxx.xxxx.carFactory"/>
<bean id="car1" factory-bean="carFactory"
factory-method="createHongQiCar"/>
3-3-2)静态工厂方法
由于无须用户创建工厂类实例,因此静态工厂方法比非静态工厂方法更易用。
/** CaFactory工厂类 **/
public class CarFactory {
public static Car createHongQiCar(){
Car car = new Car();
car.setBrand("红旗QQ");
return car;
}
}
/** Spring配置文件 **/
......................
<bean id="car1" class="com.xxxx.xxxx.carFactory" factory-method="createHongQiCar"/>
3-4)注入参数详解
3-4-1)字面值
一般是指可用字符串表示的值
/** Spring配置文件 **/
......................
<bean id="car" class="com.XXXX.XXXX.Car">
<property name="maxSpeed">
<value>200</value>
</property>
<property name="brand">
<value><![CDATA[红旗&CA72]]></value>
</property>
</bean>
XML特殊字体符号(特殊符号 | 转义序列)
< < " &quto; & &
> > ' '
如果使用XML转义序列,可以使用以下
/** Spring配置文件 **/
......................
<property name="brand">
<value>红旗&CA72</value>
</property>
3-4-2)引用其他bean
3.4.2.1 引用本容器的Bean
<?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:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
<bean id="car" class="com.imooc.demo.bean.Car"
p:brand="红旗CC"
p:color="红色"
p:maxSpeed="280" />
<bean id="boss" class="com.imooc.demo.bean.Boss"
p:car-ref="car"/>