原始方式:spring四种依赖注入方式 java
spring有多种依赖注入的形式,下面仅介绍spring经过xml进行IOC配置的方式:spring
Set注入less
这是最简单的注入方式,假设有一个SpringAction,类中须要实例化一个SpringDao对象,那么就能够定义一个private的SpringDao成员变量,而后建立SpringDao的set方法(这是ioc的注入入口):ssh
package com.bless.springdemo.action; public class SpringAction { //注入对象springDao private SpringDao springDao; //必定要写被注入对象的set方法 public void setSpringDao(SpringDao springDao) { this.springDao = springDao; } public void ok(){ springDao.ok(); } }
随后编写spring的xml文件,<bean>中的name属性是class属性的一个别名,class属性指类的全名,由于在SpringAction中有一个公共属性Springdao,因此要在<bean>标签中建立一个<property>标签指定SpringDao。<property>标签中的name就是SpringAction类中的SpringDao属性名,ref指下面<bean name="springDao"...>,这样实际上是spring将SpringDaoImpl对象实例化而且调用SpringAction的setSpringDao方法将SpringDao注入:函数
<!--配置bean,配置后该类由spring管理--> <bean name="springAction" class="com.bless.springdemo.action.SpringAction"> <!--(1)依赖注入,配置当前类中相应的属性--> <property name="springDao" ref="springDao"></property> </bean> <bean name="springDao" class="com.bless.springdemo.dao.impl.SpringDaoImpl"></bean>
构造器注入测试
这种方式的注入是指带有参数的构造函数注入,看下面的例子,我建立了两个成员变量SpringDao和User,可是并未设置对象的set方法,因此就不能支持第一种注入方式,这里的注入方式是在SpringAction的构造函数中注入,也就是说在建立SpringAction对象时要将SpringDao和User两个参数值传进来:ui
public class SpringAction { //注入对象springDao private SpringDao springDao; private User user; public SpringAction(SpringDao springDao,User user){ this.springDao = springDao; this.user = user; System.out.println("构造方法调用springDao和user"); } public void save(){ user.setName("卡卡"); springDao.save(user); } }
在XML文件中一样不用<property>的形式,而是使用<constructor-arg>标签,ref属性一样指向其它<bean>标签的name属性:this
<!--配置bean,配置后该类由spring管理--> <bean name="springAction" class="com.bless.springdemo.action.SpringAction"> <!--(2)建立构造器注入,若是主类有带参的构造方法则需添加此配置--> <constructor-arg ref="springDao"></constructor-arg> <constructor-arg ref="user"></constructor-arg> </bean> <bean name="springDao" class="com.bless.springdemo.dao.impl.SpringDaoImpl"></bean> <bean name="user" class="com.bless.springdemo.vo.User"></bean>
解决构造方法参数的不肯定性,你可能会遇到构造方法传入的两参数都是同类型的,为了分清哪一个该赋对应值,则须要进行一些小处理:spa
下面是设置index,就是参数位置:prototype
<bean name="springAction" class="com.bless.springdemo.action.SpringAction"> <constructor-arg index="0" ref="springDao"></constructor-arg> <constructor-arg index="1" ref="user"></constructor-arg> </bean>
另外一种是设置参数类型:
<constructor-arg type="java.lang.String" ref=""/>
静态工厂的方法注入
静态工厂顾名思义,就是经过调用静态工厂的方法来获取本身须要的对象,为了让spring管理全部对象,咱们不能直接经过"工程类.静态方法()"来获取对象,而是依然经过spring注入的形式获取:
package com.bless.springdemo.factory; import com.bless.springdemo.dao.FactoryDao; import com.bless.springdemo.dao.impl.FactoryDaoImpl; import com.bless.springdemo.dao.impl.StaticFacotryDaoImpl; public class DaoFactory { //静态工厂 public static final FactoryDao getStaticFactoryDaoImpl(){ return new StaticFacotryDaoImpl(); } }
一样看关键类,这里我须要注入一个FactoryDao对象,这里看起来跟第一种注入如出一辙,可是看随后的xml会发现有很大差异:
public class SpringAction { //注入对象 private FactoryDao staticFactoryDao; public void staticFactoryOk(){ staticFactoryDao.saveFactory(); } //注入对象的set方法 public void setStaticFactoryDao(FactoryDao staticFactoryDao) { this.staticFactoryDao = staticFactoryDao; } }
Spring的IOC配置文件,注意看<bean name="staticFactoryDao">指向的class并非FactoryDao的实现类,而是指向静态工厂DaoFactory,而且配置 factory-method="getStaticFactoryDaoImpl"指定调用哪一个工厂方法:
<!--配置bean,配置后该类由spring管理--> <bean name="springAction" class="com.bless.springdemo.action.SpringAction" > <!--(3)使用静态工厂的方法注入对象,对应下面的配置文件(3)--> <property name="staticFactoryDao" ref="staticFactoryDao"></property> </property> </bean> <!--(3)此处获取对象的方式是从工厂类中获取静态方法--> <bean name="staticFactoryDao" class="com.bless.springdemo.factory.DaoFactory" factory-method="getStaticFactoryDaoImpl"></bean>
实例工厂的方法注入
实例工厂的意思是获取对象实例的方法不是静态的,因此你须要首先new工厂类,再调用普通的实例方法:
public class DaoFactory { //实例工厂 public FactoryDao getFactoryDaoImpl(){ return new FactoryDaoImpl(); } }
那么下面这个类没什么说的,跟前面也很类似,可是咱们须要经过实例工厂类建立FactoryDao对象:
public class SpringAction { //注入对象 private FactoryDao factoryDao; public void factoryOk(){ factoryDao.saveFactory(); } public void setFactoryDao(FactoryDao factoryDao) { this.factoryDao = factoryDao; } }
最后看spring配置文件:
<!--配置bean,配置后该类由spring管理--> <bean name="springAction" class="com.bless.springdemo.action.SpringAction"> <!--(4)使用实例工厂的方法注入对象,对应下面的配置文件(4)--> <property name="factoryDao" ref="factoryDao"></property> </bean> <!--(4)此处获取对象的方式是从工厂类中获取实例方法--> <bean name="daoFactory" class="com.bless.springdemo.factory.DaoFactory"></bean> <bean name="factoryDao" factory-bean="daoFactory" factory-method="getFactoryDaoImpl"></bean>
总结
Spring IOC注入方式用得最多的是(1)(2)种,多谢多练就会很是熟练。
另外注意:经过Spring建立的对象默认是单例的,若是须要建立多实例对象能够在<bean>标签后面添加一个属性:
<bean name="..." class="..." scope="prototype">
注解方式:Spring零配置经过注解实现Bean依赖注入
Spring3的基于注解实现Bean依赖注入支持以下三种注解:
Spring自带依赖注入注解: Spring自带的一套依赖注入注解;
JSR-250注解:Java平台的公共注解,是Java EE 5规范之一,在JDK6中默认包含这些注解,从Spring2.5开始支持。
JSR-330注解:Java 依赖注入标准,Java EE 6规范之一,可能在加入到将来JDK版本,从Spring3开始支持;
JPA注解:用于注入持久化上下文和尸体管理器。
这三种类型的注解在Spring3中都支持,相似于注解事务支持,想要使用这些注解须要在Spring容器中开启注解驱动支持,即便用以下配置方式开启:
<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" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <context:annotation-config/> </beans>
1、@Required:依赖检查;
对应于基于XML配置中的依赖检查,但XML配置的依赖检查将检查全部setter方法,详见【3.3.4 依赖检查】;
基于@Required的依赖检查表示注解的setter方法必须,即必须经过在XML配置中配置setter注入,若是没有配置在容器启动时会抛出异常从而保证在运行时不会遇到空指针异常,@Required只能放置在setter方法上,且经过XML配置的setter注入,可使用以下方式来指定:
Java代码
@Requried setter方法
一、准备测试Bean
package cn.javass.spring.chapter12; public class TestBean { private String message; @Required public void setMessage(String message) { this.message = message; } public String getMessage() { return message; } }
二、在Spring配置文件(chapter12/dependecyInjectWithAnnotation.xml)添加以下Bean配置:
<bean id="testBean" class="cn.javass.spring.chapter12.TestBean"> <property name="message" ref="message"/> </bean> <bean id="message" class="java.lang.String"> <constructor-arg index="0" value="hello"/> </bean>
三、测试类和测试方法以下:
package cn.javass.spring.chapter12; //省略import public class DependencyInjectWithAnnotationTest { private static String configLocation = "classpath:chapter12/dependecyInjectWithAnnotation.xml"; private static ApplicationContext ctx = new ClassPathXmlApplicationContext("configLocation"); //一、Spring自带依赖注入注解 @Test public void testRequiredForXmlSetterInject() { TestBean testBean = ctx.getBean("testBean", TestBean.class); Assert.assertEquals("hello", testBean.getMessage()); } }
在XML配置文件中必须指定setter注入,不然在Spring容器启动时将抛出以下异常:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'testBean' defined in class path resource [chapter12/dependecyInjectWithAnnotation.xml]: Initialization of bean failed; nested exception is org.springframework.beans.factory.BeanInitializationException: Property 'message' is required for bean 'testBean'
2、@Autowired:自动装配
自动装配,用于替代基于XML配置的自动装配,详见【3.3.3 自动装配】。
基于@Autowired的自动装配,默认是根据类型注入,能够用于构造器、字段、方法注入,使用方式以下:
@Autowired(required=true) 构造器、字段、方法
@Autowired默认是根据参数类型进行自动装配,且必须有一个Bean候选者注入,若是容许出现0个Bean候选者须要设置属性“required=false”,“required”属性含义和@Required同样,只是@Required只适用于基于XML配置的setter注入方式。
(1)、构造器注入:经过将@Autowired注解放在构造器上来完成构造器注入,默认构造器参数经过类型自动装配,以下所示:
一、准备测试Bean,在构造器上添加@AutoWired注解:
package cn.javass.spring.chapter12; import org.springframework.beans.factory.annotation.Autowired; public class TestBean11 { private String message; @Autowired //构造器注入 private TestBean11(String message) { this.message = message; } //省略message的getter和setter }
二、在Spring配置文件(chapter12/dependecyInjectWithAnnotation.xml)添加以下Bean配置:
<bean id="testBean11"class="cn.javass.spring.chapter12.TestBean11"/>
三、测试类以下:
@Test public void testAutowiredForConstructor() { TestBean11 testBean11 = ctx.getBean("testBean11", TestBean11.class); Assert.assertEquals("hello", testBean11.getMessage()); }
在Spring配置文件中没有对“testBean11”进行构造器注入和setter注入配置,而是经过在构造器上添加@ Autowired来完成根据参数类型完成构造器注入。
(2)、字段注入:经过将@Autowired注解放在构造器上来完成字段注入。
一、准备测试Bean,在字段上添加@AutoWired注解:
package cn.javass.spring.chapter12; import org.springframework.beans.factory.annotation.Autowired; public class TestBean12 { @Autowired //字段注入 private String message; //省略getter和setter }
二、在Spring配置文件(chapter12/dependecyInjectWithAnnotation.xml)添加以下Bean配置:
<bean id="testBean12" class="cn.javass.spring.chapter12.TestBean12"/>
三、测试方法以下:
@Test public void testAutowiredForField() { TestBean12 testBean12 = ctx.getBean("testBean12", TestBean12.class); Assert.assertEquals("hello", testBean12.getMessage()); }
字段注入在基于XML配置中无相应概念,字段注入不支持静态类型字段的注入。
(3)、方法参数注入:经过将@Autowired注解放在方法上来完成方法参数注入。
一、准备测试Bean,在方法上添加@AutoWired注解:
package cn.javass.spring.chapter12; import org.springframework.beans.factory.annotation.Autowired; public class TestBean13 { private String message; @Autowired //setter方法注入 public void setMessage(String message) { this.message = message; } public String getMessage() { return message; } }
package cn.javass.spring.chapter12; //省略import public class TestBean14 { private String message; private List<String> list; @Autowired(required = true) //任意一个或多个参数方法注入 private void initMessage(String message, ArrayList<String> list) { this.message = message; this.list = list; } //省略getter和setter }
二、在Spring配置文件(chapter12/dependecyInjectWithAnnotation.xml)添加以下Bean配置:
<bean id="testBean13" class="cn.javass.spring.chapter12.TestBean13"/> <bean id="testBean14" class="cn.javass.spring.chapter12.TestBean14"/> <bean id="list" class="java.util.ArrayList"> <constructor-arg index="0"> <list> <ref bean="message"/> <ref bean="message"/> </list> </constructor-arg> </bean>
三、测试方法以下:
@Test public void testAutowiredForMethod() { TestBean13 testBean13 = ctx.getBean("testBean13", TestBean13.class); Assert.assertEquals("hello", testBean13.getMessage()); TestBean14 testBean14 = ctx.getBean("testBean14", TestBean14.class); Assert.assertEquals("hello", testBean14.getMessage()); Assert.assertEquals(ctx.getBean("list", List.class), testBean14.getList()); }
方法参数注入除了支持setter方法注入,还支持1个或多个参数的普通方法注入,在基于XML配置中不支持1个或多个参数的普通方法注入,方法注入不支持静态类型方法的注入。
注意“initMessage(String message, ArrayList<String> list)”方法签名中为何使用ArrayList而不是List呢?具体参考【3.3.3 自动装配】一节中的集合类型注入区别。
产考文档:http://blessht.iteye.com/blog/1162131
http://www.iteye.com/topic/1121784