spring ioc

2019-01-10  本文已影响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,设置属性可以选择单例多例。

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

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

<bean id=“唯一标示” factory-bean=“工厂bean的id”  factory-method=“方法名”></bean>
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来维护了。

<bean id=“accountService” class=“com.demo.service.impl.AccountServiceImpl” p:name=“张三”>
<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>


上一篇 下一篇

猜你喜欢

热点阅读