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和DI
IOC(Inversion of Control):其思想是反转资源获取的方向。
传统的资源查找方式要求组件向容器发起请求查找资源,作为回应,容器适时的返回资源,而应用了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 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
| <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
| <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
| <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 3
| <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 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; }
@Override public Object getObject() throws Exception { return new Car(brand, 400000); }
@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 2
| <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属性