美文网首页
spring ioc

spring ioc

作者: 许先森的许 | 来源:发表于2019-01-10 17:47 被阅读11次
1、IoC 依赖注入(控制反转) 方便解耦

耦合:
业务层的A类中要使用持久层B类对象,于是在A类中new了一个B类对象来用,这就导致了A类会强依赖于B类,产生耦合,耦合只能减弱不能消除,消除相当于这两个类毫无关系了。
减弱耦合:
不在A类中newB类的对象,建立一个对象容器(工厂),这个容器里面就产生各种对象给别的类调用,对象的生成只在这个容器中,可以把要生成的对象path写在properties或xml文件中,在容器中用静态代码块读取properties或xml中的内容,通过反射生成对象,保存在容器中,比如一个Map中,再向外界提供一个根据map的key获取对象的方法。

1、1那么spring是如何做到减弱耦合的呢?

原理和上面的对象容器工厂差不多,容器由spring完成了,我们只需要在xml中配置业务层和持久层的对象信息:说明要创建哪个对象、用什么方式去取:

    <bean id=“accountService” class=“com.demo.service.impl.AccountServiceImpl”><bean/>
    <bean id=“accountDao” class=“com.demo.dao.impl.AccountDaoImpl”><bean/>
    id:对象的唯一标示;class:要创建对象的全限定类名

spring有一个核心容器,xml中读取的对象都生成放在核心容器中;下面我们只需要获取到核心容器后,再根据bean的id获取对象:

核心容器类:
    ApplicationContext:
        是BeanFactory下的子接口的再子接口。
        特点是创建bean对象时,采用的是立即加载的策略。(当读取完xml配置文件,配置文件中所有的bean对象都已经创建完成了,实测)
    BeanFactory:
        它是springioc容器的顶层接口。
        特点是创建bean对象时,采用的是延迟加载的策略。(当真正要从容器获取bean对象时才创建,读完配置文件时不创建)
    单例对象可以用ApplicationContext,多例对象用BeanFactory,不过spring会帮我们处理,一般都用ApplicationContext,设置属性可以选择单例多例。
  • 用bean标签创建bean对象三种创建方式:
    1、通过调用默认构造函数来创建bean对象,默认情况下,在bean标签中写了class属性,spring就会调用默认构造函数创建对象,如果没有默认构造函数,则对象创建失败:
    <bean id=“唯一标示” class=“全限定类名”></bean>

2、静态工厂创建,项目中已经有一个创建对象的工厂类,其中有创建对象的静态方法可以使用:
<bean id=“唯一标示” class=“全限定类名(工厂类)” factory-method=“方法名”></bean>

3、实例工厂创建,项目中已经有一个创建对象的工厂类,其中有创建对象的非静态方法可以使用:

<bean id=“唯一标示” factory-bean=“工厂bean的id”  factory-method=“方法名”></bean>
  • bean对象的作用范围:
    可以通过一个配置属性来指定:scope属性: 比如 scope=“singleton”
    有几个值:
    singleton:单例的 (默认值,也最常用)
    prototype:多例的
    request:请求范围
    session:会话范围
    global-session:全局会话范围

  • Bean对象的生命周期:
    单例对象
    出生:容器创建,对象出生
    活着:只要容器在,对象就一直可用
    死亡:容器销毁,对象消亡
    多例对象
    出生:每次使用时,容器才会为我们创建对象
    活着:只要对象在使用过程中就一直活着
    死亡:spring不知道对象你什么时候用完,spring把这件事交给了java的gc:对象长时间不用,并且也没有其他对象引用时,java的垃圾回收器回收

1、2对象创建出来了,那么依赖关系要怎么构建呢,spring提供了依赖注入:

场景:展示层调用AccountServiceImpl(业务层)的saveAccount方法,这个方法中又调用AccountDao(持久层)类的保存账号方法,那这个时候AccountServiceImpl类中就需要引用到AccountDao对象,我们前面已经把这两个对象都用spring创建出来了,那么现在开始往AccountServiceImpl中依赖AccountDao对象,为了简单我们先用简单类型的属性代替AccountDao对象引入到AccountServiceImpl中:

1、构造函数注入:
使用constructor-arg标签,该标签是写在bean标签内部的子标签:
    标签的属性:
        type:指定要注入的参数在构造函数中的类型
        index:指定要注入的参数在构造函数中的索引位置
        name:指定要注入的参数在构造函数中的名称
        value:指定要注入数据内容,他只能指定基本类型数据和String类型数据
        ref:指定其他bean类型数据。写的是其他bean的id。其他bean指的是存在于spring容器中的bean。
例子:
<bean id=“accountService” class=“com.demo.service.impl.AccountServiceImpl”>
    <constructor-arg    name=“name”  value=“xc”></constructor-org>
    <constructor-arg    name=“age”  value=“27”></constructor-org>
    <constructor-arg    name=“birthday”  ref=“now”></constructor-org>
<bean/>
<bean id=“now” class=“java.util.Date”></bean>

这种方式需要AccountServiceImpl类中有带有这三个参数的构造函数,否则报错。
这时候在展示层通过spring获取的AccountServiceImpl对象其中的三个属性就已经有了上面设置的值,这感觉有点像是初始化对象赋值呢?不过好像确实是这样,因为是用构造函数注入的。

2、使用setter方法注入:(常用)
涉及的标签:property。也是要写在bean标签内部的子标签
标签属性:
    name:指定的是setter方法的名称。匹配的是类中setter方法set后面的部分:setAppName(),那么这里就取appName,首字母要小写。
    value:指定要注入数据内容,他只能指定基本类型数据和String类型数据
    ref:指定其他bean类型数据。写的是其他bean的id。其他bean指的是存在于spring容器中的bean。
    例子:
    <bean id=“accountService” class=“com.demo.service.impl.AccountServiceImpl”>
    <property    name=“name”  value=“xc”></property>
    <property    name=“age”  value=“27”></property>
    <property    name=“birthday”  ref=“now”></property>
    <bean/>

这种方式需要类中的属性有set方法,可以没有get方法,但是一定要有set方法.
用这种方式往AccountServiceImpl中引用AccountDao:

<bean id=“accountService” class=“com.demo.service.impl.AccountServiceImpl”>
<property name=“accountDao” ref=“accountDao”></constructor-org>
<bean/>
<bean id=“accountDao” class=“com.demo.dao.impl.AccountDaoImpl”><bean/>
这样写完,业务层和持久层的依赖关系就交给了spring来维护了。

  • 2.1使用p名称空间注入:它的本质仍然是需要类中提供set方法,同时在配置文件中要导入p名称空间:

<bean id=“accountService” class=“com.demo.service.impl.AccountServiceImpl” p:name=“张三”>
<bean/>

  • 2.2复杂类型注入:注入的方式采用set方法,注入的类型都是集合类型:
    注意:结构相同标签可以互换
          <!— 给数组注入数据—>
          <property    name=“myStrs” >
              <array>
                  <value>AAA</value>
                  <value>BBB</value>
                  <value>ccc</value>
              </array>
          </property>
          <!— 给list注入数据—>
          <property    name=“myList” >
              <list>
                  <value>AAA</value>
                  <value>BBB</value>
                  <value>ccc</value>
              </list>
          </property>
          <!— 给set注入数据—>
          <property    name=“mySet” >
              <set>
                  <value>AAA</value>
                  <value>BBB</value>
                  <value>ccc</value>
              </set>
          </property>
          <!— 给map注入数据—>
          <property    name=“myMap” >
              <map>
                  <entry key=“testA” value=“AAA”></value>
                  <entry key=“testB” value=“BBB”></value>
              </map>
          </property>
          <!— 给properties注入数据—>
          <property    name=“myProps” >
              <props>
                  <prop key=“testa”>AAA</value>
                  <prop key=“testB”>BBB</value>
              </props>
          </property>
      <bean/>
    
    
1.3用spring注解的方式再做一遍上面的工作:

和上面xml的目的都是为了降低耦合,只不过是形式不一样

 * 用于创建对象的:
 *
 * @Component :
 * 作用:就相当于在spring的xml配置文件中写了一个bean标签。
 * 属性:
 * value:用于指定bean的Id。当不写时,默认值是当前类名,首字母改小写。
 * 由此注解衍生的三个注解:
 * @Controller, 用于表现层
 * @Service, 用于业务层
 * @Repository 用于持久层
 * 他们的作用以及属性和@Component的作用是一样的。它们的出现时spring框架为我们提供更明确的语义话来指定不同层的bean对象。
 * <p>
 * 用于注入数据的:
 * @Autowired
 * 作用:自动按照类型注入。只要容器中有唯一的类型匹配,则可以直接注入成功。
 * 细节:当使用此注解注入时,set方法就可以省略了。
 * 属性:required :是否必须注入成功。取值true(默认值)/false。当取值是true时,没有匹配的对象就会报错。写不写无所谓,反正没有匹配到总会报错,只不过报错信息不一样。
 * 用于改变作用范围的:
 * 和生命周期相关的:
 */

@Component(value = "accountService")
public class AccountServiceImpl implements IAccountService {

    @Autowired(required = false)
    IAccountDao accountDao;

    @Override
    public void saveAccount() {
        accountDao.saveAccount();
    }
}

public class Client {

    public static void main(String[] args) {
        ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
        IAccountService accountService = ac.getBean("accountService",IAccountService.class);
        IAccountDao accountDao = ac.getBean("accountDao",IAccountDao.class);

        accountService.saveAccount();
    }
}
<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
         http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
         http://www.springframework.org/schema/context
         http://www.springframework.org/schema/context/spring-context-3.0.xsd">

    <!--告知spring创建容器时要扫描的包-->
    <context:component-scan base-package="com.ncz.nczupkeep.biz"></context:component-scan>

</beans>


相关文章

网友评论

      本文标题:spring ioc

      本文链接:https://www.haomeiwen.com/subject/qvoarqtx.html