Spring笔记(二):Ioc 之注入与装配

一、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();

	}


郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。