注入
以前,对象对自己负责,如果他要用到其他类,则直接保存它的实例.
这样做后,类和工具就被绑在一起,如果工具改变了,就不得不改变类,最快想到的解决办法是利用抽象,将工具抽象,但抽象类无法实例化,如何才能得到工具类的实例呢,答案是从外部传入,也就是说在类里有一工具类的引用,然后对外公开setter方法,从外部将工具的实例传进去.这种方式就叫依赖注入.
在Spring中,我们在配置文件来声明要对某个类注入哪个类.然后在代码中,我们可以获得配置文件中所有已配置的类的实例.因为配置文件被解析成容器,配置的类全在容器中.
Spring容器有两种,一种是基本的容器,提供简单的应用:BeanFactory.另一种是BeanFactory的扩展:ApplicationContext.
BeanFactory
它采用工厂设计模式.负责创建和分发Bean,但工厂模式只能创建一个基类的类.而BeanFactory可以管理所有类型的类,只要在配置文件中声明了.声明方式就不介绍了.
Spring中有多种BeanFactory的实现,其中最常用的是:org.springframework.beans.factory.xml.XmlBeanFactory,它根据XML文件中的定义装载Bean.XmlBeanFactory需要一个org.springframework.core.io.Resource的实例给构造函数.该Resource对象提供XML文件给工厂.而在Spring中,该Resource也有很多实现:
Org.springframework.core.io.ByteArrayResource----配置内容由一组字节给定
Org.springframework.core.io.ClassPathResource---- 配置从classpath提取
Org.springframework.core.io.DescriptiveResource----可以忽略
Org.springframework.core.io.FileSystemResource----从文件中读取
Org.springframework.core.io.InputStreamResource----从输入流读入
Org.springframework.core.io.UrlResource---从给定URL读取
Org.springframework.web.portlet.context.PortletContextResource----在portlet上下文中的定义
Org.springframework.web.context.support.ServletContextResource---- 在servlet上下文中
因为在项目中我们都是把配置放在xml文件中,所以常用的应该是ClassPathResource,FileSystemResource,InputStreamResource.如:
BeanFactory factory = new XmlBeanFactory(new FileSystemResource(“c:/config.xml”))
这里是获得工厂,但这时候还不会实例化bean,它只是把bean的相关信息载入进来.只有在我们获得bean时才会实例化具体的类,如:
MyBean mybean = (MyBean)factory.getBean(“myBean”);
ApplicationContext
applicationContext比BeanFactory多了三个功能:国际化,载入文件资源(如图片),事件
在大多数情况下应该使用ApplicationContext.它有三个经常用到的实现:
1.
2.
3.
如:
ApplicationContext context = new FileSystemXmlApplication
ApplicationContext context = new ClassPathXmlAplicationCo
从上面可以看出,前者是在电脑中的具体文件地址.后者是一个相对目录的文件.而这个文件处的地方就是整个项目的类路径,包括引入的jar文件.所以一般将文件放在项目classpath的根目录下,这样免得它去找其他地方花时间.
上下文和工厂的另一个重要区别是工厂是在我们要获得对象时才实例化.而上下文是启动后预载入所有的对象,当我们要获得对象时就更快.
构造函数/属性注入
构造函数优点
1.
2.
3.
属性注入优点
1.
2.
3.
4.
前面已经介绍过了.通过构造函数或属性注入,都有几种情况:注入原始类型的值,注入对象.
具体用法查看上面Spring Core里的内容.
另一种特殊的注入是内部Bean注入:
<property name=””>
</property>
装配集合
上面说了可以注入基本类型(通过value)和自定义类(通过ref).但这两个只能传递单一值,如果要传递集合,就必须用其他标签,Spring提供四种:<list>,<set>,<map>,<props>.
List 和 set在类中的依赖属性是数组或Collection接口的某个实现时非常有用.注意的是,这里的list和set标签并不表示它们只能传递给java中的List和Set.
List
用法:
<property name=”valList”>
<property>
List元素包含一个或多个值.ref指向配置文件中的其它bean.当然,这里也可以直接用内部bean赋值,对于原始属性,可以直接用value,还可以用空值:<null />,而且一个list还可以包含另外的list,形成多维的列表.
在JAVA类的接收端,可以是数组,也可以是任意的Collection 的实现,如:
MyType[] valList;
List<MyType> valList;
Set
Set 和 list用法完全一模一样.在所有使用list的地方都可以用set代替.但set比list多一个功能:它限制里面的值只有一个,即,如果有重复的值,它会忽略:
<property name=”valList”>
<property>
上面的注入实际上只注入了两个值到列表里,因为a是重复的.
Map
需要 键—值 对的集合时用这个.用法:
JAVA类中:
Map<String,MyType> valMap
<property name=”valMap”>
</property>
要注意的是:
Map标签对键和值都没做类型的限定,也就是说,键和值都可以使用原始类型和扩展类型.
用原始类型时,键和值的表示分别是:
key
扩展类型时:
key-ref
Props
它和map的用法一样.但不同的是它的键和值都被强制要求为String.如:
Java端:
Properties valProp
<property name=”valMap”>
</property>
自动装配
前面已经知道了如何进行构造函数注入和属性注入,但这些都在在配置文件中显式的写出来的,这样会写大量的XML.Spring提供自动装配机制. 有四种实现方式:
1.
在容器中寻找和需要自动装配的属性名相同的Bean,如果没有找到就无法装配
2.
在容器中寻找和需要自动装配的属性类型相同的Bean,就是和JAVA代码中接收参数类型相同的Bean.如果找不到就无法装配,如果找到多个,就会抛出异常.
3.
寻找和自动装配的bean构造函数参数一臻的一个或多个bean.
4.
先尝试用constructor,然后用byType
用法:
<bean id=”toLoad” class=”…..” autowire=”byName”></bean>
上面配置可以看出,我们没有象以前一样,在bean里面加入property属性,然后用ref或value注入值.那是因为我们设置了autowire,容器会自动装配它,如果JAVA代码中该类是这样的:
setAProp(MyBeanA mybeana){}
setBProp(MyBeanB mybeanb){}
在类中有两个待注入的属性,但我们在配置文件中设置了按名称自动装配,则spring会在容器中自动找ID为:mybeana和mybeanb的bean.
如果自动装配设置为按类型:autowire=”byType”.则会在容器中找class等于MyBeanA和MyBeanB的bean.
Constructor一般用在我们用构造函数注入的时候和自动装配.