spring个人理解

spring控制反转(IoC)实现过程

提示:下文中所有地方提到的实例对象bean对象 等价于 accountService = new AccountServiceImp();

一、示例代码准备

  • POJO
    • Account
package com.roy.demo;
import java.io.Serializable;
//pojo
public class Account implements Serializable {
    private Integer id;
    private String name;
    private Float money;
   	//无参构造......略
 	//有参构造......略
	//getter()/setter()/toStirng()......略
}
  • service层接口
    • AccountService
package com.roy.demo.service;
import com.roy.demo.Account;
import java.util.List;
//service层的接口
public interface AccountService {
    List<Account> findAllAccount();
}
  • service层接口的实现类
    • AccountServiceImpl
package com.roy.demo.service.impl;
import com.roy.demo.Account;
import com.roy.demo.service.AccountService;
import java.util.List;
//接口的实现类
public class AccountServiceImpl implements AccountService {
    @Override
    public List<Account> findAllAccount() {
    //dao层代码略
        return accountDao.findAllAccount();
    }

业务场景描述:

  1. 客户端发送请求——>服务端(WEB)接受请求并调用servcie及dao实现请求
  2. web层要调用service的功能方法,必须要拿到service的实例对象,即:AccountService accountService = new AccountServiceImpl();
  3. 使用accountService.findAllAccount();才可以调用service层方法

二、实现业务的原始方案

  • web层调用service层实现查询所有账户功能,代码实现:
//web层调用service层
public class AccountServlet {
 	private AccountService *accountService* = new AccountServiceImpl();
    public void findAllAccount() {
        accountService.findAllAccount();
    }
}

原始方案存在的问题:

  1. 真实项目中service层中不可能只有AccountService一个接口实现,可能还会有:UserService、OrderService等。
  2. web层要想实现所有的功能就必须new AccountServiceImpl(),这就使web层对service层的代码产生了编译期依赖,因为如果没有accountService,web就完成不了功能。
  • 下面的改进方案就帮我们解决了编译期依赖

三、改进方案

改进方案一:

  • 使用工厂模式和反射机制,从工厂中获取一个Bean对象
package com.roy.demo;
public class BeanFactory {
    private static Object accountService;
    public static Object getBean() {
        try {
            Class<?> clazz = Class.forName("com.roy.service.impl.AccountServiceImpl");
            accountService = clazz.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return accountService;
    }
}

当存在上面一个BeanFactory的类时,我们只需要提供一个com.roy.service.impl.AccountServiceImpl就可以通过BeanFactory.getBean();拿到sercive的对象,而不需要我们自己去new;

仍然存在的问题:

  1. 我们仍需自己手写com.roy.service.impl.AccountServiceImpl,带来了硬编码问题
  • 改进方案二解决了硬编码问题

改进方案二:

  • 使用配置文件beans.properties解决硬编码问题
//   	格式:[key=value]
accountService=com.roy.service.impl.AccountServiceImpl
userService=com.roy.service.impl.AccountServiceImpl
orderService=com.roy.service.impl.AccountServiceImpl
  • BeanFactory改进代码
package com.roy.demo;
import java.io.InputStream;
import java.util.Properties;
import java.util.PropertyResourceBundle;

public class BeanFactory {
    public static Object getBean(String key) throws Exception{
//        读取配置文件
        InputStream is = BeanFactory.class.getClassLoader().getResourceAsStream("beans.properties");
        Properties properties = new Properties();
        properties.load(is);
        // getProperty("userService")就可以得到className = "com.roy.service.impl.AccountServiceImpl"
        String className  = properties.getProperty(key);
        Class<?> clazz = Class.forName(className);
        // 得到 UserService的实例对象 bean
        Object bean = clazz.newInstance();
        return bean;
    }
}
  • 此时获取bean对象的方式变为传入一个key:AccountServcie accountService = BeanFactory.getBean("accountService"); 其它bean对象获取方式相同
  • 改进方案二已经又了springIoC(控制反转的雏形)

spring 控制反转实现分析:

  • springIoC可以理解成一个容器,它帮我们管理和创建我们所需要的依赖对象,比如:上面的accountService、userService等等。简单的画个图理解一下:
    Spring控制反转的工作方式

四、Spring控制反转代码完善

package com.roy.demo;

import java.io.InputStream;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

public class BeanFactory {
//    创建一个‘容器’存放实例对象【可以想象成就是一个Spring的IoC‘容器’】
    private static Map<String,Object> beans = new HashMap<String, Object>();
    static {
//        读取配置文件
        try {
            InputStream is = BeanFactory.class.getClassLoader().getResourceAsStream("beans.properties");
            Properties properties = new Properties();
            properties.load(is);
            Enumeration<?> enumeration = properties.propertyNames();
//            循环每个key
            if (enumeration.hasMoreElements()) {
                String key = (String) enumeration.nextElement();
//                获取每个key的value得到的就是全限定类名
                String className = properties.getProperty(key);
                Class<?> clazz = Class.forName(className);
//                通过反射的到className对应的实例对象
                Object bean = clazz.newInstance();
//                将对象丢到map‘容器’中
                beans.put(key,bean);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } 
    }
    public static Object getBean(String key) {
//        从map‘容器’中找到key对应的实例对象,并返回给调用者
        return beans.get(key);
    }
}

五、总结

  • 控制反转的理解:
    1. Spring将想象成一个容器,IoC控制反转就是将我们主动创建对象反转成被动接受【Spring容器帮我们创建了】
    2. 自始至终我们都要提供accountService=com.roy.service.impl.AccountServiceImpl,Spring IoC的实现原理使用到了反射机制,Class.forName("com.roy.service.impl.AccountServiceImpl");
    3. 之前我们自己写的代码是从配置文件中获取com.roy.service.impl.AccountServiceImpl
    4. 要想spring帮我们管理和创建实例对象,也是需要告诉springcom.roy.service.impl.AccountServiceImpl;告诉的方式就是在spring的核心配置文件中使用标签:<bean id="accountService" class="com.roy.service.impl.AccountServiceImpl"/>
      END
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值