Spring IoC与Bean管理

Spring IoC与Bean管理

Spring快速入门

IoC控制反转

  • IoC控制反转,全称Inverse of Control,是一种设计理念
  • 由代理人来创建与管理对象,消费者通过代理人来获取对象
  • IoC的目的是降低对象之间直接耦合
  • 加入IoC容器将对象统一管理,让对象关联变为弱耦合

DI依赖注入

  • IoC是设计理念,是现代程序设计遵循的标准,是宏观目标
  • DI(Dependency Injection)是具体技术实现,是微观实现
  • DI在Java中利用反射技术实现对象注入(Injection)

Spring

Spring的含义

  • Spring可从狭义与广义俩个角度看待
  • 狭义的Spring是指Spring框架(Spring Framework)
  • 广义的Spring是指Spring生态体系

狭义的Spring

  • Spring框架是企业开发复杂性的一站式解决方案
  • Spring框架的核心是IoC容器与AOP面向切面变成
  • Spring IoC负责创建与管理系统对象,并在此基础上扩展功能

传统开发方式

  • 对象直接引用导致对象硬性关联,程序难以扩展维护

Spring IoC

  • IoC容器是Spring生态的地基用于统一创建与管理对象依赖

在这里插入图片描述

Spring IoC容器职责

  • 对象的控制器交由第三方统一管理(IoC控制反转)
  • 利用Java反射技术实现运行时对象创建与关联(DI依赖注入)
  • 基于配置提高应用程序的可维护性与扩展性

代码示例:

需要引入的依赖

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.3.1</version>
</dependency>

Apple.java

package com.imooc.spring.ioc.entity;

/**
 * @author CubeMonkey
 * @create 2020-11-27 23:57
 */
public class Apple {
    private String title;
    private String color;
    private String origin;

    public Apple() {
    }

    public Apple(String title, String color, String origin) {
        this.title = title;
        this.color = color;
        this.origin = origin;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    public String getOrigin() {
        return origin;
    }

    public void setOrigin(String origin) {
        this.origin = origin;
    }
}

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
        https://www.springframework.org/schema/beans/spring-beans.xsd">
    <!-- 在IoC容器启动时,自动由Spring实例化Apple对象,取名sweetApple放入到容器中-->
    <bean id="sweetApple" class="com.imooc.spring.ioc.entity.Apple">
        <property name="title" value="红富士"></property>
        <property name="origin" value="欧洲"></property>
        <property name="color" value="红色"></property>
    </bean>
    <bean id="sourApple" class="com.imooc.spring.ioc.entity.Apple">
        <property name="title" value="青苹果"></property>
        <property name="origin" value="中亚"></property>
        <property name="color" value="绿色"></property>
    </bean>
    <bean id="softApple" class="com.imooc.spring.ioc.entity.Apple">
        <property name="title" value="金帅"></property>
        <property name="origin" value="中国"></property>
        <property name="color" value="金色"></property>
    </bean>
    <bean id="rdApple" class="com.imooc.spring.ioc.entity.Apple">
        <property name="title" value="蛇果"></property>
        <property name="origin" value="美国"></property>
        <property name="color" value="红色"></property>
    </bean>


    <bean id="lily" class="com.imooc.spring.ioc.entity.Child">
        <property name="name" value="莉莉"></property>
        <property name="apple" ref="softApple"></property>
    </bean>
    <bean id="andy" class="com.imooc.spring.ioc.entity.Child">
        <property name="name" value="安迪"></property>
        <property name="apple" ref="rdApple"></property>
    </bean>
    <bean id="luna" class="com.imooc.spring.ioc.entity.Child">
        <property name="name" value="露娜"></property>
        <property name="apple" ref="sweetApple"></property>
    </bean>
</beans>

SpringApplication.java

package com.imooc.spring.ioc;

import com.imooc.spring.ioc.entity.Apple;
import com.imooc.spring.ioc.entity.Child;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @author CubeMonkey
 * @create 2020-11-30 16:14
 */
public class SpringApplication {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
        Apple sweetApple = context.getBean("sweetApple", Apple.class);
        System.out.println(sweetApple.getTitle());
        //从Ioc容器中提取beanId = lily的对象
        Child lily = context.getBean("lily", Child.class);
        lily.eat();
        Child andy = context.getBean("andy", Child.class);
        andy.eat();
        Child luna = context.getBean("luna", Child.class);
        luna.eat();
    }

}

XML管理对象(Bean)

三种配置方式

1. 基于XML配置Bean
实例化Bean的三种方式
  • 基于构造方法对象实例化

    核心代码:

    applicationContext.xml

    <bean id="apple2" class="com.imooc.spring.ioc.entity.Apple">
        <constructor-arg name="title" value="红富士"></constructor-arg>
        <constructor-arg name="color" value="红色"></constructor-arg>
        <constructor-arg name="origin" value="欧洲"></constructor-arg>
    </bean>
    
  • 基于静态工厂实例化

    核心代码:

    applicationContext.xml

    <!--利用静态工厂获取对象-->
    <bean id="apple4" class="com.imooc.spring.ioc.factory.AppleStaticFactory" factory-method="createSweetApple"></bean>
    
    

    ​ AppleStaticFactory.java

    package com.imooc.spring.ioc.factory;
    
    import com.imooc.spring.ioc.entity.Apple;
    
    /**
     * 静态工厂通过静态方法创建对象,隐藏创建对象的细节
     * @author CubeMonkey
     * @create 2020-12-01 18:50
     */
    public class AppleStaticFactory {
        public static Apple createSweetApple(){
            //logger.info("")
            Apple apple = new Apple();
            apple.setTitle("红富士");
            apple.setOrigin("欧洲");
            apple.setColor("红色");
            return apple;
        }
    }
    
    
  • 基于工厂实例方法实例化

    核心代码:

    applicationContext.xml

    <!--利用工厂实例方法获取对象-->
        <bean id="factoryInstance" class="com.imooc.spring.ioc.factory.AppleFactoryInstance"></bean>
            <bean id="apple5" factory-bean="factoryInstance" factory-method="createSweetApple"></bean>
    

    AppleFactoryInstance.java

    package com.imooc.spring.ioc.factory;
    
    import com.imooc.spring.ioc.entity.Apple;
    
    /**
     * 工厂实例方法创建对象是指IoC容器对工厂类进行实例化并调用对应的实例方法创建对象的过程
     * @author CubeMonkey
     * @create 2020-12-01 18:56
     */
    public class AppleFactoryInstance {
        public Apple createSweetApple(){
            Apple apple = new Apple();
            apple.setTitle("红富士");
            apple.setOrigin("欧洲");
            apple.setColor("红色");
            return apple;
        }
    }
    
    
2. 基于注解配置Bean
3. 基于Java代码配置Bean

从IoC容器获取bean

方法:

Apple apple4 = context.getBean("apple4", Apple.class);//推荐
System.out.println(apple4.getTitle());
Apple apple3 = (Apple)context.getBean("apple3");
System.out.println(apple3.getTitle());

id与name属性相同点

  • bean id 与name都是设置对象在IoC容器中唯一标识
  • 两者在同一配置文件中都不允许出现重复
  • 两者允许在多个配置文件中出现重复,新对象覆盖旧对象

id与name属性区别

  • id要求更为严格,一次只能定义一个对象标识(推荐)
  • name更为宽松,一次允许定义多个对象标识
  • tips:id与name的命名有意义,按驼峰命名书写

路径表达式

加载单个配置文件

ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");

加载多配置文件

String[] configLocations = new String[]{"classpath:applicationContext.xml", {"classpath:applicationContext-1.xml"}};
ApplicationContext context = new ClassPathXmlApplicationContext(configLocations)

路径表达式说明

表达式实例说明
classpath:config.xml扫描classpath根路径(不包含jar)的config.xml
classpath:com/imooc/config.xml扫描classpath下(不包含jar)com.imooc包中的config.xml
classpath*:com/imooc/config.xml扫描classpath下(包含jar)com.imooc包中的config.xml
classpath:config-*.xml扫描classpath根路径下所有以config-开头的XML文件
classpath:com/**/config.xml扫描com包下(包含任何子包)的config.xml
file:c/config.xml扫描c盘根路径config.xml

依赖注入

对象依赖注入

  • 依赖注入是指运行时将容器内对象利用反射赋给其他对象的操作

  • 基于setter方法注入对象

    <bean name="sweetApple" class="com.imooc.spring.ioc.entity.Apple">
        <!-- IoC容器自动利用反射机制运行时调用setXxx方法为属性赋值-->
        <property name="title" value="红富士"></property>
        <property name="color" value="红色"></property>
        <property name="origin" value="欧洲"></property>
        <property name="price" value="123"></property>
    </bean>
    <bean name="lily" class="com.imooc.spring.ioc.entity.Child">
        <property name="name" value="莉莉"></property>
        <!--利用ref注入依赖对象-->
        <property name="apple" ref="sweetApple"></property>
    </bean>
    
  • 基于构造方法注入对象

    <bean id="sourApple" class="com.imooc.spring.ioc.entity.Apple">
        <property name="title" value="青苹果"></property>
        <property name="color" value="绿色"></property>
        <property name="origin" value="中亚"></property>
        <property name="price" value="9.8"></property>
        </bean>
        <bean id="andy" class="com.imooc.spring.ioc.entity.Child">
            <constructor-arg name="name" value="安迪"></constructor-arg>
            <constructor-arg name="apple" ref="sourApple"></constructor-arg>
            </bean>
    

集合依赖注入

注入List
<bean id = "..." class = "...">
	<property name="someList">
    	<list>
        	<value>具体值</value>
            <ref bean="beanId"></ref> 
        </list>
    </property>
</bean>
注入Set
<bean id = "..." class="...">
	<property name="someSet">
    	<set>
        	<value>具体值</value>
            <ref bean="beanId"></ref>
        </set>
    </property>
</bean>
注入Map
<bean id="..." class="...">
	<property name="someMap">
    	<map>
        	<entry key="k1" value="v1"></entry>
            <entry key="k2" value-ref="beanId"></entry>
        </map>
    </property>
</bean>
注入Properties
<bean id="..." class="...">
	<properties name="someProperties">
    	<props>
        	<prop key="k1">v1</prop>
            <prop key="k2">v2</prop>
        </props>
   	</properties>
</bean>

查看容器内对象

String[] beanNames = context.getBeanDefinitionNames();

bean scope属性

  • bean scope属性用于决定对象何时被创建与作用范围
  • bean scope配置将影响容器内对象的数量
  • bean scope默认值singleton(单例),指全局共享同一个对象实例

bean scope属性清单

scope属性说明
singleton单例(默认值),每一个容器有且只有唯一的实例,实例被全局共享
prototype多例,每次使用时都是创建一个实例
requestweb环境下,每一次独立请求存在唯一实例
sessionweb环境下,每一个session存在有唯一实例
applicaitonweb环境下,每一个ServletContext存在唯一实例
websocket每一次WebSocket连接中存在唯一实例

singleton与prototype对比

singletonprototype
对象数量全局唯一存在多个
实例化时机IoC容器启动时getBean()或对象注入时
线程安全问题存在不存在
执行效率

bean生命周期

在这里插入图片描述

Ioc容器极简实现

示例代码:

package com.imooc.spring.ioc.context;

import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;

import java.io.File;
import java.lang.reflect.Method;
import java.net.URLDecoder;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;

/**
 * @author Rex
 * @create 2020-12-31 16:08
 */
public class ClassPathXmlApplicationContext implements  ApplicationContext{

    private Map iocContainer = new HashMap();

    public ClassPathXmlApplicationContext(){
        try {
            String filePath = this.getClass().getResource("/applicationContext.xml").getPath();
            filePath = new URLDecoder().decode(filePath, "utf-8");
            SAXReader reader = new SAXReader();
            Document document = reader.read(new File(filePath));
            List<Node> nodes = document.getRootElement().selectNodes("bean");
            for (Node node : nodes) {
                Element ele = (Element) node;
                String id = ele.attributeValue("id");
                String className = ele.attributeValue("class");
                Class<?> c = Class.forName(className);
                Object obj = c.newInstance();
                List<Node> properties = ele.selectNodes("property");
                for (Node p : properties) {
                    Element property = (Element) p;
                    String propName = property.attributeValue("name");
                    String propValue = property.attributeValue("value");

                    String setMethodName = "set"+propName.substring(0, 1).toUpperCase() + propName.substring(1);
                    System.out.println("准备执行"+setMethodName+"方法注入数据");
                    Method setMethod = c.getMethod(setMethodName, String.class);
                    setMethod.invoke(obj, propValue);
                }
                iocContainer.put(id, obj);
            }
            System.out.println(iocContainer);
            System.out.println("IOC容器初始化完毕");

        }catch (Exception e){
            e.printStackTrace();
        }
    }

    @Override
    public Object getBean(String beanId) {
        return iocContainer.get(beanId);
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Rex·Lin

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值