L1nker4

Spring学习笔记(一)

Word count: 3,189 / Reading time: 14 min
2019/03/14 Share

Spring介绍

  1. Spring是一个开源框架。
  2. Spring为简化企业级应用开发而生,使用Spring可以使简单的JavaBean实现以前只有EJB才能实现的功能。
  3. Spring是一个IOC(DI)和AOP容器框架。
  4. 轻量级:Spring是非侵入式的-基于Spring开发的应用中的对象可以不依赖于Spring的API
  5. 依赖注入(DI):Dependency Injection,IOC
  6. 面向切面编程(AOP-aspect oriented programming)
  7. 容器:Spring是一个容器,因为它包含并且管理应用对象的生命周期
  8. 框架:Spring实现了使用简单的组件配置组合成一个复杂的应用,在Spring中可以使用XML和Java注解组合这些对象。
  9. 一站式:在IOC和AOP的基础上可以整合各种企业应用的开源框架和优秀的第三方类库

IOC和DI

IOC(Inversion of Control):其思想是反转资源获取的方向。

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

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

配置Bean

配置形式:基于XML文件的方式,基于注解的方式

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

1
2
3
4
5
6
7
8
9
10
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

<!--配置Bean-->
<bean id="helloWorld" class="HelloWorld">
<property name="name" value="Spring"/>
</bean>
</beans>

class:bean的全类名,通过反射的方式在IOC容器中创建bean,所以要求bean要有无参构造器

id:标识容易中的bean,id唯一

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

  • BeanFactory:IOC容器的基本实现
  • ApplicationContext 提供了更多的高级特大型,是BeanFactory的子接口

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

ApplicationContext 面向使用Spring框架的开发者,几乎所有的应用场合都直接使用ApplicationContext

1
2
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
HelloWorld helloWorld = (HelloWorld) ctx.getBean("helloWorld");

利用id定位到IOC容器中的Bean

ApplicationContext 代表IOC容器

ApplicationContext的两个实现类

ClassPathXmlApplicationContext 是从类路径下加载配置文件

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

依赖注入的方式

属性注入(最常用)

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

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

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

1
<property name="name" value="Spring"/>

构造方法注入

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

构造器注入在<constructor-arg>元素里声明属性

<constructor-arg>中没有name属性

1
2
3
4
5
6
<!--可以指定参数的位置和参数的类型,以区分重载的构造器-->
<bean id="car2" class="Car">
<constructor-arg value="BMW" type="java.lang.String"/>
<constructor-arg value="Shanghai" type="java.lang.String"/>
<constructor-arg value="240" type="int"/>
</bean>
1
2
3
<constructor-arg type="int">
<value>240</value>
</constructor-arg>

若注入的值含有特殊字符,可以使用<![CDATA[]]>将字面值包起来

1
2
3
<constructor-arg type="int">
<value><![CDATA[<shanghai^]]></value>
</constructor-arg>

工厂方式注入

(很少使用,不推荐)

在Bean中引用其他Bean

(ref元素)

1
2
3
4
5
<bean id="person" class="Preson">
<property name="name" value="Tom"/>
<property name="age" value="24"/>
<property name="car" ref="car2"/>
</bean>

也可以在属性或构造器里包含Bean的声明

1
2
3
4
5
6
7
8
<!--内部bean,不能被外部引用,只能在内部使用-->
<property name="car">
<bean class="Car">
<constructor-arg value="ford"/>
<constructor-arg value="Chanan"/>
<constructor-arg value="200000" type="double"/>
</bean>
</property>

null 值和级联属性

1
<constructor-arg><null/></constructor-arg>

级联属性

1
<property name="car.price" value="20000"/>

为级联属性赋值:属性需要先初始化后才能为级联属性赋值,否则会有异常。

集合属性

1
2
3
4
5
6
7
8
9
10
11
<!--测试配置集合属性-->
<bean id="person3" class="com.test.spring.collection.Person">
<property name="name" value="Mike"/>
<property name="age" value="27"/>
<property name="cars">
<list>
<ref bean="car"/>
<ref bean="car2"/>
</list>
</property>
</bean>

数组也用<list>

Set使用<set>

Map类型

1
2
3
4
5
6
7
8
9
10
<!--配置map属性值-->
<bean id="newPerson" class="com.test.spring.collection.NewPerson">
<property name="name" value="rose"/>
<property name="age" value="28"/>
<property name="cars">
<map>
<entry key="AA" value-ref="car"/>
<entry key="BB" value-ref="car2"/>
</map>
</property>

Properties类型

1
2
3
4
5
6
7
8
9
10
11
12
<!--配置Properties属性值-->
<bean id="dataSource" class="com.test.spring.collection.DataSource">
<property name="properties">
<props>
<prop key="user">root</prop>
<prop key="password">123456</prop>
<prop key="jdbcUrl">jdbc:mysql://xxx</prop>
<prop key="DriverClass">com.mysql.jdbc.Driver</prop>

</props>
</property>
</bean>

p命名空间

通过p命名空间为bean的属性赋值,需要先导入p命名空间

1
<bean id="person5" class="com.test.spring.collection.Person" p:age="30" p:name="Queen" p:cars-ref="cars"/>

Spring自动装配

<bean>的autowire属性里面指定自动装配的模式。

原始方式
1
2
3
4
5
<bean id="address" class="com.test.spring.autowire.Address" p:city="Beijing" p:street="tiananmen"/>

<bean id="car" class="com.test.spring.autowire.Car" p:brand="Audi" p:price="300000"/>

<bean id="person" class="com.test.spring.autowire.Person" p:name="Tom" p:address-ref="address" p:car-ref="car"/>
自动装配
1
<bean id="person" class="com.test.spring.autowire.Person" p:name="Tom" autowire="byName"/>

使用autowire属性指定自动装配的方式

byName:根据bean的名字和当前bean的setter风格的属性名进行自动装配

ByType:根据bean的类型和当前bean的属性的类型进行自动装配,若IOC容器中有一个以上的类型匹配的Bean,则抛异常。

自动装配的缺点

不够灵活,autowire要么根据类型自动匹配,要么根据名称自动匹配,不能兼有。

实际的项目中很少使用自动装配

Bean之间的关系

继承

1
2
<bean id="address" class="com.test.spring.autowire.Address" p:city="BeiJing" p:street="WuDaoKou"/>
<bean id="address2" class="com.test.spring.autowire.Address" p:street="DaZongShi" parent="address"/>
  • Spring允许继承Bean的配置
  • 子Bean从父Bean中继承配置,包括Bean的属性配置
  • 子Bean也可以覆盖从父Bean继承过来的配置
  • 父Bean可以作为配置模板,也可以作为Bean实例,若想把父Bean作为模板,可以设置<bean>的abstract属性为True,这样Spring将不会实例化这个Bean,这个抽象Bean就是用来继承的。
  • 并不是Bean元素里面所有属性都会被继承,比如:autowire,abstract等
  • 也可以忽略父Bean的class属性,让子Bean指定自己的类,而共享相同的属性配置,但此时必须设为true

依赖

需求:在配置Person时,必须有一个关联的car,换句话说person这个Bean依赖于car这个Bean

1
2
<bean id="car" class="com.test.spring.autowire.Car" p:brand="Audi" p:price="300000"/>
<bean id="person" class="com.test.spring.autowire.Person" p:name="tom" p:address-ref="address" depends-on="car"/>
  • Spring允许用户通过depends-on属性设定Bean前置依赖的Bean,前置依赖的Bean会在本Bean实例化之前创建好。
  • 如果前置依赖于多个Bean,则可以通过逗号,空格的方式配置Bean的名称

Bean的作用域

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

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

prototype:原型的,容器初始化时不创建bean实例,而在每次请求时都创建一个新的Bean实例,并返回

使用外部属性文件

在配置文件里面配置Bean的时候,有时候需要在Bean的配置里面混入系统部署的细节信息(文件路径,数据源配置信息),而这些部署细节实际上需要和Bean配置相分离。

1
2
3
4
5
6
7
8
9
<!--导入属性文件-->
<context:properties location="db.properties"/>
<!--使用外部属性文件的属性-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="user" value="${user}"/>
<property name="password" value="${password}"/>
<property name="driverClass" value="${driverclass}"/>
<property name="jdbcUrl" value="${jdbcUrl}"/>
</bean>

SpEL

  • Spring表达式语言:是一个支持运行时查询和操作对象圈的强大的表达式语言。
  • 语法类似于EL,SpEL使用#{—}作为定界符
  • SpEL为Bean的属性进行动态赋值提供了便利。

Bean的生命周期

  • Spring IOC容器可以管理Bean的生命周期,Spring允许在Bean生命周期的特定点执行定制的任务。
  • 在Bean的声明里面设置init-method和destory-method属性,为Bean指定初始化和销毁方法。
1
2
3
<bean id="car" class="com.test.spring.cycle.Car" init-method="init" destroy-method="destory">
<property name="brand" value="Audi"/>
</bean>
1
2
3
4
5
6
7
public static void main(String[] args) {
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("beans-cycle.xml");
Car car = (Car) ctx.getBean("car");
System.out.println(car);

ctx.close();
}

Bean的后置处理器

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

实现BeanPostProcessor接口,并实现:

Object postProcessBeforeInitialization(Object bean, String beanName) //init-method之前被调用
Object postProcessAfterInitialization(Object bean, String beanName) //init-method之后被调用

bean:bean实例本身

beanName:IOC容器配置的Bean的名字

返回值:是实际上返回给用户的那个Bean,注意:可以在以上两个方法中修改返回的Bean,甚至返回一个新的Bean

1
2
<!--配置bean的后置处理器-->
<bean class="com.test.spring.cycle.MyBeanPostProcessor"/>

MyBeanPostProcessor.java

1
2
3
4
5
6
7
8
9
10
11
12
13
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object o, String s) throws BeansException {
System.out.println("postProcessBeforeInitialization:"+o+","+s);
return o;
}

@Override
public Object postProcessAfterInitialization(Object o, String s) throws BeansException {
System.out.println(o+s);
return o;
}
}

工厂方法配置Bean

静态工厂方法

直接调用某一个类的静态方法就可以返回Bean实例

通过静态工厂方法来配置Bean,不是配置静态工厂方法实例,而是配置Bean实例。

1
2
3
<bean id="car1" class="com.test.spring.factory.StaticCarFactory" factory-method="getCar">
<constructor-arg value="Audi"/>
</bean>

class:指向静态工厂方法的全类名

factory-method:只想静态工厂方法的名字

constructor-arg:配置传入的参数

实例工厂方法

现需要创建工厂本身,再调用工厂的实例方法来返回Bean实例

FactoryBean配置

1
2
3
<bean id="car" class="com.test.spring.FactoryBean.CarFactoryBean">
<property name="brand" value="BMW"/>
</bean>

com.test.spring.FactoryBean.CarFactoryBean

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class CarFactoryBean implements FactoryBean {

private String brand;

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

//返回bean的对象
@Override
public Object getObject() throws Exception {
return new Car(brand, 400000);
}

//返回bean的类型
@Override
public Class<?> getObjectType() {
return Car.class;
}

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

注解配置Bean

在classpath中扫描组件

  • Spring能够从classpath下自动扫描,侦测和实例化具有特定注解的组件
  • 组件包括:
    • @Component:基本注解,标识了一个受Spring管理的组件
    • @Respository:标识持久层组件
    • @Service:标识业务层组件
    • @Controller:标识表现层组件 UserService userService
  • 对于扫描到的组件,Spring有默认的命名策略,使用非限定类名,第一个字母小写,也可以在注解中通过value属性标识组件的名称
  • 在组件类上使用了特定的注解之后,还需要在Spring的配置文件中声明 <context:component-scan>
    • base-package属性指定一个需要扫描的基类包,Spring容器会将扫描的这个基类包里及其子包中的所有类
    • resource-pattern属性扫描的资源
    • <context:include-filter>子节点表示要包含的目标类
    • <context:exclude-filter>子节点表示要排除在外的目标类,需要use-default-filters配合使用
1
<context:component-scan base-package="com.test.spring.annotation.entity" resource-pattern="repository/*.class"/>
1
2
3
<context:component-scan base-package="com.test.spring.annotation.entity">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>

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

使用@Autowired自动装配Bean

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

CATALOG
  1. 1. Spring介绍
    1. 1.0.1. IOC和DI
    2. 1.0.2. 配置Bean
    3. 1.0.3. 依赖注入的方式
      1. 1.0.3.1. 属性注入(最常用)
      2. 1.0.3.2. 构造方法注入
      3. 1.0.3.3. 工厂方式注入
        1. 1.0.3.3.1. 在Bean中引用其他Bean
      4. 1.0.3.4. null 值和级联属性
    4. 1.0.4. 集合属性
      1. 1.0.4.1. p命名空间
    5. 1.0.5. Spring自动装配
      1. 1.0.5.0.1. 原始方式
      2. 1.0.5.0.2. 自动装配
      3. 1.0.5.0.3. 自动装配的缺点
  2. 1.0.6. Bean之间的关系
    1. 1.0.6.1. 继承
    2. 1.0.6.2. 依赖
  3. 1.0.7. Bean的作用域
  4. 1.0.8. 使用外部属性文件
  5. 1.0.9. SpEL
  6. 1.0.10. Bean的生命周期
  7. 1.0.11. Bean的后置处理器
  8. 1.0.12. 工厂方法配置Bean
    1. 1.0.12.1. 静态工厂方法
    2. 1.0.12.2. 实例工厂方法
  9. 1.0.13. FactoryBean配置
  10. 1.0.14. 注解配置Bean
    1. 1.0.14.1. 在classpath中扫描组件
    2. 1.0.14.2. 使用@Autowired自动装配Bean