Spring的简介
基于依赖注入的核心机制、基于AOP的声明式事务管理,与多种持久层技术的整合。使用Spring框架必须使用Spring Core Container只要由org.springframework.core、org.springframework.beans、org.springframework.context、org.springframework.expression四个包及其子包组成。
- 像大工厂一样,负责创建、管理所有Java对象,这些Java对象就是Bean。
- 管理容器中Bean之间的依赖关系
- 本质是通过XML配置文件来驱动Java代码
使用Spring管理bean
Spring容器是一个工厂。
Bean是Spring容器管理的对象,一切Java对象都可以是Bean。
bean与Java Bean的不同
- 写法不同:Java Bean必须遵守特定的规范,必须给每个属性提供对应的getter和setter方法,而Bean只需提供setter方法。
- 用处不同:Bean是Java实例、Java组件,JavaBean通常作为DTO(数据传输对象)来封装值对象,来传递参数
- 生命周期不同:JavaBean作为值对象传递,不接受任何容器管理其生命周期。Bean由Spring管理生命周期。
<?xml version="1.0" encoding="UTF-8"?>
<beans>
<!-- 配置db.properyies文件位置 -->
<bean id="configurer" class="org.springframework.beans.factory.config.PreferencesPlaceholderConfigurer">
<property name="locations" value="classpath:db.properties"></property>
</bean>
</beans>
<bean/>驱动spring以反射方式调用该类无参的构造器。id为Bean的唯一标识,通过id属性值访问Bean和管理Bean之间的依赖。class指定Bean的实现类。
<property/>驱动spring在底层以反射执行setter方法赋值。 name属性决定执行哪个setter方法,value或ref决定执行setter方法传入的参数。ref可指定一个bean属性,该属性用于引用容器内中其他Bean实例的id属性值。
<value>是<property/>的子元素相当于value,可指定调用setDriverClass()方法。的参数值为com.mysql.jdbc.Driver。设值注入。现在用得少。
程序通过Spring容器来访问容器中的Bean,ApplicationContext是Spring容器最常用的接口,有如下两种实现类:
- ClassPathXmlApplicationContext:从类加载路径下搜索配置文件,根据配置文件创建Spring容器。通常用这个。
- FileSystemXmlApplicationContext:从文件系统的相对路径
public class BeanTest
{
public static void main(String[] args)throws Exception{
// 创建Spring容器
ApplicationContext ctx = new ClassPathXmlApplicationContext("bean.xml");
// 获取id为person的Bean
Person p = ctx.getBean("person",Person.Class);
}
}
Spring的核心机制:依赖注入(DI ,Dependency Injection)
依赖:A对象调用B对象的方法,即A对象依赖于B对象。
注入普通的属性值,还可以注入其他Bean的引用。当某个Java实例需要其他Java实例时,系统自动提供所需实例,无需程序显示获取。
工厂模式和被依赖对象的接口耦合,被依赖对象交给工厂创建。
现在只需被动的等待Spring容器注入。
实现方法:
- 设值注入。IOC(控制反转)容器使用成员变量的setter方法来注入被依赖对象
- 构造注入。IOC(控制反转)容器使用构造器来注入被依赖对象
Spring推荐面向接口编程。不论调用者还是被依赖者都定义为接口。也可以通过注解,利用反射创建实例。
public class Chinese implements Person{
private Axe axe;
//设值注入所需的setter方法
public void setAxe(Axe axe){
this.axe=axe;
}
public void useAxe(){
// 实现Person接口的useAxe方法
System.out.println(axe.chop());
//调用chop方法,表明Person对象依赖于axe对象
}
}
使用XML配置文件指定实例之间的依赖关系。
构造注入
通俗来说,就是驱动Spring底层以反射方式执行带指定参数的构造器。
问题:<bean/>总是驱动Spring执行无参的构造器来创建对象,怎么驱动Spring执行有参数的构造器???
答案是<contructor-arg />子元素。<contructor-arg />子元素代表一个构造器参数。
public class Chinese implements Person{
private Axe axe;
//构造注入所需的带参数的构造器
public Chinese(Axe axe){
this.axe=axe;
}
public void useAxe(){
// 实现Person接口的useAxe方法
System.out.println(axe.chop());
//调用chop方法,表明Person对象依赖于axe对象
}
}
//对应的配置文件添加<contructor-arg />子元素
优先依赖的,优先注入。
建议:以设值注入为主,构造注入为辅。依赖关系无需变化的注入,就是用构造注入。
Spring的核心接口
ApplicationContext和BeanFactory,ApplicationContext是BeanFactory的子接口
BeanFactory
方法
- boolean containsBean(String name):
- <T> T getBean(Class<T> requiredType)返回属于requiredType类型的Bean实例。Object getBean(String name)容器id为name的Bean实例
- Class<?> getType(String name)
注意事项
- 创建BeanFactory实例时,必须提供XML配置文件作为参数,XML配置文件通常使用Resource对象传入。(Resource接口是Spring提供的资源访问接口)
- 如果需要加载多个配置文件来创建Spring容器,利用ApplicationContext来创建SessionFactory的实例。
ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml","service.xml");
ApplicationContext
使用ApplicationContext实例作为容器,Spring的上下文。
允许以声明式方式操作容器,除了提供BeanFactory所支持的全部功能外,还支持如下功能:
- ApplicationContext默认会预初始化所有的singleton Bean,也可通过配置取消预初始化。不加特殊配置,Bean默认为singleton行为
- ApplicationContext继承MessageSource接口,提供国际化支持。
- 资源访问,如URL和文件
- 事件机制
- 同时加载多个配置文件
- 以声明式方式启动创建Spring容器
优先使用ApplicationContext
<bean />元素指定lazy-init="true"阻止容器预初始化该Bean
ApplicationContext的国际化支持
ApplicationContext继承MessageSource接口,提供国际化支持
String getMessage(String code,Object[] args,Locale loc)
String getMessage(String code,Object[] args,Locale loc)
ApplicationContext的事件机制
ApplicationContext的事件机 制是观察者设计模式实现。通过ApplicationEvent(容器事件)和ApplicationListener(监听器)接口实现事件处理。
事件源、事件和事件监听器组成
Spring容器中的Bean
- 开发Bean
- 配置Bean
Bean的基本定义和别名
<beans />元素是Spring的根元素,属性如下:
- default-merge:指定所有Bean默认的merge行为
- default-lazy-init:指定所有Bean默认的延迟初始化
- default-autowire:自动装配行为。no、byName、byType、constructor、autodetect
- default-autowire-candidates:指定所有Bean默认是否作为作为自动装配的候选Bean。不做自动装配设为false。
- default-init-method:初始化方法
- default-destroy-method:回收方法
定义Bean时,通常指定两个属性:
- id:Bean的唯一标识
- class:实现类
- name:指定别名,多个别名可用逗号、冒号、空格
- <alias />子元素为已有的Bean指定别名。name:指定Bean实例的标志,alias:别名
容器中Bean的作用域
5种作用域:
- singleton(常用):默认单例,整个Spring IOC容器中,singleton只生成一个bean实例
- prototype(常用):每次通过容器的getBean()方法获取prototype作用域的Bean,都将产生新的实例
- request:对于一次HTTP请求,request作用域的Bean就只生成一个实例。Web应用中生效
- session:对于一次HTTP会话,session作用域的Bean就只生成一个实例。Web应用中生效
- global session:每个全局的HTTP session对应一个作用域。仅在使用portlet context有效,Web应用中生效。
使用自动装配注入合作者Bean
通过<bean />的autowire属性指定或<beans />的default-autowire指定。属性值如下:
- no
- byName:根据setter的方法名。没找到匹配BeanSpring不做任何事情。
- byType:根据setter的方法参数类型。容器包含多于一个的匹配参数类型实例就会抛出异常。
- constructor:与byType相似,区别在于自动匹配构造器的参数。如果找不到匹配与构造器参数类型匹配的Bean就会抛出错误
- autodetect:Spring根据Bean内部结构,自行决定使用construct或byType策略。如果是默认构造函数就会使用byType。
注入嵌套Bean
如果某个Bean所依赖的Bean不想被Spring容器直接访问,可以使用嵌套Bean。
嵌套Bean:把<bean />作为<property/>或<contructor-args/>的子元素,那么该<bean/>元素配置的Bean仅仅作为setter注入、构造注入的参数。由于容器不能获取嵌套Bean,所以不用指定id
本质上与使用ref引用容器中的另一个Bean一样。
小贴士
- 形参类型是基本类型、String、日期等,用value指定字面值即可。
- 形参类型是复合类(如Person、Dog、DataSource等Java对象)作为实参。1.使用ref引用容器中已配置的Bean(Java对象)2.使用<bean/>元素配置嵌套Bean
注入集合值
在<property/>元素下添加<list/>、<set/>、<map/>和<props/>设置集合参数值
<property name="">
<list>
<!--每个value、ref、bean都配置List元素 -->
<value>小学</value>
<value>中学</value>
</list>
<property/>
<property name="">
<map>
<entry key="" value=""/>
<entry key="" value=""/>
</map>
<property/>
<property name="">
<map>
<entry key="" value-ref=""/>
<entry key="" value-ref=""/>
</map>
<property/>
<property name="">
<props>
<!--每个key、value只能是字符串 -->
<prop key="属性名"></prop>
<prop key="血压">125</prop>
<prop key="身高">163</prop>
<props/>
<property/>
<property name="">
<set>
<!--每个value、ref、bean都配置set元素 -->
<value>普通字符串</value>
<bean class="类的路径" />
<ref bean="类名" />
<list>
<value></value>
<set>
<value type="int"></value>
</set>
</list>
</set>
<property/>
组合属性
除最后一个属性外,其他属性不能为null
Java配置管理
Java配置类的三个Annotation
- @Configuration:用于修饰配置类
- @Bean:修饰一个方法,将该方法的返回值定义成容器中的一个Bean
- @Value:修饰Field,为该Field配置一个值
- @Import:修饰Java配置类,用于向当前Java配置类中导入其他Java配置类
- @Scope:修饰一个方法,方法对应的Bean的作用域
- @Lazy:修饰一个方法,方法对应的Bean是否延迟初始化
- @DependsOn:修饰一个方法,指定在初始化该方法对应的Bean及其依赖关系之前初始化指定的Bean。
以XML配置方式为主,需要在XML配置中加载Java类配置
<!-- 加载Java配置类 -->
<bean class="org.crazyit.app.config.AppConfig">
以Java类配置为主,借助@ImportResources注解修饰Java配置类
@Configuration
// 导入XML配置
@ImportResources("classpath:/beans.xml")
创建Bean的3种方式
- 调用构造器创建Bean
- 调用静态工厂方法创建Bean
- 调用实例工厂方法创建Bean
调用构造器创建Bean
如果不采用构造注入,Spring底层默认调用Bean类的无参构造器创建实例。所有基本类型初始化为0或false,所有引用类型初始化为null。根据配置文件实例化被依赖的Bean,为Bean注入依赖关系,最后将一个完整的Bean实例返回程序。
调用静态工厂方法创建Bean
<bean />必须指定class属性。此时class指定的是静态工厂类。还需要使用factory-method属性指定静态工厂方法。Spring调用静态工厂方法返回Bean实例。
public class BeingFactory{
//返回Being实例的静态工厂方法
// 参数arg决定返回哪个Being类的实例
public static Being getBeing(String arg){
if(arg.equalsIgnoreCase("dog")){
return new Dog();
// 返回Dog实例
}
// 否则返回Cat实例
else{
return new Cat();
}
}
}
<bean class="BeanFactory" factory-method="getBeing">
<!-- 配置静态工厂方法的参数 -->
<constructor-arg value="dog"/>
<property name="msg" value="the dog"/>
</bean>
调用实例工厂方法创建Bean
实例工厂和静态工厂只有一点不同:调用静态工厂方法只需使用工厂类,而调用实例工厂需要工厂实例。
配置静态工厂方法使用class指定静态工厂类,配置实例工厂使用factory-bean指定工厂实例。
使用实例工厂时,<bean/>无须class属性,Spring容器调用实例工厂的工厂方法创建Bean实例。
实例工厂方法创建<bean/>元素时需要指定的属性:
- factory-bean:指定工厂Bean的id
- factory-method:指定实例工厂的工厂方法
抽象Bean与子Bean
<bean/>元素下添加abstract="true",不指定class就是抽象Bean,不能被实例化,只能被继承
<bean/>元素下添加parent="父Bean的id",该bean是一个子bean.
Bean继承和Java继承的区别
- Spring中子Bean与父Bean可以是不同类型,Java继承保证子类是特殊父类
- Bean的继承是实例间的关系,主要表现在参数值的延续。Java继承是类之间的关系,主要表现在方法、属性的延续。
- 子Bean不能作为父Bean使用,不具备多态性,Java继承子类实例可以当父类实例使用
工厂Bean:与前面不同,Spring的一种特殊Bean,必须实现FactoryBean接口。返回该Bean实例的getObject()方法的返回值。开发者实现getObject()方法。(返回某个类型的值)
容器中Bean的生命周期
Spring可以管理singleton作用域的Bean的生命周期,Spring可以精确的知道该Bean何时被创建、初始化完成、何时准备销毁该实例。
prototype作用域的Bean,Spring仅仅负责创建。其他就交给客户端代码管理,无法管理。
注入依赖关系之后
- 使用init-method属性:指定某个方法在Bean注入依赖关系之后自动执行
- InitializingBean接口:在为Bean注入依赖关系之后实现void afterPropertiesSet() throws Exception
Bean销毁之前
- 使用destroy-method属性:指定某个方法在Bean销毁之前自动执行
- 实现disposableBean接口:void destroy() throws Exception
获取其他Bean的属性值
PropertyPathFactoryBean用来获取其他Bean的属性值。(实际上就是getter方法的返回值)
- 调用哪个对象:由PropertyPathFactoryBean的setTargetObject(Object targetObject)方法指定
- 调用哪个getter方法:由PropertyPathFactoryBean的setPropertyPath(String propertyPath)方法指定。
<bean class="" class="org.springframework.beans.factory.config.PropertyPathFactoryBean">
<property name="targetBeanName" value="person"/>
<property name="propertyPath" value="son"/>
</bean>
<util:property-path/>作为PropertyPathFactoryBean简化配置。id属性:指定getter方法的返回值定义成名为id的Bean实例。path:指定哪个Bean实例、哪个属性暴露出来。
获取Field值
通过FieldRetrievingFactoryBean类,可访问类的静态Field或对象的实例Field值。可将获取的值注入到其他Bean,也可直接定义新的Bean。<util:constant/>
<bean class="" class="org.springframework.beans.factory.config.PropertyPathFactoryBean">
<property name="targetClass" value="java.sql.Connection"/>
<property name="targetField" value="TRANSACTION_SERIALIZABLE"/>
</bean>
获取方法返回值
通过MethodInvokingFactoryBean工厂Bean,可以获取任意类的类方法。
SpEL
Spring表达式语言即SpEL。略
Spring的零配置支持
- @Component:标注普通Java Bean类,首字母小写,其他不变
- @Controller:控制器组件类
- @Service:业务逻辑组件类
- @Repository:DAO组件类
- @Scope:作用域
- @Resource(name=" ")和<property/>的ref效果相同,可以省略name。修饰setter方法或实例变量
- @PostConstruct修饰的方法是Bean创建之后执行方法
- @PreDestroy修饰的方法是Bean销毁之前执行方法
- @DependsOn:强制初始化其他Bean
- @Lazy:指定Bean是否取消预初始化。延迟。
- @Autowired:自动装配,可以修饰setter方法、普通方法、实例变量和构造器。默认采用byType自动装配策略
- @Qualifier:根据Bean的id执行自动装配
自动扫描指定包及其子包下的所有Bean类<context:component-scan base-package="org.crazyit.app.service"/>
<context:component-scan base-package="org.crazyit.app.service">
<context:include-filter type="regex" expression=".*Chinese"/>
<context:include-filter type="regex" expression=".*Axe"/>
</context:component-scan>
<context:exclude-filter>或<context:include-filter>子元素指定Spring Bean类,只要位于指定路径下的Java类满足这个规则,就会当成Bean类处理。
type:指定过滤器类型
expression:过滤器所需要的表达式
Spring内建支持的4种过滤器:annotation(annotation过滤器)、assignable(类名过滤器)、regex(正则表达式)、aspectj(aspectj过滤器)
资源访问
资源=>XML配置文件、二进制流等各种类型文件
Resource接口的实现类有UrlResource等
- 访问网络资源
- 访问类加载路径下的资源
- 访问文件系统资源
- 访问应用相关资源
- 访问字节数组资源
ApplicationContext中使用资源
1.使用ApplicationContext实现类指定访问策略
- ClassPathXmlApplicationContext:对应使用ClassPathResource进行资源访问
- FileSystemXmlApplicationContext:对应使用FileSystemResource进行资源访问
- XmlWebApplicationContext:对应使用ServletContextResource进行资源访问
2.使用前缀指定访问策略
http:、ftp:等前缀,用来确定对应的资源访问策略。
3.classpath*:前缀用法