Spring—IoC控制反转

Spring—IoC控制反转

  • spring核心技术:ioc,aop。能实现模块之间的解耦合
  • 依赖:calssA中使用classB的属性或者方法,叫做classA依赖classB

一、ioc的概念(spring的一个核心功能)

  • ioc:控制反转,是一个理论,概念,思想

  • 描述:把对象的创建,赋值,管理工作,都交给代码之外的容器实现,也就是对象的创建是有其他外部资源完成的。

  • 控制:创建对象,对象的属性赋值,对象之间的关系管理。

  • 反转:把原来的开发人员管理,创建对象的权限转移给代码之外的容器实现。由容器代替开发人员管理对象。创建对象,给属性赋值

  • 正转:有开发人员在代码中,使用new构造方法创建对象,开发人员主动管理对象。

    public static void main(string args[]){
        Student student = new Student();//在代码中,创建对象。————正转
    }
    
  • 容器:是一个服务器软件,一个框架(spring)

  • 使用ioc的目的:减少对代码的改动,也能实现不用的功能。实现耦合。

二、ioc的技术实现

  • DI是ioc 的技术实现
  • DI:依赖注入,只需要在程序中提供要使用的对象名称就可以,至于对象如何在容器中创建,赋值,查找都是由容器内部实现。
  • spring是使用的DI实现了ioc的功能,spring底层创建对象,使用的是反射机制。
  • spring是一个容器,管理对象,给属性赋值,底层是反射创建对象。

Ⅰ、DI的实现(两种)

  1. 在spring的配置文件中,使用标签和属性完成,叫做基于XML的di实现
  2. 使用spring中的注解,完成属性的赋值,叫做基于注解的id实现

Ⅱ、DI的语法分类

注入就是赋值的意思

  1. set注入(设置注入):spring调用类的set方法,在set方法可以实现属性的赋值(80%都是使用set注入)
  2. 构造注入:spring调用类的有参构造方法,创建对象。在构造方法中完成赋值

1、实现步骤

  1. 创建maven项目

  2. 加入maven的依赖

    spring的依赖

    junit依赖

  3. 创建类(接口和他的实现类)和没有使用框架一样,就是普通的类

    通过spring的语法完成属性的赋值

  4. 创建spring需要使用的配置文件

    声明类的信息,这些类由spring创建和管理

  5. 测试spring创建的对象

2、bean标签

Ⅰ、spring的配置文件

  1. beans:是根标签,spring把Java对象成为bean
  2. spring-beans.xsd 是约束文件,和mybatis指定 dtd是一样的。

Ⅱ、告诉spring创建对象

  • 声明bean,就是spring要创建某个类的对象

  • id:对象的自定义名称,唯一值。spring通过这个名称找到对象

  • class:类的全限定名称(不能是接口,因为spring是反射机制创建对象,必须使用类)

  • spring就完成SomeService someService = new SomeServiceImpl();

  • spring是把创建好的对象放入到map中,spring框架有一个map对象的

    springMap.put( id的值 , 对象 );

    eg : springMap.put ( “someService” , new SomeServiceImpl () ) ;

  • 一个bean标签只能声明一个对象

    <bean id = "someService" class = "nuc.gjq.service.impl.SomeServiceImpl" />
    

3、使用spring容器创建的对象

spring默认创建对象的时间:在创建spring的容器时,会创建配置文件中的所有对象

public void test(){
    
    
    //使用spring容器创建的对象
    //1.指定spring配置文件的名称
    String config = "beans.xml";
    
    //2.创建表示spring容器的对象,ApplicationContext
    //ApplicationContext就是表示Spring容器,通过容器获取对象
    //ClassPathXmlApplicationContext:表示从类路径中加载spring的配置文件
    ApplicationContext ac = new ClassPathXmlApplicationContext(config);
    
    //3.从容器中获取某个对象,你要调用对象的方法
    //getBean("配置文件中的bean的id值")
    SomeService service = (service) ac.getBean("someService");
    
    //4.使用spring创建好的对象
    service.doSome();
}

4、获取spring容器中Java对象的信息

public void test(){
    String config = "beans.xml";
    ApplicationContext ac = new ClassPathXmlApplicationContext(config);
    //使用spring提供的方法,获取容器中定义的对象数量
    int nums = ac.getBeanDefinitionCount();
    System.out.print("容器中定义的对象数量:"+nums);
    //容器中每个定义的对象的名称
    String names[] = ac.getBeanDefinitionNames();
    for(String name:names){
        System.out.print(name);
    }
}

5、获取一个非自定义的类对象

spring创建对象:默认调用的是无参构造方法

<!-- 创建一个存在的某个类对象 -->
< bean id = "mydate" class = "java.util.Date" />
public void test(){
    
    
    String config = "beans.xml";
    ApplicationContext ac = new ClassPathXmlApplicationContext(config);
    //使用getBean();
    Date my = (Date) ac.getBean("mydate");
     System.out.print("Date:"+my);
}

三、基于XML的DI

1.从容器中获取Student对象

public void test(){
     String config = "applicationContext.xml";//xml文件名为固定格式
    ApplicationContext ac = new ClassPathXmlApplicationContext(config);
    //从容器中获取student对象
    student myStudent = (Student) ac.getBean("myStudent");
    System.out.print("student对象:"+myStudent);
}

2.注入分类

Ⅰ、set注入

  • spring调用类的set方法,用set方法完成属性赋值
  • 不管是自己写的类,还是本身有的类,只要有set方法就能使用(例如:非自定义的类对象)
(1)简单类型的set注入

简单类型:Java的基本数据类型+String

格式:
<bean id = "xx" class = "yyy">
    <property name = "属性名字" value = "此属性的值" />
    <!-- 一个property只能给一个属性赋值,如果有多个属性需要多个property -->   
</bean>   
public class student {
    private String name;
    private String age;
    public student(){
    }
    public void setName(String name) {
        this.name = name;
    }
    public void setAge(String age) {
        this.age = age;
    }
}
<bean id = "myStudent" class = "nuc.gjq.Student">
    <property name = "name" value = "zs" /> <!-- setName("zs") -->   
    <property name = "age" value = "23" /> <!-- setAge(23) -->   
</bean> 
(2)引用类型的set注入
格式:
<bean id = "xx" class = "yyy">
    <property name = "属性名字" ref = "bean的id(对象的名称)" />
    <!-- 一个property只能给一个属性赋值,如果有多个属性需要多个property -->   
</bean>   
 private String name;
    private String age;
    private School school;
    public Student() {
    }
    public void setName(String name) {
        this.name = name;
    }
    public void setAge(String age) {
        this.age = age;
    }
    public void setSchool(School school) {
        this.school = school;
    }
<!-- 声明School对象 -->
<bean id = "myShool" class = "nuc.gjq.School">
      <property name = "name" value = "中北大学" />
      <property name = "address" ref = "山西太原" />
</bean>
<!-- 声明Student对象 -->
<bean id = "myStudent" class = "nuc.gjq.Student">
    <property name = "name" value = "zs" /> <!-- setName("zs") -->   
    <property name = "age" value = "23" /> <!-- setAge(23) -->   
    <property name = "school" ref = "myShool" />
</bean> 

Ⅱ、构造注入

  • spring调用类有参数构造方法,在创建对象的同时,在构造对象的同时,在构造方法中给属性赋值
  • 构造注入使用< constructor - arg > 标签
  • < constructor - arg > 标签是属性
    • name:表示构造方法的形参名
    • index:表示构造方法的参数位置,参数从左往右位置是0,1,2的顺序
    • value:构造方法的形参类型是简单类型的,使用vlaue
    • ref:构造方法的形参类型是引用类型的,使用ref
(1)使用name属性
<!-- 声明School对象 -->
<bean id = "myShool" class = "nuc.gjq.School">
      <property name = "name" value = "中北大学" />
      <property name = "address" ref = "山西太原" />
</bean>
<!-- 声明Student对象 -->
<bean id = "myStudent" class = "nuc.gjq.Student">
    < constructor-arg name = "name"  value = "zs" > 
    < constructor-arg name = "age" value = "23" > 
    < constructor-arg "school" ref = "myShool" > 
</bean> 
(2)使用index属性
<!-- 0,1,2的顺序可以改变 -->
<bean id = "myStudent" class = "nuc.gjq.Student">
    < constructor-arg index = "0" value = "zs" > 
    < constructor-arg index = "1" value = "23" > 
    < constructor-arg index = "2" ref = "myShool" > 
</bean>
<!-- 也可以省略index -->
<bean id = "myStudent" class = "nuc.gjq.Student">
    < constructor-arg  value = "zs" > 
    < constructor-arg  value = "23" > 
</bean>

3、引用类型属性自动注入

spring框架根据某些规则可以给引用类型赋值,不用手动赋值

Ⅰ、byName方式自动注入(按名称注入)

  • Java类中引用类型的属性名和spring容器中(配置文件)的id名称一样且数据类型是一致的,这样的容器中的bean,spring能够赋值给引用类型

  • 语法:

    	<bean id="xx" class="yyy" autowire="byName">
            简单类型属性赋值
        </bean>		
    
     <!-- byname自动注入 -->
        <bean id = "myStudent" class = "nuc.gjq.student.Student" autowire="byName">
            <property name="name" value="zs"/>
            <property name="age" value="23"/>
        </bean>
        <bean id="school" class="nuc.gjq.student.School">
            <property name="name" value="中北大学"/>
            <property name="address" value="山西太原"/>
        </bean>
    

Ⅱ、byType方式自动注入

  • Java类中引用类型的数据类型和spring容器中(配置文件) 的class属性是同源关系的,这样的bean能够赋值给引用类型

  • 同源(一类的意思)

    • Java类中引用类型的数据类型和bean的class的值是一样的
    • Java类中引用类型的数据类型和bean的class的值是父子关系的
    • Java类中引用类型的数据类型和bean的class的值是接口和实现类关系的
  • 语法

    <bean id="xx" class="yyy" autowire="byType">
            简单类型属性赋值
        </bean>		
    
     <bean id = "myStudent" class = "nuc.gjq.student.Student" autowire="byType">
            <property name="name" value="zs"/>
            <property name="age" value="23"/>
        </bean>
        <bean id="myShool" class="nuc.gjq.student.School">
            <property name="name" value="中北大学"/>
            <property name="address" value="山西太原"/>
        </bean>
    

4、为应用指定多个spring配置文件

  1. 分配方式

    1. 按功能模块,一个模块一个配置文件
    2. 按类的功能,数据库相关的配置一个配置文件,做事务的功能一个配置文件,做service功能的一个配置文件等
  2. 包含关系的配置文件

    1. spring-total表示主配置文件 :包含其他的配置文件的,主配置文件一般是不定义对象的

    2. 语法

       <import resource="其他配置文件路径"/>
      
    3. 关键字:"classpath:"表示类路径(class文件所在的目录)

      在spring的配置文件中要指定其他文件的位置,需要使用classpath,告诉spring到哪里去加载读取文件

      <import resource="classpath:02/spring-school.xml"/>
      <import resource="classpath:02/spring-student.xml"/>
      
    4. 通配符

      • 在包含关系的配置文件中,可以用通配符(*:表示任意字符)
      • 注意:主的配置文件名称不能包含在通配符的范围中,(不能叫做spring-total.xml)
      • 配置文件文件必须放在同一个目录中
    <import resource="classpath:02/spring-*.xml"/>
    

四、基于注解的DI

通过注解完成Java对象的创建,属性赋值

1、使用注解的步骤

  1. 加入maven依赖 spring-context,加入依赖的同时,间接加入spring-aop的依赖,使用注解必须使用spring-aop依赖
  2. 在类中加入spring的注解(多个不同功能的注解)
  3. 在spring的配置文件中,加入一组件扫描器的标签,说明注解在项目中的位置

2、学习的注解

  1. @Component
  2. @Respotory
  3. @Service
  4. @Controller
  5. @Value
  6. @Autowired
  7. @Resource

3、实现步骤

  1. 加入依赖

  2. 创建类,在类中加入注解

  3. 创建spring的配置文件

    声明组件扫描器的标签,指明注解在你的项目中的位置

  4. 使用注解创建对象,创建容器ApplicationContext

4、@Component

  1. 用于创建对象,等同于的功能
  2. 属性:value 就是对象的名称,也就是bean的id值,value的值是唯一的,创建的对象在整个spring容器中就一个
  3. 位置:在类的上面
  4. @Component(value = “myStudent”)等同于
  5. @Repository,@Service,@Controller 使用语法和 @Component 一样,都能创建对象,但是这三个注解还有额外的功能
    • @Repository(用在持久层类的上面):放在dao的实现类的上面,表示创建dao对象,dao对象是能访问数据库的。
    • @Service(用在业务层类的上面):放在service的实验室类上面,创建service对象,service对象是做业务处理,可以由事务等功能的。
    • @Controller(用在控制器的上面):放在控制器(处理器)类的上面,创建控制器对象的,控制器对象,能够接受用户提交的参数,显示请求的处理结果
  6. @Repository,@Service,@Controller是给项目分层的

Ⅰ、使用方法

1、java代码(不在持久层,不在业务层,不在控制器层,eg:entity层)

//使用value属性,指定对象名称
	@Component(value = "myStudent")
//最常用,省略value
	@Component("myStudent")
//不指定对象名称,由spring提供的默认名称:类名的首字母小写
	@Component

2、声明组件扫描器(component-scan)

 <context:component-scan base-package="nuc.gjq.ba01"/>
  • 组件就是Java对象
  • base-package:指定注解在你的项目中的包名
  • component-scan工作方式:spring会扫描遍历base-package指定的包
  • 把包中和子包中的所有类,找到类中的注解,按照注解的功能创建对象,或给属性赋值
  • 调用无参构造方法,创建对象

Ⅱ、指定多个包的三种方式

  •    <!--第一种:使用多次组件扫描器,指定不同的包-->
          <context:component-scan base-package="nuc.gjq.ba01"/>
          <context:component-scan base-package="nuc.gjq.ba02"/>
    
  •   <!--第二种:使用分隔符(;或,)分隔多个包名-->
          <context:component-scan base-package="nuc.gjq.ba01;nuc.gjq.ba02"/>
    
  •    <!--第三种方式:指定父包-->
          <context:component-scan base-package="nuc.gjq"/>
    

5、简单类型属性注入@Value

Ⅰ、属性

  • value是String类型的,表示简单类型的属性值

Ⅱ、位置:

  1. 在属性定义的上面,无需set方法,推荐使用
  2. 在set方法上面
	@Value(value = "zs")
    private String name;
    @Value(value = "23")
    private int age;

6、引用类型注入@Autowired

  • spring 框架提供的注解,实现引用类的赋值
  • spring中通过注解给引用类型赋值,使用的是自动注入原理,支持byName,byType
  • @Autowired:默认使用byType自动注入

Ⅰ、属性

  • required 是一个 boolean 类型的,默认 ture
    1.required = true:表示引用类型赋值失败,程序报错,并终止执行
    2.required = false:引用类型如果赋值失败,程序正常执行,引用类型是null

Ⅱ、位置

  1. 在属性定义的上面,无需set方法,推荐使用
  2. 在set方法上面

Ⅲ、byType方法(默认方法)

 @Autowired
    private School school;
public class School {
    
    
    @Value(value = "中北大学")
    private String name;
    @Value(value = "山西太原")
    private String address;
}

Ⅳ、byName方法

  1. 在属性上面加入@Autowired
  2. 在属性上面加入 @Qualifier(value = “bean的id”):表示使用指定名称的bean完成赋值(value可以省略
@Autowired
    @Qualifier("mySchool")
    private School school;
@Component("mySchool")
public class School {
    
    
    @Value(value = "中北大学")
    private String name;
    @Value(value = "山西太原")
    private String address;
}

7.JDK注解@Resource自动注入

  • @Resource:来自jdk中的注解,spring框架提供了对这个注解的支持,可以使用它给应引用类型赋值
  • 使用的是自动注入原理,支持byName,byType,默认是byName
  • 默认是byName:先使用byName自动注入,如果byName赋值失败,再使用byType

Ⅰ、位置

  1. 在属性定义的上面,无需set方法,推荐使用
  2. 在set方法上面
@Resource
private School school;

Ⅱ、@Resource只使用byName的方式

  • 需要增加一个属性name
  • name的值是bean的id(名称)
@Resource(name = "mySchool")
private School school;

8、导入文件的形式(${})

  1. 先创建test.properties.file

    myname = “张三”
    myage = 23
    
  2. 加载属性配置文件

    <context:component-scan base-package="nuc.gjq.ba02"/>
    <context:property-placeholder location="classpath:test.properties"/>
    
  3. 赋值

    @Value("${myname}")
    private String name;
    @Value("${myage}")
    private int age;
    

五、单元测试

  • 一个工具类库,做测试方法使用

  • 单元:指定的是方法,一个类中有很多方法,一个方法称为单元

  • 使用单元测试

    1. 需要加入junit依赖

      <dependency>
          <groupId>junit</groupId>
          <artifactId>junit</artifactId>
          <version>4.11</version>
          <scope>test</scope>
      </dependency>
      
    2. 创建测试作用的类:叫做测试类

      src/test/java目录中创建类

    3. 创建测试方法

      1)public方法

      2)没有返回值 (void)

      3)方法名称自定义,建议名称是test+测试的方法名

      4)方法没有参数

      5)方法的上面加入@Test,这样的方法是可以单独执行的,不用使用main方法

public void test(){
      String config = "nuc.gjq.applicationContext.xml";
      ApplicationContext ac = new ClassPathXmlApplicationContext(config);
        
      //从容器中获取student对象
  	  student myStudent = (Student) ac.getBean("myStudent");
 	  System.out.print("student对象:"+myStudent);
    }
	<dependency>
  	  <groupId>junit</groupId>
 	   <artifactId>junit</artifactId>
  	  <version>4.11</version>
  	  <scope>test</scope>
	</dependency>
2. 创建测试作用的类:叫做测试类

	src/test/java目录中创建类

3. 创建测试方法

	1)public方法

	2)没有返回值 (void)

	3)方法名称自定义,建议名称是test+测试的方法名

	4)方法没有参数

	5)方法的上面加入@Test,这样的方法是可以单独执行的,不用使用main方法
public void test(){
      String config = "nuc.gjq.applicationContext.xml";
      ApplicationContext ac = new ClassPathXmlApplicationContext(config);
        
      //从容器中获取student对象
  	  student myStudent = (Student) ac.getBean("myStudent");
 	  System.out.print("student对象:"+myStudent);
    }

猜你喜欢

转载自blog.csdn.net/qq_45414532/article/details/115047920