Spring-IOC

Posted 再来半包

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring-IOC相关的知识,希望对你有一定的参考价值。

Spring概述

Spring全家桶:spring、springmvc、spring boot、spring cloud

spring:出现是在2002左右,解决企业开发的难度。减轻对项目模块之间的管理。

​ 类和类之间的管理,帮助开发人员创建对象,管理对象之间的关系。

​ spring核心技术:ioc、aop。能实现模块之间,类之间的解耦合。

依赖:classa中使用了classb的属性或者方法,叫做classa依赖classb

spring官网:spring.io

spring优点

轻量

Spring框架使用的jar都比较小,一般在1M以下或者几百kb。Spring核心功能的所需的jar总共在3M左右。

Spring框架运行占用的资源少,运行效率高。不依赖其他jar

针对接口编程,解耦合

Spring提供了loc控制反转,由容器管理对象,对象的依赖关系。原来在程序代码中的对象创建方式,现在由容器完成。对象之间的依赖解耦合。

AOP编程的支持

通过Spring提供的AOP功能,方便进行面向切面的编程,许多不容易用传统OOP实现的功能可以通过AOP轻松应付

在Spring中,开发人员可以从繁杂的事务管理代码中解脱出来,通过声明方式灵活地进行事务的管理,提高开发效率和质量。

方便集成各种优秀框架

Spring不排斥各种优秀的开源框架,相反Spring可以降低各种框架的使用难度,Spring提供了对各种优秀框架(如Struts、Hibernate、MyBatis)等的直接支持。简化框架的使用。Spring像插线板一样,其他框架是插头,可以容易的组合到一起。需要使用哪个框架,就把这个插头放入插线板,不需要可以轻易的移除。

Spring体系结构

框架怎么学:框架是一个软件,是其他人写好的软件。

1)知道框架能做什么,mybatis–访问数据库,对表中的数据执行增删改查。

2)框架的语法,框架要完成一个功能,需要一定的步骤支持的。

3)框架的内部实现,框架的内部怎么做,原理是什么。

4)通过学习,实现一个属于自己的框架。

Spring的核心功能 ioc

ioc(Inversion of Control):控制反转,是一个理论,概念,思想。

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

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

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

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

public static void  main(String args[])
	Student student=new Student(); //在代码中,创建对象。  -- 正转

容器:是要给服务器软件,一个框架(spring)

为什么要使用ioc:目的就是减少对代码的改动,也能实现不同的功能。实现解耦合。

Java中创建对象由哪些方式:

1、构造方法,new Student()

2、反射

3、序列化

4、克隆

5、ioc:容器创建对象

6、动态代理

ioc的体现:

​ servlet 1:创建类继承HTTP Servlet

​ 2:在web.xml 注册servlet,使用的是:

<servlet-name>myservlet</servlet-name>
<servlet-class>com.hr.MyServlet</servlet-class>

​ 3:没有创建Servlet对象,没有 MyServlet myservlet = new MyServlet();

​ 4:Servlet 是Tomcat服务器它给你创建的。Tomcat也称为容器

​ Tomcat作为容器:里面存放的有Servlet对象, Listener , Filter对象

IoC的技术实现,

​ DI 是ioc的技术实现

​ DI(Dependency Injection):依赖注入,只需要在从程序中提供要使用的对象的名称就可以了,至于对象如 何在容器中创建,赋值,查找都由容器内部实现。

Spring是使用的di实现了ioc的功能,spring底层创建对象,使用的是反射机制。

spring是一个容器,管理对象,给属性赋值,底层是反射创建对象。

Spring第一个例子

使用的ioc,由spring创建对象

实现步骤:

1、创建maven项目

2、加入maven的依赖

​ spring的依赖,版本5.2.5版本

​ junit依赖

3、创建类(接口和他的实现类)

​ 和没有使用框架一样,就是普通的类

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

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

5、测试spring创建的。

@Test
    public void test02()
        //使用spring容器创建的对象
        //1.指定spring配置文件的名称
        String config="beans.xml";
        //2.创建表示spring容器的对象,ApplicationContext
        //ApplicationContext就是表示spring容器,通过容器获取对象使用对象了
        //ClassPathXmlApplicationContext:表示从类路径中加载spring的配置文件
        ApplicationContext ac=new ClassPathXmlApplicationContext(config);

        //从容器中获取某个对象,你要调用对象的方法
        //getBean("配置文件中的bean的id值")
        SomeService someService = (SomeService) ac.getBean("someService");

        //使用spring创建好的对象,调用方法
        someService.doSome();
    

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

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

通过方法获取spring容器中Java对象的信息

@Test
    public void test03()
        String config="beans.xml";
        ApplicationContext ac = new ClassPathXmlApplicationContext(config);
        //使用spring 提供的方法,获取容器中定义的对象的数量
        int nums=ac.getBeanDefinitionCount();
        System.out.println("容器中定义的对象的数量"+nums);
        //使用spring提供的方法,获取容器中对象的名称,返回会是一个数组
        String[] names = ac.getBeanDefinitionNames();
        for (String name : names) 
            System.out.println(name);
        
    

创建非自定义的类对象

首先要在beans.xml中<beans>标签中配置

<bean id="mydate" class="java.util.Date" />

跟自定义对象不同的是,路径要写为已经写好的路径

测试非自定义类对象

@Test
    public void test04()
        String config="beans.xml";
        ApplicationContext ac = new ClassPathXmlApplicationContext(config);
        //使用getBean()
        Date mydate = (Date) ac.getBean("mydate");
        System.out.println(mydate.getTime());
    

基于XML的DI

​ 注入:就是赋值的意思
​ 简单类型:spring中规定Java的基本数据类型和spring都是简单类型
​ di:给属性赋值
​ 1、set注入(设值注入):spring调用类的set方法,你可以在set方法中来完成属性赋值
​ 1)简单类型的set注入
<bean id="xx" class="yyy">
<property name="属性名字" value="此属性的值" />
​ 一个property只能给一个属性赋值
<property ... >
</bean>

2、引用类型的set注入:spring调用类的set方法
<bean id="xxx" class="yyy">
<property name="属性名称" ref="bean的id(对象的名称)">
</bean>

简单类型设值注入

实例:

<!--给student实体类赋值-->
<bean id="myStudent" class="com.hr.qjw.ba01.Student" >
        <property name="name" value="李四" />
        <property name="age" value="21" />
    </bean>

通过实体类student类中的set设置注入,通过set类中的set方法,将值赋给变量

需要实体类中必须有set方法,否则会报错

设置注入只是去调用了对应的set方法,有没有对应的属性不会报错

引用类型设值注入

实例

<bean id="myStudent" class="com.hr.qjw.ba02.Student" >
        <property name="name" value="李四" />  <!--setName("李四")-->
        <property name="age" value="21" />  <!-- setAge(21)-->
<!--        引用类型-->
        <property name="School" ref="mySchool" />
    </bean>

<!--    声明School对象-->
    <bean id="mySchool" class="com.hr.qjw.ba02.School">
        <property name="name" value="河北软件职业"/>
        <property name="address" value="保定"/>
    </bean>

构造注入

构造注入:spring调用类有参数构造方法,在创建对象的同时,在构造方法中给属性赋值。
构造注入使用<constructor-arg> 标签
<constructor-arg>标签:一个<constructor-arg>表示构造方法一个参数。
<constructor-arg>标签属性:
name:表示构造方法的形参名
index:表示构造方法的参数的位置,参数从左往右是 0,1,2的顺序
value:构造方法的形参类型是简单类型的,使用value
ref:构造方法是引用类型的,使用ref

三种构造注入方法的实例

<!--    声明School对象-->
    <bean id="myXueXiao" class="com.hr.qjw.ba03.School">
        <property name="name" value="清华大学"/>
        <property name="address" value="北京"/>
    </bean>
<!--    使用name属性实现构造注入-->
    <bean id="myStudent" class="com.hr.qjw.ba03.Student" >
       <constructor-arg name="myname" value="ccl" />
        <constructor-arg name="myage" value="20" />
        <constructor-arg name="myschool" ref="myXueXiao" />
    </bean>
<!--    使用index属性-->
    <bean id="myStudent2" class="com.hr.qjw.ba03.Student" >
        <constructor-arg index="0" value="hxy"/>
        <constructor-arg index="1" value="19"/>
        <constructor-arg index="2" ref="myXueXiao"/>
    </bean>
<!--    使用index省略-->
    <bean id="myStudent3" class="com.hr.qjw.ba03.Student" >
        <constructor-arg  value="hxy"/>
        <constructor-arg  value="19"/>
        <constructor-arg  ref="myXueXiao"/>
    </bean>

前面两种的方法,bean标签里面的顺序不规定,但是第三种index省略必须要保持顺序符合index 0,1,2的顺序才可以

创建文件对象

<!--    创建File,使用构造注入-->
    <bean id="myfile" class="java.io.File">
        <constructor-arg name="parent" value="D:\\Project\\spring-course\\ch02-di-xml"/>
        <constructor-arg name="child" value="readme.txt"/>
    </bean>

引用类型自动注入

使用的规则常用的是byName,byType

byName

1、byName(按名称注入):Java类中引用类型的属性名和spring容器中(配置文件)<bean>的id名称一样,
且数据类型是一致的,这样的容器中的bean,spring能够赋值给引用类型。
语法规则:
<bean id="xx" class="yyy" autowire="byName">
简单类型属性赋值
</bean>

实例:

<!--    byName-->

    <bean id="myStudent" class="com.hr.qjw.ba04.Student" autowire="byName">
        <property name="name" value="李四" />  <!--setName("李四")-->
        <property name="age" value="21" />  <!-- setAge(21)-->
<!--        引用类型-->
<!--        <property name="School" ref="mySchool" />-->
    </bean>

<!--    声明School对象-->
    <bean id="school" class="com.hr.qjw.ba04.School">
        <property name="name" value="清华大学"/>
        <property name="address" value="北京"/>
    </bean>

声明的对象id要与数据类型的变量名相同

byType

2、byType(类型注入):Java类中引用类型的数据类型和spring容器中(配置文件)<bean>的class属性
是同源关系的,这样的bean能够赋值给引用类型
同源就是一类的意思:
1、Java类中引用类型的数据类型和bean的class的值是一样的。
2、Java类中引用类型的数据类型和bean的class的值是父子类关系的。
3、Java类中引用类型的数据类型和bean的class的值接口和实现类关系的。
语法规则:

     <bean id="xx" class="yyy" autowire="byType">
        简单类型属性赋值
     </bean>

​ 注意:在byType中,在xml配置文件中声明bean只能有一个符合条件的
​ 多余一个是错误的

实例:

1、Java类中引用类型的数据类型和bean的class的值是一样的。

    <bean id="myStudent" class="com.hr.qjw.ba05.Student" autowire="byType">
        <property name="name" value="李四" />  <!--setName("李四")-->
        <property name="age" value="21" />  <!-- setAge(21)-->
    </bean>
    <!--    声明School对象-->
    <bean id="mySchool" class="com.hr.qjw.ba05.School">
        <property name="name" value="人民大学"/>
        <property name="address" value="北京"/>
    </bean>

2、Java类中引用类型的数据类型和bean的class的值是父子类关系的。

    <bean id="myStudent" class="com.hr.qjw.ba05.Student" autowire="byType">
        <property name="name" value="李四" />  <!--setName("李四")-->
        <property name="age" value="21" />  <!-- setAge(21)-->
    </bean>
    <!--声明School子类-->
    <bean id="primarySchool" class="com.hr.qjw.ba05.primarySchool">
        <property name="name" value="河北软件"/>
        <property name="address" value="保定"/>

    </bean>

primarySchool是School的子类,所以也可以通过自动引用注入

基于注解的DI

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

使用注解的步骤:

​ 1、加入maven的依赖 spring-context,在你加入spring-context的同时, 间接加入spring-aop的依赖。

​ 使用注解必须使用spring-aop依赖

​ 2、在类中加入spring的注解(多个不同功能的注解)

​ 3、在spring的配置文件中,加入一个组件扫描器的标签,说明注解在你的项目中的位置

​ 学习的注解:
​ 1、@Component

​ 2、@Respotory

​ 3、@Service

​ 4、@Controller

​ 5、@Value

​ 6、@Autowired

​ 7、@Resource

​ @Component:创建对象的,等同于<bean>的功能

属性:value 就是对象的名称,也就是bean的id值,

value的值是唯一的。创建的对象在整个spring的容器中就一个

位置:在类的上面

@Component(value = “myStudent”)等同于

<bean id="myStudent" class="com.hr.qjb.ba01.Student" />

spring中和@Component功能一致,创建对象的注解还有:

1、@Repository(用来持久层类的上面):放在dao的实现类上面,

表示创建dao对象,dao对象是能访问数据库的。

2、@Service(用在业务层类的上面):放在Service的实现类上面,

创建service对象,service对象是做业务处理,可以有事务等供你的。

3、@Controller(用在控制器的上面):放在控制器(处理器)类的上面,创建控制器对象的,

控制器对象,能够接受用户提交的参数,显示请求的处理结果

以上三个注解的使用语法和@Component一样的。都能创建对象,但是这三个注解还有额外的功能

@Repository、@Service、@Controller是给项目的对象分层的。

@Component 会用到的地方:以上三个类上面都不是的地方,而且需要创建对象的地方使用

@Component用法

使用value属性,指定对象名称

@Component(value = “myStudent”)

省略value
@Component(“myStudent”)

不指定对象名称,由spring提供默认名称:类名的首字母小写
@Component

声明组件扫描器(component-scan),组件就是Java对象

base-package:指定注解在你的项目中的包名
component-scan工作方式:spring会扫描遍历base-package指定的包
把包中和子包中的所有类,找到类中的注解,按照注解的功能创建对象,或给属性赋值。
加入了component-scan标签,配置文件的变化:
1、加入一个新的约束文件spring-context.xsd
2、给这个新的约束文件起个命名空间的名称

<context:component-scan base-package="com.hr.qjb.ba01"/>

指定多个包的三种方式

<!--    第一种方式:使用多次组件扫描器,制定不同的包-->
    <context:component-scan base-package="com.hr.qjb.ba01"/>
    <context:component-scan base-package="com.hr.qjb.ba02"/>

<!--    第二种方式:使用分隔符(;或,)分割多个包名-->
    <context:component-scan base-package="com.hr.qjb.ba01;com.hr.qjb.ba02"/>

<!--    第三种方式:指定父包-->
    <context:component-scan base-package="com.hr.qjb"/>

简单类型赋值

@Value:简单类型的属性赋值

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

位置:1、在属性定义的上面,无需set方法,推荐使用

​ 2、在set方法的上面

  	//用在属性上
	@Value(value = "小龙女")
    private String name;
    private int age;

    public void setName(String name) 
        this.name = name;
    
	//用在set上
    @Value("2323")
    public void setAge(int age) 
        this.age = age;
    

    @Override
    public String toString() 
        return "Student" +
                "name='" + name + '\\'' +
                ", age=" + age +
                '';

引用类型赋值

@Autowired:spring框架提供的注解,实现应用类型的赋值。

spring中通过注解给引用类型赋值,使用的是自动注入原理,支持byName,byType

@Autowired:默认使用的是byType自动注入

位置:1、在属性定义的上面,无需set方法,推荐使用

​ 2、在set方法的上面

引用类型byType注入

@Component("mySchool")
public class School 
    @Value("河北软件")
    private String name;
    @Value("保定")
    private String addressSpring-Ioc

spring-IOC

spring-ioc

Spring-IOC注入

二:Spring-IOC源码

spring-ioc