Spring IOC

IOC是什么

  •  IOC:控制反转,是一种设计模式。
  • 一层含义是控制权的转移,由传统的在程序中控制依赖转移到由容器来控制。
  • 第二层是依赖注入:将相互依赖的对象分离,在Spring配置文件中描述他们的依赖关系,他们的依赖关系只在使用的时候才建立,简单来说就是不需要的NEW一个对象了。

BeanFactory

BeanFactory,以Factory结尾,表示它是一个工厂类(接口), 它负责生产和管理bean的一个工厂。在Spring中,BeanFactory是IOC容器的核心接口,它的职责包括:实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。

BeanFactory只是个接口,并不是IOC容器的具体实现,但是Spring容器给出了很多种实现,如 DefaultListableBeanFactory、XmlBeanFactory、ApplicationContext等,其中XmlBeanFactory就是常用的一个,该实现将以XML方式描述组成应用的对象及对象间的依赖关系。XmlBeanFactory类将持有此XML配置元数据,并用它来构建一个完全可配置的系统或应用。

 原始的BeanFactory无法支持spring的许多插件,如AOP功能、Web应用等。ApplicationContext接口,它由BeanFactory接口派生而来。现在一般使用ApplicationnContext,其不但包含了BeanFactory的作用,同时还进行更多的扩展

Note:BeanFactory和ApplicationContext创建Bean的区别

BeanFactory延时加载,在使用到某个Bean时才会进行实例化Bean
ApplicationConetxt在ApplicationContext对象创建时,会立即实例化单例Bean以及其依赖

 

<?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="userDao" class="com.lb.springioc.dao.UserDaoImpl"></bean>

    <bean id="userService" class="com.lb.springioc.service.UserServiceImpl">
        <property name="userDao" ref="userDao"></property>
    </bean>
</beans>

Bean加载原理

Bean实例化
BeanDefinition对应配置文件中的<bean>标签
BeanDefinitionReader读取配置文件所有的BeanDefinition
BeanDefinitionRegistry将Reader读取到的BeanDefinition放在容器中

 BeanDefinition

BeanDefinitionHolder就是持有对bean标签读取到的信息的对象

 BeanDefinitionReader

 BeanDefinitionRegistry

自实现的IOC

依赖

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

        <dependency>
            <groupId>dom4j</groupId>
            <artifactId>dom4j</artifactId>
            <version>1.6.1</version>
        </dependency>

实体类

@Data
public class BeanDefinition {
    private String id;
    private String className;
    private PropertyValues propertyValues;

    public BeanDefinition() {
        propertyValues = new PropertyValues();
    }
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class PropertyValue {
    private String name;
    private String ref;
    private String value;
}
public class PropertyValues implements Iterable<PropertyValue> {
    private List<PropertyValue> list;

    public PropertyValues() {
        list = new ArrayList<>();
    }

    public PropertyValues add(PropertyValue propertyValue) {
        for (int i = 0; i < list.size(); i++) {
            PropertyValue value = list.get(i);
            if (value.getName().equals(propertyValue.getName())) {
                list.set(i, propertyValue);
                return this;
            }
        }
        list.add(propertyValue);
        return this;
    }

    public PropertyValue[] getPropertyValues() {
        return list.toArray(new PropertyValue[0]);
    }

    public PropertyValue geTPropertyValue(String name) {
        for (int i = 0; i < list.size(); i++) {
            PropertyValue value = list.get(i);
            if (value.getName().equals(name)) {
                return value;
            }
        }
        return null;
    }

    public boolean isEmpty() {
        return list.isEmpty();
    }

    @Override
    public Iterator<PropertyValue> iterator() {
        return list.iterator();
    }
}

Reader & Registry

public interface BeanDefinitionReader {
    BeanDefinitionRegistry getRegistry();

    void loadResource(String location) throws Exception;
}
public class XmlBeanDefinitionReader implements BeanDefinitionReader {

    private BeanDefinitionRegistry registry;

    public XmlBeanDefinitionReader() {
        registry = new SimpleBeanDefinitionRegistry();
    }

    @Override
    public BeanDefinitionRegistry getRegistry() {
        return registry;
    }

    @Override
    public void loadResource(String location) throws Exception {
        SAXReader reader = new SAXReader();
        InputStream inputStream = XmlBeanDefinitionReader.class.getClassLoader().getResourceAsStream(location);
        Document document = reader.read(inputStream);
        Element rootElement = document.getRootElement();
        List<Element> beans = rootElement.elements("bean");

        for (Element bean : beans) {
            BeanDefinition beanDefinition = new BeanDefinition();
            String id = bean.attributeValue("id");
            beanDefinition.setId(id);
            beanDefinition.setClassName(bean.attributeValue("class"));
            PropertyValues values = new PropertyValues();
            List<Element> properties = bean.elements("property");
            for (Element property : properties) {
                PropertyValue value = new PropertyValue();
                value.setName(property.attributeValue("name"));
                value.setRef(property.attributeValue("ref"));
                value.setValue(property.attributeValue("value"));
                values.add(value);
            }
            beanDefinition.setPropertyValues(values);
            registry.registerBeanDefinition(id, beanDefinition);
        }
    }
}
public interface BeanDefinitionRegistry {
    void registerBeanDefinition(String beanName, BeanDefinition beanDefinition);

    void removeBeanDefinition(String beanName) throws Exception;

    BeanDefinition getBeanDefinition(String beanName);

    boolean containsBeanDefinition(String beanName);

    String[] getBeanDefinitionNames();

    int getBeanDefinitionCount();
}

public class SimpleBeanDefinitionRegistry implements BeanDefinitionRegistry {
    private Map<String, BeanDefinition> map = new HashMap<String, BeanDefinition>();


    @Override
    public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) {
        map.put(beanName, beanDefinition);
    }

    @Override
    public void removeBeanDefinition(String beanName) throws Exception {
        map.remove(beanName);
    }

    @Override
    public BeanDefinition getBeanDefinition(String beanName) {
        return map.get(beanName);
    }

    @Override
    public boolean containsBeanDefinition(String beanName) {
        return map.containsKey(beanName);
    }

    @Override
    public String[] getBeanDefinitionNames() {
        return map.keySet().toArray(new String[0]);
    }

    @Override
    public int getBeanDefinitionCount() {
        return map.size();
    }
}

BeanFacoty & ApplicationContext

/**
 * 提供BeanFactory的主要功能获取Bean
 */
public interface BeanFactory {

    Object getBean(String beanName) throws Exception;

    <T> T getBean(String beanName, Class<? extends T> clazz) throws Exception;
}

/**
 * 所有的子类对bean的创建都是非延时的
 */
public interface ApplicationContext extends BeanFactory {
    /**
     * 加载配置文件,并创建对象
     * @throws Exception
     */
    void refresh() throws Exception;
}

public abstract class AbstractApplicationContext implements ApplicationContext {
    protected Map<String, Object> singletonMaps = new HashMap<>();

    protected BeanDefinitionReader beanDefinitionReader;

    protected String configLocation;

    @Override
    public void refresh() throws Exception {
        beanDefinitionReader.loadResource(configLocation);

        //初始化所有的bean
        initializationBean();
    }

    private void initializationBean() throws Exception {
        BeanDefinitionRegistry registry = beanDefinitionReader.getRegistry();
        String[] beanDefinitionNames = registry.getBeanDefinitionNames();
        for (String beanDefinitionName : beanDefinitionNames) {
            BeanDefinition beanDefinition = registry.getBeanDefinition(beanDefinitionName);
            getBean(beanDefinition.getId());
        }
    }
}

public class ClassPathXmlApplicationContext extends AbstractApplicationContext {

    public ClassPathXmlApplicationContext(String location) {
        this.configLocation = location;
        this.beanDefinitionReader = new XmlBeanDefinitionReader();

        try {
            refresh();
        } catch (Exception e) {

        }
    }

    @Override
    public Object getBean(String beanName) throws Exception {
        Object obj = singletonMaps.get(beanName);
        if (obj != null) {
            return obj;
        }
        BeanDefinitionRegistry registry = beanDefinitionReader.getRegistry();
        BeanDefinition beanDefinition = registry.getBeanDefinition(beanName);
        String clazzName = beanDefinition.getClassName();
        Class<?> clazz = Class.forName(clazzName);
        Object bean = clazz.newInstance();

        PropertyValues propertyValues = beanDefinition.getPropertyValues();
        for (PropertyValue propertyValue : propertyValues) {
            //拼接set方法
            String name = propertyValue.getName();
            String setMethodName = StrUtil.filedName2SetMethodName(name);
            Method[] methods = clazz.getMethods();
            Method method = null;
            for (Method m : methods){
                if (m.getName().equals(setMethodName)){
                    method = m;
                    break;
                }
            }
            //反射创建对象
            String refStr = propertyValue.getRef();
            if (null != refStr && !"".equals(refStr)) {
                Object refObj = getBean(refStr);
                method.invoke(bean, refObj);
            }
            //value是赋值的
            String value = propertyValue.getValue();
            if (null != value && !"".equals(value)) {
                method.invoke(bean, value);
            }
        }
        singletonMaps.put(beanName, bean);
        return bean;
    }

    @Override
    public <T> T getBean(String beanName, Class<? extends T> clazz) throws Exception {
        Object obj = getBean(beanName);
        if (obj == null) return null;
        return clazz.cast(obj);
    }
}

测试

将上面的项目打包,测试项目引入其依赖

        <dependency>
            <groupId>com.test</groupId>
            <artifactId>mySpring</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>

测试代码:

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="userDao" class="springioc.dao.UserDaoImpl"></bean>

    <bean id="userService" class="springioc.service.UserServiceImpl">
        <property name="userDao" ref="userDao"></property>
    </bean>
</beans>
import com.lb.context.ClassPathXmlApplicationContext;
import springioc.dao.UserDao;
import springioc.service.UserService;

public class UserController {
    public static void main(String[] args) throws Exception{
        ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserDao userDao = classPathXmlApplicationContext.getBean("userDao", UserDao.class);
        UserService userService = classPathXmlApplicationContext.getBean("userService", UserService.class);
        System.out.println(userDao);
        System.out.println(userService);

        userService.add();
    }
}

测试结果:

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值