几种注入方式:
1、属性注入(使用属性的setter方法注入)
2、构造方法注入
3、工厂方法注入(静态工厂、实例工厂(非静态工厂))
4、注解注入
1.Set注入
这是最简单的注入方式,假设有一个SpringAction,类中需要实例化一个SpringDao对象,那么就可以定义一个private的SpringDao成员变量,然后创建SpringDao的set方法(这是ioc的注入入口):
package com.bless.springdemo.action;
public class SpringAction {
//注入对象springDao
private SpringDao springDao;
//一定要写被注入对象的set方法
public void setSpringDao(SpringDaospringDao) {
this.springDao = springDao;
}
public void ok(){
springDao.ok();
}
}
XML配置:
<!--配置bean,配置后该类由spring管理-->
<bean name="springAction" class="com.bless.springdemo.action.SpringAction">
<!--(1)依赖注入,配置当前类中相应的属性-->
<propertyname="springDao" ref="springDao"></property>
</bean>
<beanname="springDao"class="com.bless.springdemo.dao.impl.SpringDaoImpl"></bean>
2.构造器注入
这种方式的注入是指带有参数的构造函数注入,看下面的例子,我创建了两个成员变量SpringDao和User,但是并未设置对象的set方法,所以就不能支持第一种注入方式,这里的注入方式是在SpringAction的构造函数中注入,也就是说在创建SpringAction对象时要将SpringDao和User两个参数值传进来:
1. publicclass SpringAction {
2. //注入对象springDao
3. private SpringDao springDao;
4. private User user;
5.
6. publicSpringAction(SpringDao springDao,Useruser){
7. this.springDao = springDao;
8. this.user = user;
9. System.out.println("构造方法调用springDao和user");
10.}
11.
12.publicvoidsave(){
13. user.setName("卡卡");
14. springDao.save(user);
15.}
16.}
在XML文件中同样不用的形式,而是使用标签,ref属性同样指向其它标签的name属性:
<!--配置bean,配置后该类由spring管理-->
<beanname="springAction"class="com.bless.springdemo.action.SpringAction">
<!--(2)创建构造器注入,如果主类有带参的构造方法则需添加此配置-->
<constructor-argref="springDao"></constructor-arg>
<constructor-argref="user"></constructor-arg>
</bean>
<beanname="springDao"class="com.bless.springdemo.dao.impl.SpringDaoImpl"></bean>
<beanname="user"class="com.bless.springdemo.vo.User"></bean>
·
解决构造方法参数的不确定性,你可能会遇到构造方法传入的两参数都是同类型的,为了分清哪个该赋对应值,则需要进行一些小处理:
下面是设置index,就是参数位置:
<beanname="springAction"class="com.bless.springdemo.action.SpringAction">
<constructor-argindex="0"ref="springDao"></constructor-arg>
<constructor-argindex="1"ref="user"></constructor-arg>
</bean>
另一种是设置参数类型:
<constructor-argtype="java.lang.String" ref=""/>
3工厂方法
3.1静态工厂的方法注入
静态工厂顾名思义,就是通过调用静态工厂的方法来获取自己需要的对象,为了让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 newStaticFacotryDaoImpl();
}
}
同样看关键类,这里我需要注入一个FactoryDao对象,这里看起来跟第一种注入一模一样,但是看随后的xml会发现有很大差别:
publicclass SpringAction {
//注入对象
private FactoryDaostaticFactoryDao;
publicvoidstaticFactoryOk(){
staticFactoryDao.saveFactory();
}
//注入对象的set方法
publicvoidsetStaticFactoryDao(FactoryDao staticFactoryDao) {
this.staticFactoryDao =staticFactoryDao;
}
}
Spring的IOC配置文件,注意看指向的class并不是FactoryDao的实现类,而是指向静态工厂DaoFactory,并且配置factory-method=”getStaticFactoryDaoImpl”指定调用哪个工厂方法:
<!--配置bean,配置后该类由spring管理-->
<beanname="springAction"class="com.bless.springdemo.action.SpringAction" >
<!--(3)使用静态工厂的方法注入对象,对应下面的配置文件(3)-->
<propertyname="staticFactoryDao"ref="staticFactoryDao"></property>
</property>
</bean>
<!--(3)此处获取对象的方式是从工厂类中获取静态方法-->
<beanname="staticFactoryDao"class="com.bless.springdemo.factory.DaoFactory"factory-method="getStaticFactoryDaoImpl"></bean>
3.2实例工厂的方法注入
实例工厂的意思是获取对象实例的方法不是静态的,所以你需要首先new工厂类,再调用普通的实例方法:
publicclass
DaoFactory {
//实例工厂
publicFactoryDao
getFactoryDaoImpl(){
return
new
FactoryDaoImpl();
}
}
那么下面这个类没什么说的,跟前面也很相似,但是我们需要通过实例工厂类创建FactoryDao对象:
publicclass
SpringAction {
//注入对象
private FactoryDao factoryDao;
publicvoid
factoryOk
(){
factoryDao.saveFactory();
}
publicvoid
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依赖注入:注解注入总结
注解注入顾名思义就是通过注解来实现注入,Spring和注入相关的常见注解有Autowired、Resource、Qualifier、Service、Controller、Repository、Component。
基本上项目都有用过了,接下来将一个一个详细来学习一下吧。
· Autowired是自动注入,自动从spring的上下文找到合适的bean来注入
· Resource用来指定名称注入
· Qualifier和Autowired配合使用,指定bean的名称
· Service,Controller,Repository分别标记类是Service层类,Controller层类,数据存储层的类,spring扫描注解配置时,会标记这些类要生成bean(生成bean,然后需要的时候就从容器中拿出bean注入到所需要的地方)。
· Component是一种泛指,标记类是组件,spring扫描注解配置时,会标记这些类要生成bean。
上面的Autowired和Resource是用来修饰字段,构造函数,或者设置方法,并做注入的。而Service,Controller,Repository,Component则是用来修饰类,标记这些类要生成bean。
下面我们通过实例项目来看下spring注解注入的使用。
首先新建一个maven项目,并在pom中添加spring相关的依赖,如果不知道添加那些依赖,请参照上一篇文章。
然后新建CarDao类,给它添加@Repository注解,如下代码:
package cn.outofmemory.helloannotation;
import org.springframework.stereotype.Repository;
@Repository
publicclassCarDao {
publicvoid insertCar(String car) {
String insertMsg = String.format("insertingcar %s", car);
System.out.println(insertMsg);
}
}
新建CarService类,并给该类标注@Service注解,在这个类中定义CarDao的字段,并通过Autowired来修饰此字段,这样上面定义的CarDao类的实例就会自动注入到CarService的实例中了。
package cn.outofmemory.helloannotation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
publicclassCarService {
@Autowired
privateCarDao carDao;
publicvoid addCar(String car) {
this.carDao.insertCar(car);
}
}
注意:Autowired注解有一个可以为空的属性required,可以用来指定字段是否是必须的,如果是必需的,则在找不到合适的实例注入时会抛出异常。
下面我们在App.java中使用上面测试下注解注入:
package cn.outofmemory.helloannotation;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
* Hello world!
*
*/
publicclassApp
{
publicstaticvoid main( String[] args )
{
ApplicationContext appContext = newAnnotationConfigApplicationContext("cn.outofmemory.helloannotation");
CarService service =appContext.getBean(CarService.class);
service.addCar("宝马");
}
}
在上面的main方法中首先我们初始化了appContext,他是AnnotationConfigApplicationContext,它的构造函数接受一个package的名称,来限定要扫描的package。然后就可以通过appContext的getBean方法获得CarService的实例了。
上面的例子非常简单,单纯的使用AnnotationConfigApplicationContext就可以了,但是在实际项目中情况往往没有这么简单,还是需要spring配置文件的。在spring配置文件中也可以通过下面的配置让spring自动扫描注解配置。
<!-- beanannotation driven -->
<context:annotation-config/>
<context:component-scanbase-package="cn.outofmemory.helloannotation">
</context:component-scan>
下面我们看下混合使用spring配置和注解的例子,首先在项目中添加source folder,src/main/resources,并添加spring.xml, 其内容如下:
<?xml version="1.0" encoding="utf-8"?>
<beansxmlns="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">
<!-- beanannotation driven -->
<context:annotation-config/>
<context:component-scanbase-package="cn.outofmemory.helloannotation">
</context:component-scan>
<beanid="sqliteCarDao"class="cn.outofmemory.helloannotation.CarDao">
<constructor-argname="driver"value="sqlite"/>
</bean>
</beans>
在上面的配置文件中,我们通过context:annotation-config和context:component-sacn节点来指定要扫描注解注入,然后又定义了一个id为sqliteCarDao的bean,它的构造函数的driver值为sqlite。
我们修改下App.java使用xml配置文件,再运行下App看下会怎样。
package cn.outofmemory.helloannotation;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* Hello world!
*
*/
publicclassApp
{
publicstaticvoid main( String[] args )
{
//ApplicationContextappContext = newAnnotationConfigApplicationContext("cn.outofmemory.helloannotation");
ApplicationContext appContext = newClassPathXmlApplicationContext("/spring.xml");
CarService service =appContext.getBean(CarService.class);
service.addCar("宝马");
}
}
运行程序发现输出为:inserting car 宝马 into mysql,显然CarService自动注入的CarDao使用了默认构造函数构造的实例。是否可以通过注解指定使用spring.xml中配置的sqliteCarDao呢?
我们可以修改下CarService类,通过Qualifier注解来指定要使用的bean的名字。
如下,在指定Autowired注解时,同时指定Qualifier注解指定bean的名字
@Autowired
@Qualifier("sqliteCarDao")
privateCarDao carDao;
重新运行下App.java 这次输出的是inserting car 宝马 into sqlite,这次使用了spring.xml中配置的bean了。
在文中开头我们还提到了Resouce注解,这个注解可以指定名字注入,我们再次修改下CarService类:
@Resource(name="sqliteCarDao")
privateCarDao carDao;
javax.annotation.Resource注解实现的效果和@Autowired+@Qualifier的效果是一样的。