Spring之IoC

Spring

Spring框架两大核心机制

  • IoC (控制翻转) / DI (依赖注入)
  • AOP (面向切面编程)

企业级开发框架,是软件设计层面的框架,优势在于可以将应用程序进行分层

MVC :Struts2 、Spring MVC

ORMapping : Hibernate、MyBatis、Spring Data

image-20200615165841634

优点:

  1. 容易与第三方框架整合
  2. 集中管理

IoC

入门

创建对象由IoC容器创建。

步骤:

  1. 创建maven项目,添加pom依赖
<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.1.3.RELEASE</version>
    </dependency>
    
    <!--        简化实体类代码开发 @Data 自动生成 get、set方法-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.12</version>
        </dependency>
</dependencies>
  • 创建实体类

传统方式:手动 new 方式创建对象

IoC方式:在配置文件中添加管理对象,xml格式自定义文件名,resources下

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

    <bean id="student" class="com.item.Student" >
        <property name="id" value="1" />
        <property name="name" value="张三" />
        <property name="age" value="12" />
    </bean>

</beans>
//加载配置文件
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("iocconfig.xml");
Object student = applicationContext.getBean("student");
System.out.println(student);

配置文件

通过配置Bean标签进行管理

  • id: 对象名

  • class : 对象模版类 必须有无参构造,通过反射机制创建对象, 反射机制是盗用无参构造创建

  • property :完成属性赋值

    • name : 属性名
    • value : 属性值 String 直接赋值,其他的引用类型,不能通过value赋值,
    • ref : 将IoC中的另外一个Bean添加,依赖注入
<bean id="student" class="com.item.Student" >
    <property name="id" value="1" />
    <property name="name" value="张三" />
    <property name="age" value="12" />
    <property name="classes" ref="classes" />
</bean>

<bean id="classes" class="com.item.Classes" >
    <property name="id" value="1" />
    <property name="name" value="一班" />
</bean>

IoC底层原理

  • 读取xml,解析
  • 通过反射机制实例化配置文件中所有的Bean
package com.item.ioc;

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

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;


public class ClassPathXmlApplicationContext implements ApplicationContext{
    private Map<String, Object> ioc = new HashMap<String, Object>();

    public ClassPathXmlApplicationContext(String path) throws Exception {
        SAXReader reader = new SAXReader();
        Document read = reader.read("./src/main/resources/" + path);
        Element rootElement = read.getRootElement();
        Iterator iterator = rootElement.elementIterator();
        while (iterator.hasNext()){
            Element element = (Element) iterator.next();
            String id = element.attributeValue("id");
            String className = element.attributeValue("class");

            //通过反射创建对象
            Class aClass = Class.forName(className);
            Constructor constructor = aClass.getConstructor();
            Object o = constructor.newInstance();

            Iterator iterator1 = element.elementIterator();
            while (iterator1.hasNext()){
                Element next =(Element) iterator1.next();
                System.out.println("---------------");
                String name = next.attributeValue("name");
                String value = next.attributeValue("value");

                String ref = next.attributeValue("ref");
                System.out.println(ref);
                //普通赋值
                if(ref == null){
                    String mothedName = "set" + name.substring(0, 1).toUpperCase() + name.substring(1);
                    System.out.print(name+ "\t" + value + "\t");
                    Field field = aClass.getDeclaredField(name);
                    System.out.println(field.getType().getName());
                    Method method = aClass.getDeclaredMethod(mothedName, field.getType());
                    Object v = null;
                    if(field.getType().getName() == "int"){
                        v = Integer.parseInt(value);
                    }
                    if(field.getType().getName() == "String"){
                        v = value;
                    }
                    ....
                    method.invoke(o, v);

                }else{ //注入
                    //直接赋值Bean

                    Object obj1 = ioc.get("Classes");
                    System.out.println(obj1);

                    
                }
            }
            ioc.put(id, o);

        }
        System.out.println("=============");
        System.out.println(ioc);
    }

    public Object getBean(String id) {
        return ioc.get(id);
    }
}

运行时类进行获取Bean

Student bean = applicationContext.getBean(Student.class);
System.out.println(bean);

配置文件中只能有一个实例 ,如下抛异常

<bean id="classes" class="com.item.Classes" >
    <property name="id" value="1" />
    <property name="name" value="一班" />
</bean>

<bean id="classes2" class="com.item.Classes" >
    <property name="id" value="1" />
    <property name="name" value="一班" />
</bean>

有参构造创建

  • 在实例中创建有参构造
  • 在xml中配置
    <bean id="classes3" class="com.item.Classes">
        <!--  两种设置参数方式。-->
        <constructor-arg name="name" value="三班" />
        <constructor-arg index="0" value="2" />
    </bean>

集合注入

    <bean id="student" class="com.item.Student" >
        <property name="id" value="1" />
        <property name="name" value="张三" />
        <property name="age" value="12" />
        <property name="classes_List" >
            <list>
                <ref bean="classes"></ref>
                <ref bean="classes2"></ref>
            </list>
        </property>
    </bean>
	<bean id="classes" class="com.item.Classes" >
        <property name="id" value="1" />
        <property name="name" value="一班" />
    </bean>

    <bean id="classes2" class="com.item.Classes" >
        <property name="id" value="1" />
        <property name="name" value="一班" />
    </bean>

Scope 作用域

Spring 管理的bean是根据scope 来生成的,表示bean的作用域

  • singleton:单例模式,在加载文件时创建bean,通过IoC容器获取的bean是唯一的。
  • prototype:原型模式,在调用getBean时创建bean对象,通过IoC容器获取的bean是不同的。
  • request:请求,表示在一次HTTP请求内有效。
  • session:会话,表示在一个用户会话内有效。

request和session只是用于web项目,大多情况下用单例和原型较多

<bean id="classes" class="com.item.Classes" scope="singleton" >
    <property name="id" value="1" />
    <property name="name" value="一班" />
</bean>

Spring 的继承

Java是类层面的继承,子类可以继承父类的内部结构信息,Spring是对象层面的继承,子对象可以继承父对象的属性值。

  • 对象层面的继承

  • 可以使不同类之间继承,子类中必须包含父类所有属性

<bean id="classes" class="com.item.Classes" scope="singleton" >
    <property name="id" value="1" />
    <property name="name" value="一班" />
</bean>
<bean id="cla" class="com.item.Classes" parent="classes" >
	<!--对属性进行重写 -->
    <property name="id" value="3" />
</bean>

Spring的依赖

描述bean和bean之间的关系,配置依赖之后,被依赖对象一定先创建,再创建依赖bean

修改创建顺序

<bean id="cla" class="com.item.Classes" parent="classes" depends-on="student">
    <property name="id" value="3" />
</bean>

image-20200620174623885

Spring 的 P 命名空间

p 命名空间是对 IoC/ DI 的简化
xmlns:p="http://www.springframework.org/schema/p"


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

<!--p命名空间-->
<bean id="classes_p" class="com.item.Classes" p:id="1" p:name="adad"/>

<bean id="student_p" class="com.item.Student" p:id="1" p:name="李四" p:age="12" p:classes-ref="classes_p" />
</beans>

Spring 的工厂方法

静态工厂

  • 实体类
package com.item;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Car {
    Long id;
    String name;
}
  • 静态工厂
package com.item.factory;

import com.item.Car;

import java.util.HashMap;
import java.util.Map;

public class CarFactory {
    static Map<Long, Car> carMap;
    static {
        carMap = new HashMap<Long, Car>();
        carMap.put(1L, new Car(1L, "宝马"));
        carMap.put(2L, new Car(2L, "奔驰"));
    }

    public static Car getCar(Long id, String s){
        System.out.println(s);
        return carMap.get(id);
    }

}
  • 配置工厂
<!--配置静态工厂 默认为单例模式-->
<bean id="car" class="com.item.factory.CarFactory" factory-method="getCar" scope="prototype">
    <!--配置参数-->
    <constructor-arg index="0" value="2" />
    <constructor-arg name="s" value="String" />
</bean>
  • 创建对象
public static void main(String[] args) {
    try {
        ApplicationContext context = new ClassPathXmlApplicationContext("config-factory.xml");
        Car car =(Car) context.getBean("car");
        System.out.println(car);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

实例工厂

  • 工厂类
package com.item.factory;

import com.item.Car;

import java.util.HashMap;
import java.util.Map;

public class InstanceCarFactory {
    private Map<Long, Car> carMap;

    public InstanceCarFactory() {
        carMap = new HashMap<Long, Car>();
        carMap.put(1L, new Car(1L,"宝马"));
        carMap.put(2L, new Car(2L,"奔驰"));
    }

    public Car getCar(Long id){
        return carMap.get(id);
    }
}
  • 配置文件
<!--配置工厂 bean-->
<bean id="factory" class="com.item.factory.InstanceCarFactory" />
<!--配置对象 Car  使用工厂 factory获取  -->
<bean id="car2" factory-bean="factory" factory-method="getCar">
    <constructor-arg name="id" value="2" />
</bean>
  • 使用
public static void main(String[] args) {
    InstanceCarFactory factory = new InstanceCarFactory();
    System.out.println(factory.getCar(1L));

    ApplicationContext context = new ClassPathXmlApplicationContext("config-factory.xml");
    Car car2 = (Car) context.getBean("car2");
    System.out.println(car2);

}

IoC自动装载(Autowire)

IoC负责创建对象,DI完成对象的依赖注入,配置 property 标签的 ref属性。

IoC自动选择bean 进行注入

  • byName :通过名称装载

    按照名字进行装载,没有为null

    <!--传统装载-->
    <bean id="student" class="com.item.Student" >
        <property name="id" value="1" />
        <property name="name" value="张三" />
        <property name="age" value="12" />
        <property name="classes" ref="classes" />
    </bean>
    <!--自动装载-->
    <bean id="student2" class="com.item.Student" autowire="byName">
        <property name="id" value="1" />
        <property name="name" value="张三" />
        <property name="age" value="12" />
     </bean>
    
  • byType : 通过类型装载

    多个同类型,抛出异常,不知装载那个

posted @ 2020-06-22 19:54  KawYang  阅读(123)  评论(0)    收藏  举报