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