一、Spring依赖注入的原理
二、依赖注入的实现
(一)对象的注入
1、简单属性注入
1)源代码
package main.java.com.spring.ioc.base.dao.impl;
import main.java.com.spring.ioc.base.dao.PersonDao;
/**
*
* PersonDiDaoImpl
* @title
* @desc
* @author SAM-SHO
* @Dec 28, 2014
*/
public class PersonDiDaoImpl implements PersonDao {
@Override
public void save() {
System.out.println("PersonDiDaoImpl 的save()方法被调用了");
}
}
package main.java.com.spring.ioc.base.service.impl;
import main.java.com.spring.ioc.base.dao.PersonDao;
import main.java.com.spring.ioc.base.service.PersonService;
/**
* PersonDiServiceImpl
* @desc
* @author SAM-SHO
* @Dec 25, 2014
*/
public class PersonDiServiceImpl implements PersonService {
private PersonDao personDao;
@Override
public void save() {
personDao.save();
}
public PersonDao getPersonDao() {
return personDao;
}
public void setPersonDao(PersonDao personDao) {
this.personDao = personDao;
}
}
2)配置文件
<!-- 1-依赖注入的实现 -->
<!-- 1-1 对象的注入 -->
<!-- 1-1-1 简单属性注入 -->
<bean id="PersonDiDaoImpl" class="main.java.com.spring.ioc.base.dao.impl.PersonDiDaoImpl"></bean>
<bean id="PersonDiService" class="main.java.com.spring.ioc.base.service.impl.PersonDiServiceImpl">
<property name="personDao" ref="PersonDiDaoImpl"></property><!-- 这边的name必须与类中setXXX()方法的XXX名字一致 -->
</bean>
3)测试
@Test
public void BeanDISucess() {
// 1- 对象的注入
// 1-1 简单属性注入 ref属性(推荐)
ApplicationContext cxt = new ClassPathXmlApplicationContext("application-di-Context.xml");
PersonService tPersonService = cxt.getBean("PersonDiService", PersonDiServiceImpl.class);//利用接口接收
tPersonService.save();//【输出】:PersonDiDaoImpl 的save()方法被调用了
}
4)分析:
①、使用关键元素 <property name="" ref="">
②、name:必须与类中setXXX()方法的XXX名字一致。即setPersonDao 与 与name="personDao"保持一致。
③、ref:指向定义好,需要注入的Bean 。
2、内部Bean注入
1)源代码
2)配置文件
<!-- 1-1-2 内部Bean属性注入 -->
<bean id="PersonDiService2" class="main.java.com.spring.ioc.base.service.impl.PersonDiServiceImpl">
<property name="personDao" >
<bean class="main.java.com.spring.ioc.base.dao.impl.PersonDiDaoImpl" />
</property>
</bean>
3)测试
// 1-2 使用内部Bean 的属性注入(注入的Bean 不能复用)
PersonService tPersonService2 = cxt.getBean("PersonDiService2", PersonDiServiceImpl.class);//利用接口接收
tPersonService2.save();//【输出】:PersonDiDaoImpl 的save()方法被调用了
4)分析:内部Bean注入,其实就是把需要注入的bean定义在 被注入的Bean 内部。其实这样反而达不到重复使用的效果。
(二)基本类型注入
1、String 的注入
1)源代码:在PersonDiServiceImpl 中增加属性 name 。修改save()方法
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public void save() {
System.out.println("被注入的简单属性的值为:" + name);
personDao.save();
}
2)配置文件
<!-- 1-2 基本类型注入 -->
<bean id="personDiService3" class="main.java.com.spring.ioc.base.service.impl.PersonDiServiceImpl">
<property name="personDao" ref="PersonDiDaoImpl"></property>
<property name="name" value="SAM-SHO"></property>
</bean>
3)测试
// 2- 基本类型的注入
PersonService tPersonService3 = cxt.getBean("personDiService3", PersonDiServiceImpl.class);//利用接口接收
tPersonService3.save();//【输出】:被注入的简单属性的值为:SAM-SHO
2、Date 的注入
1)源代码:增加Date类型的属性并修改save()方法。
private Date date;
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
@Override
public void save() {
System.out.println("被注入的Date属性的值为:" + date);
System.out.println("被注入的简单属性的值为:" + name);
personDao.save();
}
2)配置文件:利用 SimpleDateFormat 的注入
<bean id="dateFormat" class="java.text.SimpleDateFormat">
<constructor-arg value="yyyy-MM-dd" />
</bean>
<bean id="personDiService4" class="main.java.com.spring.ioc.base.service.impl.PersonDiServiceImpl">
<property name="personDao" ref="PersonDiDaoImpl"></property>
<property name="date" >
<bean factory-bean="dateFormat" factory-method="parse">
<constructor-arg value="2015-01-01" />
</bean>
</property>
</bean>
3)测试
// 2-2 Date类型的注入
PersonService tPersonService4 = cxt.getBean("personDiService4", PersonDiServiceImpl.class);//利用接口接收
tPersonService4.save();//【输出】:被注入的Date属性的值为:Thu Jan 01 00:00:00 CST 2015
4)分析:利用SimpleDateFormat 的parse()的实例工厂方法初始化其Bean,然后注入
(三)各种集合类型的注入
1、List集合类型
1)源代码:增加list属性
// List集合类型
private List<String> lists = new ArrayList<String>();
public List<String> getLists() {
return lists;
}
public void setLists(List<String> lists) {
this.lists = lists;
}
2)配置文件
<!-- 1-3 集合类型注入 -->
<bean id="personDiService5" class="main.java.com.spring.ioc.base.service.impl.PersonDiServiceImpl">
<property name="personDao" ref="PersonDiDaoImpl"></property>
<!--1-3-1 List集合的注入-->
<property name="lists">
<list>
<value>第1个List值</value>
<value>第2个List值</value>
<value>第3个List值</value>
</list>
</property>
</bean>
3)测试
// 3-集合类型的注入
PersonDiServiceImpl tPersonDiService5 = cxt.getBean("personDiService5", PersonDiServiceImpl.class);
// 3-1 List 集合的注入
for (String strValue : tPersonDiService5.getLists()) {
System.out.println("List 集合注入的值: " + strValue);
}
System.out.println("--------------------------");
4)分析:使用<list> 标签
2、Set集合类型
1)源代码
// Set集合类型
private Set<String> sets = new HashSet<String>();
public Set<String> getSets() {
return sets;
}
public void setSets(Set<String> sets) {
this.sets = sets;
}
2)配置文件
<!--1-3-2 Set 集合的注入-->
<property name="sets">
<set>
<value>第yi个set值</value>
<value>第er个set值</value>
<value>第san个set值</value>
</set>
</property>
3)测试
PersonDiServiceImpl tPersonDiService5 = cxt.getBean("personDiService5", PersonDiServiceImpl.class);
//3-2 set集合的注入
for (String strValue : tPersonDiService5.getSets()) {
System.out.println("Set集合注入的值: " + strValue);
}
4)分析:<set> 标签
3、Properties 集合类型
1)源代码
// Properties 集合类型
private Properties properties = new Properties();
public Properties getProperties() {
return properties;
}
public void setProperties(Properties properties) {
this.properties = properties;
}
2)配置文件
<!--1-3-3 Properties 集合的注入-->
<property name="properties">
<props>
<prop key="key1">1-properties-Value</prop>
<prop key="key2">2-properties-Value</prop>
<prop key="key3">3-properties-Value</prop>
</props>
</property>
3)测试
ApplicationContext cxt = new ClassPathXmlApplicationContext("application-di-Context.xml");
PersonDiServiceImpl tPersonDiService5 = cxt.getBean("personDiService5", PersonDiServiceImpl.class);
// 3-3 Properties 集合的注入
for (Object key : tPersonDiService5.getProperties().keySet()) {
System.out.println("Properties 集合注入的值: " + tPersonDiService5.getProperties().get(key));
}
4)分析:<props><prop key="key1">1-properties-Value</prop></props>
4、Map 集合类型
1)源代码
// Map 集合类型
private Map<String,String> maps = new HashMap<String,String>();
public Map<String, String> getMaps() {
return maps;
}
public void setMaps(Map<String, String> maps) {
this.maps = maps;
}
2)配置文件
<!--1-3-4 Map集合的注入 -->
<property name="maps">
<map>
<entry key="key1" value="mapValue1"></entry>
<entry key="key2" value="mapValue2"></entry>
<entry key="key3" value="mapValue3"></entry>
</map>
</property>
3)测试
// 3-4 Map 集合的注入(其实Map 也可以利用 Properties 的配置实现)
for (String key : tPersonDiService5.getMaps().keySet()) {
System.out.println("Map 集合注入的值: " + tPersonDiService5.getMaps().get(key));
}
4)分析:<map><entry key="key1" value="mapValue1"></entry></map>
三、依赖注入的方式
1、属性注入:即一个对象作为属性存在于另一个对象中,有 setter 和 getter 方法。
1)源代码
private PersonDao personDao;
public PersonDao getPersonDao() {
return personDao;
}
public void setPersonDao(PersonDao personDao) {
this.personDao = personDao;
}
2)配置文件
<bean id="PersonDiDaoImpl" class="main.java.com.spring.ioc.base.dao.impl.PersonDiDaoImpl"></bean>
<bean id="PersonDiService" class="main.java.com.spring.ioc.base.service.impl.PersonDiServiceImpl">
<property name="personDao" ref="PersonDiDaoImpl"></property><!-- 这边的name必须与类中setXXX()方法的XXX名字一致 -->
</bean>
2、构造器注入
1)源代码
// 一定要有无参的构造方法
public PersonDiServiceImpl() {
}
// 构造器注入
public PersonDiServiceImpl(PersonDao personDao, String name) {
this.personDao = personDao;
this.name = name;
}
2)配置文件
<bean id="personDao" class="main.java.com.spring.ioc.base.dao.impl.PersonDiDaoImpl"></bean>
<!-- 2-2 构造器注入 -->
<bean id="personDiService7" class="main.java.com.spring.ioc.base.service.impl.PersonDiServiceImpl">
<constructor-arg index="0" ref="personDao" ></constructor-arg>
<constructor-arg index="1" type="String" value="构造器注入" ></constructor-arg>
</bean>
3)测试
// 2-构造器注入 constructor-arg
// 一定要有无参的构造方法
ApplicationContext cxt = new ClassPathXmlApplicationContext("application-di-Context.xml");
PersonService tPersonService = cxt.getBean("personDiService7", PersonDiServiceImpl.class);//利用接口接收
tPersonService.save();
【输出】
// 被注入的简单属性的值为:构造器注入
// PersonDiDaoImpl 的save()方法被调用了
4)分析
①、<constructor-arg>标签。
②、一定要有无参的构造方法
3、使用Field注入(用于注解方式)
1)java 的@Resource(推荐)
2)spring 的@Autowire
四、注解完成Bean的注入
(一)Resource注解
1、剖析@Resource注解的实现原理
2、实现
1)源代码
@Resource
private PersonDao personDao;
public PersonDao getPersonDao() {
return personDao;
}
public void setPersonDao(PersonDao personDao) {
this.personDao = personDao;
}
2)配置文件
<!-- 1-注解方式注入 -->
<!-- 1-支持注解 -->
<context:annotation-config/>
<!-- 2-定义两个Bean -->
<bean id="personDao" class="main.java.com.spring.ioc.base.dao.impl.PersonDiDaoImplAnnocation"></bean>
<bean id="personServiceImplAnnotation" class="main.java.com.spring.ioc.base.service.impl.PersonDIServiceImplAnnotation"></bean>
3)测试
ApplicationContext cxt = new ClassPathXmlApplicationContext("application-di-annotation-Context.xml");
PersonService tPersonService = cxt.getBean("personServiceImplAnnotation", PersonDIServiceImplAnnotation.class);//利用接口接收
tPersonService.save();//【输出】PersonDiDaoImplAnnocation 的save()方法被调用了
3、分析
1)需要增加context的xml_Schema 和 <context:annotation-config/>。这个配置这个配置隐式注册了多个对注解进行解析处理的处理器 AutowiredAnnotationBeanPostProcessor、CommonAnnotationBeanPostProcessor、PersistenceAnnotationBeanPostProcessor、RequiredAnnotationBeanPostProcessor。
2)@Resource 注解需要导入common-annotations.jar。默认按名称装配,如果没有指定了name属性,则找不到就会按类型。
3)两个注解可以放在属性或者setXXX方法上。
(二)@Autowire 注解
1、实现
1)源码
//默认情况下要求依赖对象必须存在,如果允许为null,可以设置它required=false
// @Autowired(required=true)
// @Autowired@Qualifier("personDao")
@Autowired
private PersonDao personDao;
2、分析
1)@Autowired 默认按类型装配。想使用名称装配可以结合 @Qualifier("personDao") 使用。
3、默认情况下要求依赖对象必须存在,如果允许为null,可以设置它required=false 。
五、自动装配(不推荐)
(一)自动装配
1、xml配置:Autowired
1)byType: 按属性类型装配,多个匹配的Bean类型,抛异常
2)byName:按属性名称装配
3)constructor:构造器参数类型
4)autodetect:通过自省机制,自动决定。有默认构造器,则按byType 。
(二)实例
1、配置
<!-- 2-自动装配 -->
<bean id="personDao1" class="main.java.com.spring.ioc.base.dao.impl.PersonDiDaoImplAnnocation"></bean>
<bean id="personServiceImplAnnotation1" autowire="byName" class="main.java.com.spring.ioc.base.service.impl.PersonDIServiceImplAnnotation"></bean>
2、测试
/*
* 自动装配
* xml配置:Autowired :
* 1、byType: 按属性类型装配,多个匹配的Bean类型,抛异常
* 2、byName:按属性名称装配
* 3、constructor:构造器参数类型
* 4、autodetect:通过自省机制,自动决定。有默认构造器,则按byType 。
*/
PersonService tPersonService = cxt.getBean("personServiceImplAnnotation1", PersonDIServiceImplAnnotation.class);//利用接口接收
tPersonService.save();//【输出】PersonDiDaoImplAnnocation 的save()方法被调用了
六、Spring自动扫描和管理Bean
(一)自动扫描:用注解管理Bean
1、四个注解:
1)@Controller:最常见用于action,配以@Scope("prototype")。
2)@Service:用于service层。
3)@Repository:用于Dao层。
4)@Component:用于不同于上者三个注解。
2、配置需要扫描的包
<!-- 3-自动扫描 -->
<context:component-scan base-package="main.java.com.spring.*"></context:component-scan>
3、@PostConstruct:对应init-method 方法,在构造方法之后。
4、@PreDestroy:destroy-method 方法,容器关闭之前。
(二)自动扫描与注解结合
1、源码:
@Service
public class PersonDIServiceImplAnnotation implements PersonService {
@Resource
private PersonDao personDao;
}
@Repository
public class PersonDiDaoImplAnnocation implements PersonDao {
@Override
public void save() {
System.out.println("PersonDiDaoImplAnnocation 的save()方法被调用了");
}
}
2、配置:
<context:annotation-config/>
<context:component-scan base-package="main.java.com.spring.*"></context:component-scan>
1)不需要使用任何Bean的配置。
2)甚者,在使用自动扫描的配置下,可以省略解析注解的配置。因为配置注解只是隐式注册了多个对注解进行解析处理的处理器 ,而自动扫描可以起到一样的效果。
<context:component-scan base-package="main.java.com.spring.*"></context:component-scan>
3、测试
//自动扫描
@Test
public void beanAutoScrean(){
AbstractApplicationContext cxt = new ClassPathXmlApplicationContext("application-di-annotation-Context.xml");
PersonService tPersonService = cxt.getBean("personDIServiceImplAnnotation", PersonDIServiceImplAnnotation.class);//利用接口接收
// tPersonService.save();
tPersonService.save();
cxt.close();
}