Spring基础(一)笔记----------IOC(控制反转)和DI(依赖注入)

 

一. 总概览:

 

二:Spring的核心包:

2.1:Spring的体系结构

 Spring-beans和srping-core提供控制反转和依赖注入

 Spring-Context上下文对象,基于beans和core

 Spring-spel是Spring提供的一个表达式

 

三. IOC(控制反转):

       3.1 概念:

将创建对象的过程交给Spring中的容器创建,而以前则是通过new关键字创建,创建对象的权限发生了改变。

       3.2 传统方式解决问题的过程:

  创建IAccountDao接口

public interface IAccountDao {
    void save();
}

            创建IAccountDaoImpl,模拟mysql数据库去存储实现IAccountDao类

public class IAccountDaoImpl implements IAccountDao {
    @Override
    public void save() {
        System.out.println("通过mysql保存一位用户");
    }
}

           创建IAccountDaoOracleImpl,模拟Oracle存储用户实现IAccountDao类

public class IAccountOracleDaoImpl implements IAccountDao {
    @Override
    public void save() {
        System.out.println("通过Oracle保存了用户!");
    }
}

           创建IAccountService接口,模拟业务层

public interface IAccountService {
    void saveAccount();
}

           创建IAccountServiceImpl实现业务接口。

public class AccountServiceImpl implements IAccountService {

    private IAccountDao accountDao = new IAccountDaoImpl();

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

           测试类:

public class AccountTest {
    @Test
    public void AccountTest(){
        IAccountService accountService = new IAccountServiceImpl();
        accountService.saveAccount();    // 输出 通过mysql保存用户
    }
}

传统方式创建对象,并调用对应的方法区实现相关的业务,不利于后期的维护,因为如果实现Oracle去保存用户,则实现类的dao层和实现类的业务层都需要更改代码。显然耦合性过高,而如何降低耦合性呢?

       3.3 通过反射方法实现自定义IOC容器

  在resources目录下创建bean.properties配置文件

# dao接口
accountDao=com.google.dao.Impl.IAccountDaoImpl
# accountDao=com.google.dao.Impl.IAccountOracleDaoImpl

# service接口
accountService=com.google.Service.Impl.IAccountServiceImpl

在创建一个BeanFactory工厂类(利用工厂模式进行解耦

import java.util.ResourceBundle;

public class BeanFactory {
    // 读取配置文件
    private static ResourceBundle bundle;
    static {
        // 加载配置文件的工具类
        bundle = ResourceBundle.getBundle("bean");
    }
    
    /**
     *
     * @param key   与bean.properties的key值保持一致,通过此参数去获取对应的实现类
     * @param clazz 传入字节码文件,在创建对象时,则无需强制装换
     * @param <T>   泛型,可以拓展更多的类使用该工厂。
     * @return
     */
    public static <T> T getBundle(String key,Class<T> clazz){
        try {
            // 根据key,获取配置文件的类全名
            String className = bundle.getString(key);
            // 创建对象
            return (T)Class.forName(className).newInstance();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }


}

 修改IAccountServiceImpl中的代码

public class AccountServiceImpl implements IAccountService {
    // private IAccountDao accountDao = new IAccountDaoImpl();

    // 通过工厂来创建对象
    private IAccountDao accountDao = BeanFactory.getBundle("accountDao",IAccountDao.class);
    
    @Override
    public void save() {
        accountDao.saveAccount();
    }
}

            测试类:

public class AccountTest {
    @Test
    public void save(){
        IAccountService accountService = BeanFactory.getBundle("accountService",IAccountService.class);
        accountService.saveAccount();  // 输出 通过mysql保存用户
    }
}

以上代码虽然比传统的多,但是如果需要更换数据库存储用户,如通过Oracle去存储用户,则只要修改配置文件即可:

# dao接口
# accountDao=com.google.dao.Impl.IAccountDaoImpl
accountDao=com.google.dao.Impl.IAccountOracleDaoImpl

# service接口
accountService=com.google.Service.Impl.IAccountServiceImpl

尽管以上代码只能降低了耦合性,便于后期维护,但还是存在很多问题,因此接下来将用Spring实现IOC实现业务

       3.4 通过xml方式配置IOC容器

           添加依赖:spring-context

          创建Account对象:

          创建bean.xml配置文件

          测试类

当然,以上只是IOC的入门,接下来将记录一些常用的bean配置里面的参数

其中scope设置bean的作用范围,如:

         scope为singleton(默认值),在测试类中的代码

         测试结果:两者的地址为一样,说明创建对个对象,实际上就是同一个对象。如图:

      而如果将scope改为prorotype,则更改配置文件:

      测试结果为,两个对象的地址不一致,说明创建了两个对象:如果

   而lazy-init的默认值为false,且必须为scope=singleton才能使用,默认的时候测试代码及其效果

 如果将其设置为true后:

再次测试将不会输出任何语句,只要将代码改为,才会输出:

 

3.5 通过容器创建对象的方式(3种):

      1. 默认无参构造器,上面所演示的代码,即通过无参构造

      2. 通过类的静态方法:

          创建普通类:

public class AccountStatic {
    public AccountStatic(){
        System.out.println("无参构造数被调用");
    }

    public static AccountStatic accountStatic(){
        System.out.println("通过静态方法创建对象");
        return new AccountStatic();
    }
}

          创建配置文件:关键点factory-method,如果没有将会通过默认无参构造器创建对象

         测试类

    @Test
    public void getObjectByStatic(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");
        // 测试输出:通过静态方法创建对象
        //           无参构造数被调用
        AccountStatic account = applicationContext.getBean("accountStatic", AccountStatic.class);
    }

      3. 调用类的实例方法

          普通类

public class Account {
    // 创建实例方法
    public Account getAccount(){
        System.out.println("通过实例方法创建对象");
        return new Account();
    }
}

          创建配置文件:先创建工厂对象,再通过工厂对象进行调用创建对象

    <!--通过创建工厂对象-->
    <bean id="factory" class="com.google.pojo.Account" />
    <!--再通过工厂对象调用-->
    <bean id="account" factory-bean="factory" factory-method="getAccount" />

          测试类:

public class AccountTest {
    private ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");

    @Test
    public void accountTest(){
        // 输出 创建了Account对象!
        Account account = applicationContext.getBean("account", Account.class);
    }

 

四:依赖注入:就是在创建对象之后,给对象属性赋值。

4.1  带参构造函数注入:即通过有参构造函数创建对象

    4.1.1: 创建普通类

public class Account {
    private String name;

    public Account(String name) {
        this.name = name;
    }

    public Account() {
    }
    

    @Override
    public String toString() {
        return "Account{" +
                "name='" + name + '\'' +
                '}';
    }
    
}

            4.1.2 创建配置:name与参数名称一致,value代表赋值

    <!--constructor-arg 通过构造函数创建对象、给对象属性赋值
            index       表示第几个构造函数参数,从0开始
            name        构造函数参数名称,如:public Person(int id123) 中的id123
            type        参数类型
            value       参数值 (直接给构造函数参数赋值。)
            ref         表示引用ioc容器中的对象。(重点)
                        ref="str" 表示引入容器中bean的id是str的对象,注入方法参数。
    -->
    <bean id="account" class="com.google.pojo.Account">
        <!--name与参数名称一致,value代表赋值-->
        <constructor-arg name="name" value="tom" />
    </bean>

3.1.3 测试类:

       4.2  set方式注入:即通过有set方式创建对象

4.2.1,创建普通类

public class Account {
    private String name;

    public Account(String name) {
        this.name = name;
    }

    public Account() {
    }
    
    // 创建Set方法
    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Account{" +
                "name='" + name + '\'' +
                '}';
    }
    
}

4.2.2,创建配置:其中name与setXxx中的Xxx保持一致并且首字母小写

<!--其中name与setXxx中的Xxx保持一致并且首字母小写-->
    <bean id="account" class="com.google.pojo.Account">
        <property name="name" value="jerry" />
    </bean>

4.2.3:测试类省略

       4.3  P名称空间注入:实质还是通过set方式注入

           4.3.3:配置

     <!--其中name与setXxx中的Xxx保持一致-->
    <bean id="account" class="com.google.pojo.Account" p:name="james" />

       4.4  集合类型注入:可以百度简单了解下。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值