JavaWeb Spring依赖注入深入学习_java

一、依赖注入(DI)

依赖注入听起来很高深的样子,其实白话就是:给属性赋值。一共有两种方法,第一是以构造器参数的形式,另外一种就是以setting方法的形式。

1 构造器注入

1 使用构造器注入

使用xml的注入方式

A. 通过参数的顺序

<constructor-arg index="0"><value>张三</value></constructor-arg>
<constructor-arg index="1"><value>56</value></constructor-arg>

 B. 通过参数的类型

<constructor-arg type="java.lang.Integer"><value>56</value></constructor-arg>
<constructor-arg type="java.lang.String"><value>张三</value></constructor-arg>

具体实例

假如现在要对一个Person类注入参数,Student是一个另外一个类。

public class Person {
 private String pid;
 private String name;
 private Student student;

 public Person(String pid, Student student){
  this.pid= pid;
  this.student = student;
 }

 public Person(String pid, String name){
  this.pid = pid;
  this.name = name;
 }
}

配置applicationContext.xml,假如不进行参数配置,则报错,找不到相应的构造器。配置了相应的参数,则应在类中声明相应的构造函数。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.springframework.org/schema/beans
   http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
 <bean id="person" class="com.itheima10.spring.di.xml.constructor.Person">
  <!--
   不配参数,将会采取默认的构造器
   constructor-arg person类中某一个构造器的某一个参数
    index 为参数的角标
    type 参数的类型
    value 如果为基础属性,则用这个赋值
    ref 引用类型赋值
   -->
  <constructor-arg index="0" type="java.lang.String" value="aaa"></constructor-arg>
  <constructor-arg index="1" ref="student"></constructor-arg>
 </bean>
 <bean id="person1" class="com.itheima10.spring.di.xml.constructor.Person">
  <property name="pid" value="1"></property>
 </bean>
 <bean id="student" class="com.itheima10.spring.di.xml.constructor.Student"></bean>
</beans>

编写测试类DIXMLConstructorTest ,进行断点调试,将会发现根据配置的参数,进入的构造函数是Person(String pid, Student student)

public class DIXMLConstructorTest {

 @Test
 public void test1(){
  ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
  Person person = (Person) context.getBean("person");
 }
}

2 使用属性setter方法进行注入

使用xml的注入方式:

A. 简单Bean的注入
简单Bean包括两种类型:包装类型和String

<bean id="personService" class="com.itcast.bean.impl.PersonServiceImpl">
<!-- 基本类型,string类型 -->
<property name="age" value="20"></property>
<property name="name" value="张无忌"></property>
</bean>

B. 引用其他Bean

<bean id="person" class="com.itcast.bean.Person" />
 <bean id="personService" class="com.itcast.bean.impl.PersonServiceImpl">
 <property name="person" ref="person" />
</bean>

1.1 装配list集合

<property name="lists">
 <list>
  <value>list1</value>
  <value>list2</value>
  <ref bean="person" />
 </list>
</property>

1.2 装配set集合

<property name="sets">
 <set>
  <value>list1</value>
  <value>list2</value>
  <ref bean="person" />
 </set>
</property>

1.3 装配map

<property name="maps">
    <map>
     <entry key="01">
       <value>map01</value>
     </entry>
     <entry key="02">
       <value>map02</value>
     </entry>
    </map>
</property>

map中的<entry>的数值和<list>以及<set>的一样,可以使任何有效的属性元素,需要注意的是key值必须是String的。

1.4 装配Properties

<property name="props">
 <props>
  <prop key="01">prop1</prop>
  <prop key="02">prop2</prop>
 </props>
</property> 

 具体实例

1.创建两个对象Person和Student

package xgp.spring.demo;

import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

public class Person {
 private String pid;
 private String name;
 private Student student;
 private List lists;
 private Set sets;
 private Map map;
 private Properties properties;
 private Object[] objects;

 public Person(){
  System.out.println("new person");
 }
 //省略getter和setter方法
}
package xgp.spring.demo;

public class Student {

 public Student(){
  System.out.println("new student");
 }
 public void say(){
  System.out.println("student");
 }
}

配置applicationContext.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.springframework.org/schema/beans
   http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
 <!--
  把person和student放入到spring容器中
  property 用来描述Person类的属性
  value 如果是一般属性,则用value赋值
  ref 如果该属性是引用类型,用ref赋值
  -->
 <bean id="person" class="com.itheima10.spring.di.xml.setter.Person"
   init-method="init"
   lazy-init="true">
  <property name="pid" value="1"></property>
  <property name="name" value="王二麻子"></property>
  <property name="student" ref="student"></property>
  <property name="lists">
   <list>
    <value>list1</value>
    <value>list2</value>
    <ref bean="student"/>
   </list>
  </property>
  <property name="sets">
   <set>
    <value>set1</value>
    <value>set2</value>
    <ref bean="student"/>
   </set>
  </property>
  <property name="map">
   <map>
    <entry key="entry1">
     <value>map1</value>
    </entry>
    <entry key="entry2">
     <ref bean="student"/>
    </entry>
   </map>
  </property>
  <property name="properties">
   <props>
    <!--
     不需要引用类型
     -->
    <prop key="prop1">prop1</prop>
    <prop key="prop2">prop2</prop>
   </props>
  </property>
  <property name="objects">
   <list>
    <value>aa</value>
    <value>bb</value>
   </list>
  </property>
 </bean>
 <bean id="student" class="com.itheima10.spring.di.xml.setter.Student"></bean>
</beans>

编写测试类DIXMLSetterTest

package xgp.spring.test;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import xgp.spring.demo.Person;

public class DIXMLSetterTest {
 /**
  * spring 容器做的事情:
  *  1、spring容器做了什么?(1)启动spring容器
  *       (2)为person和student两个bean创建对象
  *       (3)解析property的name属性,拼接setter方法,解析property的
  *        value或者ref属性,给setter方法传递参数,利用反射技术给对象赋值。
  *       (4)从spring容器中,把对象提取出来,对象调用方法。
  *  2、spring容器执行顺序是什么?
  */
 @Test
 public void test1(){
  ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
  Person person = (Person) context.getBean("person");
  System.out.println(person.getPid());
  System.out.println(person.getName());
  System.out.println(person.getLists());
  System.out.println(person.getSets());
  System.out.println(person.getMap());
  System.out.println(person.getObjects().length);
 }

}
/*1
王五
[list1, list2, xgp.spring.demo.Student@76a9b9c]
[set1, set2, xgp.spring.demo.Student@76a9b9c]
{entry1=map1, entry2=map2}
2*/

spring容器的执行顺序

1.都是默认设置

2.设置student(lazy-init=true)

3.设置person(lazy-init=true)

总结
可以采用两种方法注入参数,构造器要写对应的构造函数,setter要生成相应的setter方法,并编写默认的构造器。

2.5 IOC与DI的意义

学了这些,发现有什么意义?下面写个文档管理系统例子来说明,需求见下图

1.编写Document 接口

public interface Document {
 public void read();
 public void write();
}

2、编写实现类WordDocument ,ExcelDocument ,PDFDocument

public class WordDocument implements Document{
 public void read() {
  System.out.println("word read");
 }

 public void write() {
  System.out.println("word write");
 }
}

3、编写文档管理 系统 DocumentManager

public class DocumentManager {
 private Document document;

 public void setDocument(Document document) {
  this.document = document;
 }
 public DocumentManager(){
 }
 public DocumentManager(Document document) {
  super();
  this.document = document;
 }
 public void read(){
  this.document.read();
 }

 public void write(){
  this.document.write();
 }
}

4、编写测试类DocumentTest

/**
 * 利用ioc和di能做到完全的面向接口编程
 *
 */
public class DocumentTest {
 /**
  * Document document = new WordDocument();
  * 这行代码是不完全的面向接口编程,因为等号的右边出现了具体的类
  */
 @Test
 public void testDocument_NOSPRING(){
  Document document = new WordDocument();
  DocumentManager documentManager = new DocumentManager(document);
  documentManager.read();
  documentManager.write();
 }

 /**
  * 在代码端不知道Document是由谁来实现的,这个是由spring的配置文件决定的
  * <bean id="documentManager"
   class="com.itheima10.spring.iocdi.document.DocumentManager">
   <!--
    document为一个接口
    -->
   <property name="document">
    <!--
     wordDocument是一个实现类,赋值给了document接口
     -->
    <ref bean="pdfDocument"/>
   </property>
  </bean>
  */
 @Test
 public void testDocument_Spring(){
  ApplicationContext context =
     new ClassPathXmlApplicationContext("applicationContext.xml");
  DocumentManager documentManager =(DocumentManager)context.getBean("documentManager");
  documentManager.read();
  documentManager.write();
 }
}

从上面可以看出不适用spring和适用spring的区别

<!--
  documentManager,wordDocument,excelDocument,pdfDocument放入到spring容器中
  -->
 <bean id="wordDocument" class="com.itheima10.spring.iocdi.document.WordDocument"></bean>
 <bean id="excelDocument" class="com.itheima10.spring.iocdi.document.ExcelDocument"></bean>
 <bean id="pdfDocument" class="com.itheima10.spring.iocdi.document.PDFDocument"></bean>

 <bean id="documentManager"
  class="com.itheima10.spring.iocdi.document.DocumentManager">
  <!--
   document为一个接口
   -->
  <property name="document">
   <!--
    wordDocument是一个实现类,赋值给了document接口
    -->
   <ref bean="pdfDocument"/>
  </property>
 </bean>

使用spring只需要在applicationContext中配置相应的<ref bean="">对象,而不需要关注具体的实现类,实现完全的面向接口编程,这也是为什么spring能够和这么多工具集成的原因。

2.6 mvc实例–模拟structs2

需求描述

建立工程目录

编码:
1、创建Dao层
建立PersonDao接口和实现类PersonDaoImpl

public interface PersonDao {
 public void savePerson();
}

public class PersonDaoImpl implements PersonDao {
 @Override
 public void savePerson() {
  System.out.println(" save person");
 }
}

2、建立service层,PersonService接口与PersonServiceImpl实现类

public interface PersonService {
 public void savePerson();
}

public class PersonServiceImpl implements PersonService{
 private PersonDao personDao;

 public void setPersonDao(PersonDao personDao) {
  this.personDao = personDao;
 }
 @Override
 public void savePerson() {
  this.personDao.savePerson();

 }

}

3、建立Action,PersonAction类

public class PersonAction {
 private PersonService personService;

 public void setPersonService(PersonService personService) {
  this.personService = personService;
 }

 public void savePerson(){
  this.personService.savePerson();
 }
}

4、配置applicationContext.xml

 <!--
  把service,dao,action层的类放入到spring容器中
  -->
 <bean id="personDao" class="xgp.spring.demo.PersonDaoImpl"></bean>
 <bean id="personService" class="xgp.spring.demo.PersonServiceImpl">
 <property name="personDao">
  <ref bean="personDao"/>
 </property>
 </bean>
 <bean id="personAction" class="xgp.spring.demo.PersonAction">
 <property name="personService">
  <ref bean="personService"/>
 </property>
 </bean>

5、编写测试类testMVC

public class MVCTest {
 @Test
 public void testMVC(){
  ApplicationContext context =
     new ClassPathXmlApplicationContext("applicationContext.xml");
  PersonAction personAction = (PersonAction)context.getBean("personAction");
  personAction.savePerson();//save person
 }
}

上述实例很清楚的展现出了spring的面向接口编程,service层只需调用dao层的接口,而不需要关注于dao层的实现类,action也只需调用service的接口,而不需要关注service的实现类。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索spring
, javaweb
依赖注入
,以便于您获取更多的相关知识。

时间: 2024-10-24 16:13:16

JavaWeb Spring依赖注入深入学习_java的相关文章

JavaWeb Spring开发入门深入学习_java

1 Spring基本特征 Spring是一个非常活跃的开源框架:它是一个基于Core来构架多层JavaEE系统的框架,它的主要目地是简化企业开发. Spring以一种非侵入式的方式来管理你的代码,Spring提倡"最少侵入",这也就意味着你可以适当的时候安装或卸载Spring,Spring让java亮了. (开放–闭合原理),这里是闭原则. 2 开发spring所需要的工具 (这里先将spring2.5 ,后面3.0) 2.1 Spring的jar包 到http://www.sprin

spring依赖注入测试时出错

问题描述 spring依赖注入测试时出错 错误如下: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'analysisService': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationExcepti

spring 依赖注入的困惑 关于子类和父类

问题描述 spring 依赖注入的困惑 关于子类和父类 有一个Son类 package cn.extend; import javax.annotation.Resource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; public class Son extends Father { } 还有一个父类Father

java框架spring依赖注入的6种方式

spring中如何给对象的属性复制? 1)通过构造方法2)通过set方法给属性注入值3)p命名空间4)自动转配(了解即可,不推荐使用)5)注解6)通过接口 准备工作(模拟业务方法)Action-->service-->dao 1)UserDao:     p<span style="font-family:Courier New;">ublic class UserDao {           public void save(){              

面向对象编程依赖注入详解_java

说说依赖注入 在面向对象编程中,我们经常处理处理的问题就是解耦,程序的耦合性越低表明这个程序的可读性以及可维护性越高.控制反转(Inversion of Control或IoC)就是常用的面向对象编程的设计原则,使用这个原则我们可以降低耦合性.其中依赖注入是控制反转最常用的实现. 什么是依赖 依赖是程序中常见的现象,比如类Car中用到了GasEnergy类的实例energy,通常的做法就是在Car类中显式地创建GasEnergy类的实例,并赋值给energy.如下面的代码 interface E

Spring 依赖注入方式详解

阅读目录 1.Set注入 2.构造器注入 3.静态工厂的方法注入 4.实例工厂的方法注入 5.总结    平常的java开发中,程序员在某个类中需要依赖其它类的方法,则通常是new一个依赖类再调用类实例的方法,这种开发存在的问题是new的类实例不好统一管理,spring提出了依赖注入的思想,即依赖类不由程序员实例化,而是通过spring容器帮我们new指定实例并且将实例注入到需要该对象的类中.依赖注入的另一种说法是"控制反转",通俗的理解是:平常我们new一个实例,这个实例的控制权是我

Spring依赖注入的两种方式(根据实例详解)

1,Set注入    2,构造注入 Set方法注入: 原理:通过类的setter方法完成依赖关系的设置 name属性的取值依setter方法名而定,要求这个类里面这个对应的属性必须有setter方法. Set方法注入时spring中配置文件: <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans&qu

spring依赖注入的3种实现方式

 在讲解依赖注入的3种实现方式之前,这里先澄清一下依赖注入的意义:让组件依赖于抽象,当组件要与其他实际对象发生依赖关系时,通过抽象来注入依赖的实际对象.     依赖注入的3种实现方式分别是:接口注入(interface injection).Set注入(setter injection)和构造注入(constructor injection).接下来笔者还将主要通过举例的方式,把依赖注入的3种实现方式介绍给读者.     3.2.1  接口注入(interface injection)    

详析Spring中依赖注入的三种方式_java

前言 平常的java开发中,程序员在某个类中需要依赖其它类的方法,则通常是new一个依赖类再调用类实例的方法,这种开发存在的问题是new的类实例不好统一管理,spring提出了依赖注入的思想,即依赖类不由程序员实例化,而是通过spring容器帮我们new指定实例并且将实例注入到需要该对象的类中.依赖注入的另一种说法是"控制反转",通俗的理解是:平常我们new一个实例,这个实例的控制权是我们程序员,而控制反转是指new实例工作不由我们程序员来做而是交给spring容器来做. 在Sprin