Spring IOC

一、什么是Spring IOC?

1、IOC不是一种技术而是一种设计思想,Ioc意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制。
2、在传统Java SE程序设计,我们直接在对象内部通过new进行创建对象,IoC是有专门一个容器来创建这些对象,即由Ioc容器来控制对 象的创建;
3、何为控制反转?
传统应用程序是由我们自己在对象中主动控制去直接获取依赖对象,也就是正转;而反转则是由容器来帮忙创建及注入依赖对象;
因为由容器帮我们查找及注入依赖对象,对象只是被动的接受依赖对象,所以是反转;哪些方面反转了?依赖对象的获取被反转了。

二、IOC能做什么

1.IOC控制反转
IoC(Inversion of Control,控制反转)。这是spring的核心,贯穿始终。所谓IoC,对于spring框架来说,就是由spring来负责控制对象的生命周期和对象间的关系。而Spring提供了IOC容器来帮我们生成所需要的对象。也就是说在我们原先的对象中有用到其他对象的地方Spring会帮我们来注入。不用我们再去考虑这些问题。
2.DI(依赖注入)
spring提供了三种方式来依赖注入,有构造方法注入,setter方法注入以及接口注入。使用构造方法注入需要注意的一点就是要避免循环依赖。所谓的循环依赖指的就是在A对象的构造方法中Spring要注入B,而在B对象中Spring要注入A。这个时候会形成一个闭环因为Spring不知道该先注入哪一个接着会抛出异常。而Spring建议的处理方式是说如果遇到这种情况的话就改用Setter方式注入。
而spring就是通过反射来实现注入的。
理解DI的关键是:“谁依赖谁,为什么需要依赖,谁注入谁,注入了什么”。
谁依赖谁:应用程序依赖于IoC容器;
为什么需要依赖:应用程序需要IoC容器来提供对象需要的外部资源;
谁注入谁:IoC容器注入应用程序某个对象,应用程序依赖的对象;
注入了什么:注入某个对象所需要的外部资源(包括对象、资源、常量数据)

三、底层原理

ioc的底层原理是工厂设计模式即通过工厂获取实例对象,实现代码的解耦,好了,话不多说,通过实例来理解:

首先创建一个实体类User(使用lombok实现实体类的方法)


@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class User {
    private String username;
    private String password;
}

创建接口UserMapper和类UserMapperImpl

public interface UserMapper {

    User selectByUser(User user);
    Integer addUser(User user);
}



public class UserMapperImpl implements UserMapper{
    @Override
    public User selectByUser(User user) {
        System.out.println("select * from user where username="+user.getUsername()+"and password = "+user.getPassword());
        return user;
    }

    @Override
    public Integer addUser(User user) {
        System.out.println("insert into user(username,password) values("+user+")");
        return 1;
    }
}

创建接口UserService

public interface UserService {

    Boolean login(User user);
    Boolean register(User user);
}

在未使用spring之前,我们书写类UserServiceImpl时,如下:

public class UserServiceImpl implements UserService{
    private UserMapper userMapper = new UserMapperImpl();
    
    @Override
    public Boolean login(User user) {
        User usr = userMapper.selectByUser(user);
        return usr == null;
    }

    @Override
    public Boolean register(User user) {
        Integer line = userMapper.addUser(user);
        return line>0;
    }
}

此时使用new创建对象,是硬编码,不利于代码维护且耦合性高

当我们使用工厂对象时:

1、创建配置文件:applicationContext.properties

userService=cn.kgc.spring.basic.UserServiceImpl
userMapper=cn.kgc.spring.basic.UserMapperImpl

2、创建工厂对象:BeanFactory

/**
 *工厂创建对象如何解耦
 * 存在原因:  使用 new关键词创建对象
 *
 *创建对象的方式:
 * 1.   new 调用构造方法
 * 2.  反射
 *      1.获取类对象  Class  clazz
 *       获取类对象的方式:
 *          1. 类名.class
 *          2. Class.forName("全类名")  推荐   更灵活
 *          3.对象.getClass()
 *
 *          配合使用   配置文件 properties   实现进一步的解耦
 */
public class BeanFactory {

    private static ResourceBundle rb;
    static {
        rb=ResourceBundle.getBundle("applicationContext");
        String userService = rb.getString("userService");
    }
    public static UserService getUserServiceImpl(){
        UserService userService=null;
        try {
            // 类的全类名 需要读取配置文件
            Class<?> clazz = Class.forName(rb.getString("userService"));
            userService = (UserService)clazz.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return userService;
    }

    public static UserMapper getUserMapperImpl(){
        UserMapper userMapper=null;
        try {
            Class<?> clazz = Class.forName(rb.getString("userMapper"));
            userMapper = (UserMapper)clazz.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return userMapper;
    }
}

此时的UserServiceImpl可以改写为:

public class UserServiceImpl implements UserService{
    private UserMapper userMapper = BeanFactory.getUserMapperImpl();

    @Override
    public Boolean login(User user) {
        User usr = userMapper.selectByUser(user);
        return usr == null;
    }

    @Override
    public Boolean register(User user) {
        Integer line = userMapper.addUser(user);
        return line>0;
    }
}

进一步,将BeanFactory改写:创建NewBeanFactory

public class NewBeanFactory {
    private static ResourceBundle rb;
    static {
        // 加载配置文件
        rb=ResourceBundle.getBundle("applicationContext");
    }
    public static Object getBean(String key){
        Object obj = null;
        try {
            // 类的全类名 需要读取配置文件
            Class<?> clazz = Class.forName(rb.getString(key));
            obj = clazz.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return obj;
    }

    // 泛型   方法上 使用泛型
    public static <T> T getBean(String key,Class<T> tClass){
        T cast = null;
        try {
            // 类的全类名 需要读取配置文件
            Class<?> clazz = Class.forName(rb.getString(key));
            Object obj  = clazz.newInstance();
            cast = tClass.cast(obj);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return cast;
    }
}

此时的UserServiceImpl可以改写为:

public class UserServiceImpl implements UserService{

    private UserMapper userMapper = (UserMapper)NewBeanFactory.getBean("userMapper");
    @Override
    public Boolean login(User user) {
        User usr = userMapper.selectByUser(user);
        return usr == null;
    }

    @Override
    public Boolean register(User user) {
        Integer line = userMapper.addUser(user);
        return line>0;
    }
}

看到这里,相信你对oc的底层原理已经有了初步的认识,接下来用Spring IOC

1、引入依赖

<dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <version>1.18.24</version>
    </dependency>

2、创建配置文件:applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--    使用标签声明 需要托管的对象-->
    <bean id="userMapper" class="cn.kgc.spring.basic.UserMapperImpl"></bean>

    <bean id="userMapper2" class="cn.kgc.spring.basic.UserMapperImpl2"></bean>
    <!--
            项目中   entity包装的类  一般不会纳入spring容器的管理     项目中的组件(  controller  service  mapper  ) 会放入容器管理
            原因: 实体类对应是数据库中的表   实体类的重要作用是用于封装持久化层的数据  持久层框架 会自动完成对象的创建和数据的封装
            所以 一般在项目中不会将 实体类放入spring容器
    -->
    <bean id="user" class="cn.kgc.spring.basic.User"></bean>
</beans>

3、创建test文件:TestSpring

@Test
    public void test1(){
        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationComtext.xml");

        //  ac 类似  NewBeanFactory

        UserMapper userMapper = (UserMapper)ac.getBean("userMapper");
        User user = new User("tom", "123");

        userMapper.addUser(user);
        userMapper.selectByUser(user);
    }

 public void test2(){  //  如何通过spring容器获取指定对象

        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");

        //  ac 类似  NewBeanFactory
        // 根据 class 类型获取对象   前提:  配置文件中只能有一个指定类型的对象
        UserMapper userMapper = ac.getBean(UserMapper.class);

        User user = new User("tom", "1234",null);

        userMapper.addUser(user);
        userMapper.selectByUser(user);

    }


@Test
    public void test3(){  //  如何通过spring容器获取指定对象

        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");

        // 获取容器中管理bean的个数
        int beanDefinitionCount = ac.getBeanDefinitionCount();
        System.out.println("beanDefinitionCount = " + beanDefinitionCount);

        // 获取配置文件中所有bean标签中的id 值
        String[] beanDefinitionNames = ac.getBeanDefinitionNames();
        for (String beanDefinitionName : beanDefinitionNames) {
            System.out.println("beanDefinitionName = " + beanDefinitionName);
        }

        String[] beanNamesForType = ac.getBeanNamesForType(UserMapper.class);
        for (String s : beanNamesForType) {
            System.out.println("s = " + s);
        }

        boolean b = ac.containsBean("usr");
        System.out.println("user = " + b);
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值