Spring学习笔记(一)
基础
Spring介绍
- Spring是一个开源框架。
- Spring为简化企业级应用开发而生,使用Spring可以使简单的JavaBean实现以前只有EJB才能实现的功能。
- Spring是一个IOC(DI)和AOP容器框架。
- 轻量级:Spring是非侵入式的-基于Spring开发的应用中的对象可以不依赖于Spring的API
- 依赖注入(DI):Dependency Injection,IOC
- 面向切面编程(AOP-aspect oriented programming)
- 容器:Spring是一个容器,因为它包含并且管理应用对象的生命周期
- 框架:Spring实现了使用简单的组件配置组合成一个复杂的应用,在Spring中可以使用XML和Java注解组合这些对象。
- 一站式:在IOC和AOP的基础上可以整合各种企业应用的开源框架和优秀的第三方类库
核心特性
- IoC容器
- Spring事件
- 资源管理
- 国际化
- 校验
- 数据绑定
- 类型转换
- Spring表达式
- 面向切面编程
IOC和DI
IOC(Inversion of Control):其思想是反转资源获取的方向。
传统的资源查找方式要求组件向容器发起请求查找资源,作为回应,容器适时的返回资源,而应用了IOC之后,则是容器主动地将资源推送给它所管理的组件,组件所要做的仅是选择一种合适的方式来接受资源,这种行为 也被称为查找的被动形式。
IoC容器的职责:
- 依赖处理
- 依赖查找
- 依赖注入
- 生命周期管理
- 容器
- 托管的资源
- 配置
- 容器
- 外部化配置
- 托管资源
DI:IOC的另一种表述方式,即组件以一些预先定义好的方式(例如:setter方法)接受来自如容器的资源注入,相对于IOC而言,这种表述更直接。
配置Bean
配置形式:基于XML文件的方式,基于注解的方式
Bean的配置方式:通过全类名(反射),通过工厂方法(静态工厂方法&实例工厂方法),FactoryBean
<?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
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子节点指定属性值
属性注入是实际应用中最常用的注入方式
<property name="name" value="Spring"/>
构造方法注入
通过构造方法注入Bean的属性值或者依赖的对象,他保证了Bean实例在实例化后就可以使用。
构造器注入在<constructor-arg>元素里声明属性
<constructor-arg>
中没有name属性
<!--可以指定参数的位置和参数的类型,以区分重载的构造器-->
<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>
<constructor-arg type="int">
<value>240</value>
</constructor-arg>
若注入的值含有特殊字符,可以使用<![CDATA[]]>将字面值包起来
<constructor-arg type="int">
<value><![CDATA[<shanghai^]]></value>
</constructor-arg>
工厂方式注入
(很少使用,不推荐)
在Bean中引用其他Bean
(ref元素)
<bean id="person" class="Preson">
<property name="name" value="Tom"/>
<property name="age" value="24"/>
<property name="car" ref="car2"/>
</bean>
也可以在属性或构造器里包含Bean的声明
<!--内部bean,不能被外部引用,只能在内部使用-->
<property name="car">
<bean class="Car">
<constructor-arg value="ford"/>
<constructor-arg value="Chanan"/>
<constructor-arg value="200000" type="double"/>
</bean>
</property>
null 值和级联属性
<constructor-arg><null/></constructor-arg>
级联属性
<property name="car.price" value="20000"/>
为级联属性赋值:属性需要先初始化后才能为级联属性赋值,否则会有异常。
集合属性
<!--测试配置集合属性-->
<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类型
<!--配置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类型
<!--配置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命名空间
<bean id="person5" class="com.test.spring.collection.Person" p:age="30" p:name="Queen" p:cars-ref="cars"/>
Spring自动装配
在<bean>
的autowire属性里面指定自动装配的模式。
原始方式
<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"/>
自动装配
<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之间的关系
继承
<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
<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配置相分离。
<!--导入属性文件-->
<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指定初始化和销毁方法。
<bean id="car" class="com.test.spring.cycle.Car" init-method="init" destroy-method="destory">
<property name="brand" value="Audi"/>
</bean>
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
<!--配置bean的后置处理器-->
<bean class="com.test.spring.cycle.MyBeanPostProcessor"/>
MyBeanPostProcessor.java
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实例。
<bean id="car1" class="com.test.spring.factory.StaticCarFactory" factory-method="getCar">
<constructor-arg value="Audi"/>
</bean>
class:指向静态工厂方法的全类名
factory-method:只想静态工厂方法的名字
constructor-arg:配置传入的参数
实例工厂方法
现需要创建工厂本身,再调用工厂的实例方法来返回Bean实例
FactoryBean配置
<bean id="car" class="com.test.spring.FactoryBean.CarFactoryBean">
<property name="brand" value="BMW"/>
</bean>
com.test.spring.FactoryBean.CarFactoryBean
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配合使用
<context:component-scan base-package="com.test.spring.annotation.entity" resource-pattern="repository/*.class"/>
<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属性