您的位置:首页 > 编程语言 > Java开发

Spring学习笔记(一)IOC与Spring基础xml配置

2016-09-09 14:38 741 查看

1. IOC与DI

IOC(Inversion of Control):控制反转

DI(Dependency Injection):依赖注入

“控制反转”“依赖注入”其实是同一个概念:

改变由调用者创建被调用者的过程。被调用者依赖Spring容器注入到调用者中。

之所以出现两个名词是因为“控制反转”比较难懂,听者不明所以,所以有了更形象的“依赖注入”

2. IOC的发展历程



3. Spring容器

简单说,就是Spring中生成“Bean”的工厂,并管理“Bean”的生命周期。Spring的配置文件说到底就是“Bean”的配置。

“Bean”是Spring管理的基本单位,不仅仅指简单的POJO类,组件也是“Bean”,例如数据源、事务管理器,Hibernate的SessionFactory。

Spring中内置了两种基础DI容器:
BeanFactory
ApplicationContext


ApplicationContext
继承了
BeanFactory
的所有特性。关系如下图:



BeanFactory
应用与内存、CPU资源受限的场合,一般情况下优先使用
ApplicationContext
,因为它除了拥有
BeanFactory
支持的所有功能,还可以:

载入多个配置文件

提供国际化支持

事件机制

默认初始化所有的singleton Bean
BeanFactory
则不会)

常用的
ApplicationContext
的子类如下图:



XmlWebApplicationContext:面向Web应用

AnnotationConfigApplicationContext:基于注解存储DI元数据

XmlPortlerApplicationContext:面向Portal应用

ClassPathXmlApplicationContext、FileSystemXmlApplicationContext:适用于各种场景

4. 注入方式

Spring的注入方式有三种:设值注入构造器注入工厂注入

设置注入和构造器注入

实体类:

public class Person{
public String name;
private Axe axe;

public Person(Axe axe, String name) {
System.out.println("Person 的带参构造方法");
this.axe = axe;
this.name = name;
}
/**
* 砍柴
*/
public void choopWood() {
if(axe!=null){
axe.useAxe();
}
}

public void info() {
System.out.println("This person's name is " + name);
}

public void setName(String name) {
this.name = name;
}

public void setAxe(Axe axe) {
this.axe = axe;

}

}


注入类:

public interface Axe {

public void useAxe();
}

public class StoneAxe implements Axe {

public void useAxe() {
System.out.println(test + "石斧砍柴很慢");
}
}

public class IronAxe implements Axe{

public void useAxe() {
System.out.println("铁斧砍柴很快");
}

}


Spring配置文件:

<?xml version="1.0" encoding="UTF-8"?>
<!--spring配置文件的根元素,使用spring-beans-3.0.xsd语义约束(.xsd都是语言约束文件)
xmlns:p配置可使用p标签更方便的配置属性 -->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> 
<!-- id 表示你这个组件的名字,class表示组件类;autowire为是否自动加载; lazy-init为是否懒加载,即applicationContext容器启动不自动加载 -->
<bean id="person" class="test.wsz.spring.bean.Person" lazy-init="true" autowire="byType" >
<!--自定义set注入,name 为成员变量名称,value为自定义的值 -->
<property name="name" value="wsz"></property>
<!--引用set注入,name 为成员变量名称,ref为注入bean的id -->
<property name="axe" ref="ironaxe"></property>
<!--构造注入,index为形参的位置,从0开始,ref为注入bean的id -->
<constructor-arg ref="stoneaxe" index="0" />
<constructor-arg value="wsz" index="1" />
</bean>

<!--其余实体Bean-->
<bean id="ironaxe" class="test.wsz.spring.bean.IronAxe" />
<bean id="stoneaxe" class="test.wsz.spring.bean.StoneAxe" />

</beans>


从配置的注释可以知道“设置注入”和“构造器注入”的配置方法。

“设置注入”会调用成员变量的
setXXX
方法。

“构造器注入”会调用类对应的构造方法。

测试代码:

ApplicationContext context=new ClassPathXmlApplicationContext("config/spring-config.xml");
Person person=context.getBean("person",Person.class);
person.info();
person.choopWood();


工厂方式注入

工厂方式注入有好几种,这里只举“静态工厂注入”和“工厂Bean的例子”

静态工厂注入

先创建一个工厂类:

/**
* 静态简单工程类
*/
public class AxeFactory {
/**
* 获取产品的方法,根据形参返回不同的产品
*/
public static Axe getAxe(String type) {
if("stone".equals(type))
return new StoneAxe();

else if("iron".equals(type))
return new IronAxe();

return new StoneAxe();
}
}


再修改之前的类当成产品类:

public class StoneAxe implements Axe {
private String test;

public StoneAxe() {
System.out.println("调用StoneAxe的无参构造方法");
}

public void useAxe() {
System.out.println(test + "石斧砍柴很慢");
}

public void setTest(String test) {
this.test = test;
}
}


再在xml文件中进行对应的配置:

<!--静态工厂类获取Bean,class为工厂类;factory-method为工厂获取方法-->
<bean id="stone" class="test.wsz.spring.factory.AxeFactory" factory-method="getAxe">
<!--设置传入工厂类获取产品方法形参的值-->
<constructor-arg value="stone"/>
<!--设置注入产品Bean的属性-->
<property name="test" value="哈哈,"></property>
</bean>


根据配置我们可以知道,现在设置的工厂类返回
StoneAxe
,我们进行测试:

Axe axe=context.getBean("stone",Axe.class);
axe.useAxe();


输出:

哈哈,石斧砍柴很慢


工厂Bean注入

这种方式配置比较简单。只需要创建一个实现了Spring工厂接口的工厂类,再将这个工厂类配置在
<Beans   />
中即可。

工厂类,需实现接口的三个方法:

public class AxeBeanFactory implements FactoryBean<Axe>{
Axe axe=null;
/**
* 返回产品
*/
public Axe getObject() throws Exception {
if(axe==null){
axe=new StoneAxe();
}
return axe;
}
/**
* 返回产品的类型
*/
public Class<?> getObjectType() {
return Axe.class;
}
/**
* 是否单例
*/
public boolean isSingleton() {
return true;
}
}


xml配置:

<!--容器中的工厂Bean-->
<bean id="stonefactory" class="test.wsz.spring.factory.AxeBeanFactory" />


值得注意的是,虽然
<Bean />
中配置的好像是工厂类,但实现了Spring工厂接口的该类,最终
getBean()
时返回的是对应的产品类。

测试代码:

Axe axe=context.getBean("stonefactory",Axe.class);
axe.useAxe();


输出:

null石斧砍柴很慢


5. 配置细节

Spring的配置的参数太多,这里只总结一些常用的。复杂的等用到时再看书就行。

<bean />
中的常用配置

scope:

Bean的作用域,有5种:

singleton:单例模式,即整个容器里面该Bean实例只有一个,默认

prototype:原型模式,每次
getBean
获取的是一个新创建的对象

request:每个HTTP请求,产生一个实例

session:每个HTTP session,产生一个实例

global session:每个全局的HTTP session,产生一个实例

lazy-init:

懒加载,当使用使用
ApplicationContext
时,会自动初始化所有的
singleton
的“Bean”(“Bean”默认是
singleton
)。设置懒加载即不自动初始化这个类。

autowire:

自动注入。即你不用在配置中设定成员变量的注入。设置为
byType
时,会自动匹配依赖类型相同的Bean,若有多个类型相同的会抛出异常。设置为
byName
时,会查找id名与属性名相等的Bean。

init-method:

指定Bean依赖关系设置完毕后执行的方法。另外一种实现方式是让Bean类实现
InitializingBean
接口

destory-method:

指定Bean销毁之前执行的方法。另外一种实现方式是让Bean类实现
DisposableBean
接口

p名称空间:

可以看作一个语法糖,在
<beans />
中添加:

xmlns:p="http://www.springframework.org/schema/p"


即可更简单的设置注入:

<bean id="person" class="test.wsz.spring.bean.Person"
p:name="name" />


等效于

<bean id="person" class="test.wsz.spring.bean.Person" >
<property name="name" value="wsz"></property>
</bean>


6. 免XML的JAVA类配置

这个其实应用场景比较少,毕竟单纯用Java类完成复杂的Spring配置还是比较困难的。下面简单给个例子:

@Configuration
public class Config {

@Value("大树") String personName;   //注入Bean的属性中的值
@Bean(name="person")
public Person person(){
Person p=new Person();
p.setName(personName);
p.setAxe(stoneAxe());
return p;
}
@Bean(name="stoneAxe")
public Axe stoneAxe() {
Axe axe=new StoneAxe();

return axe;
}
}


除了纯粹的Java类配置,还可以在xml中引用Java类配置,或者在Java类配置中引用xml配置。有兴趣的朋友可以自行百度。

本文总结于

《疯狂JavaEE》的第七章《Spring的基本用法》
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  spring ioc