Spring框架-IoC核心


spring FrameWork

springBoot+springCloud+springCloud Data Flow

一:spring的两大核心机制:

  • IoC :工厂模式
  • AOP:代理模式

1:Ioc

Ioc是Spring是框架的灵魂,控制反转。

Student student = new Student();

lombok 可以帮助开发这者自动生成get set 方法..

在idea中使用必须安装插件

@Data注解

@AllArgsConstructor注解全参的构造

@NoArgsConstructor注解构造无参

设置mavend的版本太低:

  1. file - projectStructure.. - Modules - Language Level:jdk8以上
  2. File --> Settings --> Build,Execution,Deployment --> Compiler --> java Compiler

开发过程:

  1. 创建Maven工程,pom.xml导入依赖。
       
               
                   org.springframework
                   spring-context
                   5.2.3.RELEASE
               

           

  2. 在resources路径下创建spring.xml


    3.IoC容器通过读取spring.xml配置文件,加载bean标签来创建对象
    4.调用API来获取IoC中的已经创建的对象
    //传统的开发方式是手动开发对象
    // Student a = new Student();
    // System.out.println(a);
    //IoC容器自动创建对线,开发者只需要取出对象即可
    ApplicationContext applicationContext =new ClassPathXmlApplicationContext("spring.xml");
    Student student = (Student)applicationContext.getBean("student");
    System.out.println(student);
    }

IoC容器创建Bean的两种方式:

  • 无参构造

    给成员变量赋值(原理是利用set 方法修改的)

    IoC取对象:

  • id取
    Student student = (Student)applicationContext.getBean("student");

  • 实体类的实例类取
    Student student = (Student)applicationContext.getBean(Student.class);

    实体类有多个抛异常

  • 有参构造

取对象:

 ApplicationContext applicationContext =new ClassPathXmlApplicationContext("spring.xml");
        Student student = (Student)applicationContext.getBean("student1");
//        Student student = (Student)applicationContext.getBean(Student.class);
        System.out.println(student);

bean中包含特殊字符可以:]]>

<bean id ="classes" class="com.southwind.entity.Classes">
    <property name="id" value="1">property>
    <property name="name">
       <value>]]>value
    property>
bean>

IoC Di

Di 指的是bean之间的依赖注入,设置对象之间的级联关系

Classes:

package com.southwind.entity;

import lombok.Data;

@Data
public class Classes {
    private Integer id;
    private  String name;

}

Student:

package com.southwind.entity;

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


@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
    private Integer id;
    private  String name;
    private Integer age;
    private Classes classes;
}

spring-di.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 ="classes" class="com.southwind.entity.Classes">
        <property name="id" value="1">property>
        <property name="name" value="1班">property>
    bean>
    
    <bean id ="student" class="com.southwind.entity.Student">
        <property name="id" value="1">property>
        <property name="name" value="张三">property>
        <property name="age" value="18">property>
        <property name="classes" ref="classes">property>
    bean>
beans>

Test2:

package com.southwind.test;

import com.southwind.entity.Classes;
import com.southwind.entity.Student;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test2 {
    public static void main(String[] args) {
        //IoC容器自动创建对线,开发者只需要取出对象即可
        ApplicationContext applicationContext =new ClassPathXmlApplicationContext("spring-di.xml");
//        String[] names = applicationContext.getBeanDefinitionNames();
//        for (String name:names){
//            System.out.println(name);
//        }
        Student student = (Student)applicationContext.getBean("student");
        Classes classes =(Classes)applicationContext.getBean("classes");
        System.out.println(student);
    }
}

Bean对象的级联学要使用ref属性来完成映射,而不能直接使用value否值会抛出类型转化异常:

Classes:

package com.southwind.entity;

import lombok.Data;

import javax.swing.*;
import java.util.List;

@Data
public class Classes {
    private Integer id;
    private  String name;
    private List studentList;

}

spring-di.xml:


<bean id ="classes" class="com.southwind.entity.Classes">
    <property name="id" value="1">property>
    <property name="name">
       <value>]]>value>
    property>
    <property name="studentList">
        <list>
            <ref bean="student" >ref>
            <ref bean="student1" >ref>
        list>
    property>
bean>

但是要注意不能闭环

spring中的Bean

bean 是根据scope 来生成的,表示bean的作用域,scope有4种“

  1. singleton ,单例,表示通过Spring容器获取对象的唯一性 默认
    (无论取不取,只要加载IoC容器,就创建对象)
  2. prototype, 原型,表示通过Spring容器获取的对象是不同的
    (如果不取Bean就不创建对象,取几个就创建几个对象)
  3. request ,请求,表示在一次HTTP请求内有效
  4. session ,会话,表示在一个用户内有效
    requestion、session仅在web中有效

Spring的继承

Spring的继承不同于Java ,区别:java中的继承是真对类的,SPring中的继承是针对对象的(Bean)

Spring的继承中,子Bean可以以继承父Bean中的值

通过parent设置继承关系,同时值bean的值来继承和覆盖

<bean id="user1" class="com.southwind.entity.User" scope="prototype" >
    <property name="id" value="1">property>
    <property name="name" value="张三">property>
bean>
<bean id="user" class="com.southwind.entity.User" scope="prototype" parent="user1">
    <property name="name" value="李四">property>
bean>

即使是两个不同的类,只是赋值。(属性名一样必须,不一样抛异常)(只要成员变量一样就行)

Spring的依赖:

用来设置两个Bean的顺序

IoC容器默认情况是通过spring.xml中bean的配置顺序来决定创建的顺序

在不修改spring.xml来depends-on=""修改

"user" class="com.southwind.entity.User" depends-on="student">

bean>
"student" class="com.southwind.entity.Student">bean>

Spring读取外部资源

实际开发中,数据库的资源一般会单独保存起来。一般会保存到后缀为properties的文件中,方便维护和修改,如果Spring加载资源,就需要在spring.xml中读取properties中的资源

xxx.properties

user=root
password=root
url = jdbc:mysql://localhost:3306/library
driverName=com.mysql.cj.jdbc.Driver

spring-xx.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"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"
>


    <context:property-placeholder location="classpath:jdbc.properties">context:property-placeholder>

    <bean id="dataSource" class="com.southwind.entity.DataSouse ">
        <property name="user" value="${user}">property>
        <property name="password" value="${password}">property>
        <property name="url" value="${url}">property>
        <property name="driverName" value="${driverName}">property>
    bean>
beans>

DataSource:

package com.southwind.entity;

import lombok.Data;

@Data
public class DataSouse {
    private String user;
    private String password;
    private String url;
    private String driverName;
}

测试类:

package com.southwind.test;

import com.southwind.entity.DataSouse;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test4 {
    public static void main(String[] args) {
        ApplicationContext applicationContext =new ClassPathXmlApplicationContext("spring-property.xml");
        DataSouse dataSouse = (DataSouse)applicationContext.getBean("dataSource");
        System.out.println(dataSouse);
    }
}

Spring p 命名空间

p 命名空间简化Bean的配置

Spring-p.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"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd"
>

    <bean id="student" class="com.southwind.entity.Student" p:id="1" p:name="张三">bean>
beans>

测试类:

package com.southwind.test;

import com.southwind.entity.Student;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test5 {
    public static void main(String[] args) {
        ApplicationContext applicationContext =new ClassPathXmlApplicationContext("spring-p.xml");
        Student student = (Student)applicationContext.getBean("student");
        System.out.println(student);
    }
}

如果和级联一样:也是p:age-ref=""写类

同时也要引入:

xmlns:p="http://www.springframework.org/schema/p"

"http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd"
>

Spring的工厂方法:

IoC通过工厂模式创建bean对线有两种方式:

  • 静态工厂模式
  • 实例工厂模式
    区别在与:静态工厂不需要实例化,实例工厂需要实例化

1.静态工厂

  1. 实体类Car
    package com.southwind.entity;

    import lombok.AllArgsConstructor;
    import lombok.Data;

    @Data
    @AllArgsConstructor
    public class Car {
    private Integer num;
    private String brand;
    }

  2. 创建静态工厂,使用静态工厂方法:
    package com.southwind.factory;

    import com.southwind.entity.Car;

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

    public class StaticCarFactory {
    private static Map carMap;
    static {
    carMap=new HashMap<>();
    carMap.put(1,new Car(1,"奥迪"));
    carMap.put(1,new Car(1,"奥拓"));
    }
    public static Car getCar(Integer num){
    return carMap.get(num);
    }
    }

3.Spring-xx.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="car1" class="com.southwind.factory.StaticCarFactory" factory-method="getCar">
        <constructor-arg value="1">constructor-arg>
    bean>
beans>

factory-method 是指向静态方法

constructor-arg value="1” 是指向传入的参数

测试类:

package com.southwind.test;

import com.southwind.entity.Car;
import com.southwind.factory.StaticCarFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test6 {
    public static void main(String[] args) {
//        Car car = StaticCarFactory.getCar(1);
        ApplicationContext applicationContext= new ClassPathXmlApplicationContext("spring-factory.xml");
        Car car = (Car)applicationContext.getBean("car1");
        System.out.println(car);
    }
}

2.实例工厂方法:

1.创建实例工厂类、工厂方法

package com.southwind.factory;

import com.southwind.entity.Car;

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

public class InstanceCarFactory {
    private Map carMap;
    public InstanceCarFactory(){
        carMap= new HashMap<>();
        carMap.put(1,new Car(1,"奥迪"));
        carMap.put(1,new Car(1,"奥托"));

    }
    public  Car getCar(Integer num){
        return carMap.get(num);
    }
}

2.spring-xx.xml


    <bean id="instanceCarFactory" class="com.southwind.factory.InstanceCarFactory">bean>

    <bean id="car2" factory-bean="instanceCarFactory" factory-method="getCar">
        <constructor-arg value="1">constructor-arg>
    bean>

测试类:

package com.southwind.test;

import com.southwind.entity.Car;
import com.southwind.factory.StaticCarFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test6 {
    public static void main(String[] args) {
//        Car car = StaticCarFactory.getCar(1);
//        ApplicationContext applicationContext= new ClassPathXmlApplicationContext("spring-factory.xml");
//        Car car = (Car)applicationContext.getBean("car1");
//        System.out.println(car);
//    }
//        实例工厂
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-factory.xml");
        Car car = (Car) applicationContext.getBean("car2");
        System.out.println(car);
    }
}

区别:

  1. 静态工厂方法创建Car对象,不需要创建Car对象,因为静态工厂的静态方法,不需要通过创建对象即可调用。spring-xx.xml中只需要配置一个Bean,即最终的Car即可。
  2. 实例工厂方法创建Car对象,需要实例化工厂对象,因为getCar()方法是非静态的,就必须通过实例化的对象才能调用,所以就必须创建工厂对象,spring。xml中,要配置两个Bean一个是工厂对象,一个是Car 对象。

Spring IoC 自动装载 autowire:

自动装载是Spring提供的一种更加简单的方式,来完成DI,不需要手动配置property ,IoC容器会自动选择Bean玩成注入。

自动装载俩种:

  • byName ,通过属性名完成自动装载

  • byType,通过属性对应的数据类型完成自动装载
    byName
    1.创建实体类
    package com.southwind.entity;

    import lombok.Data;

    @Data
    public class Presson {
    private Integer Id;
    private String name;
    private Car car;

    }

2.在spring.xml中配置Car和Person的Bean,通过自动装载完成依赖注入

<bean id="person" class="com.southwind.entity.Presson" autowire="byName">
    <property name="id" value="1">property>
    <property name="name" value="张三">property>
bean>
<bean id="car" class="com.southwind.entity.Car">
    <constructor-arg name="num" value="1"> constructor-arg>
    <constructor-arg name="brand" value="奥迪">constructor-arg>
bean>

测试:

package com.southwind.test;

import com.southwind.entity.Presson;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test7 {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-autowire.xml");
        Presson preson =(Presson)applicationContext.getBean("person");
        System.out.println(preson);
    }
}

byType:

1.实体类

2.在spring.xml中配置Car和Person的Bean,通过自动装载完成依赖注入

<bean id="person" class="com.southwind.entity.Presson" autowire="byType">
    <property name="id" value="1">property>
    <property name="name" value="张三">property>
bean>
<bean id="car" class="com.southwind.entity.Car">
    <constructor-arg name="num" value="1"> constructor-arg>
    <constructor-arg name="brand" value="奥迪">constructor-arg>
bean>

注意:

使用byType进行自动装载时,多个会有异常。

Spring IoC基于注解的开发

SpingIoC的作用帮助开发者创建项目中所需要的Bean,同时完成Bean之间的依赖注入关系。DI

实现功能有两种方式:

  • 基于xml
  • 基于注解
    基于注解的配置有两部:
  1. 配置自动扫包

  2. 添加注解: @Component (默认首字母类第一个字母小写为名字)
    package com.southwind.entity;

     import lombok.Data;
     import org.springframework.stereotype.Component;

     @Data
     @Component
     public class Repository {
         private  DataSouse dataSouse;
     }

    改名字:@Component(value = "myrepo")
    package com.southwind.entity;

     import lombok.Data;
     import org.springframework.stereotype.Component;

     @Data
     @Component(value = "myrepo")
     public class Repository {
         private  DataSouse dataSouse;
     }

    分析注入得到类:
    String[] s= applicationContext.getBeanDefinitionNames();
    for(String name :s){
    System.out.println(name);
    }

DI:

package com.southwind.entity;

import lombok.Data;
import org.springframework.stereotype.Component;

@Data
@Component
public class DataSouse {
    private String user;
    private String password;
    private String url;
    private String driverName;
}

自动装载:@Autowired(默认时byType)

package com.southwind.entity;

import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Data
@Component
public class Repository {
    @Autowired
    private  DataSouse dataSouse;
}

要改变为byName()配合 @Qualifier(value="DS")

@Data
@Component
public class Repository {
    @Autowired
    @Qualifier(value="DS")
    private  DataSouse dataSouse;
}

实体类中的普通的成员变量可以通过@Value进行赋值

@Data
@Component(value = "DS")
public class DataSouse {
    @Value("root")
    private String user;
    @Value("root")
    private String password;
    @Value("jdbc:mysql://localhost:3306/library")
    private String url;
    @Value("com.mysql.cj.jdbc.Driver")
    private String driverName;
}

实际开发的使用

实际开发中会将程序分为3层:

  1. Controller
  2. Servlet
  3. Repository(DAO)

关系Controller 调运Servlet 调运 Repository(DAO)

@Component 注解是将标注的类加载到IoC容器中,实际开发中可以分别根据

@Controller 控制层

@Service 业务层

@Repository 持久层

代码:

1.

package com.southwind.Repository;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;


public interface myRepository {
    public  String domyRepository(Double score);
}

package com.southwind.Repository.impl;

import com.southwind.Repository.myRepository;
import org.springframework.stereotype.Repository;

@Repository
public class mymyRepositoryImpl  implements myRepository {
    @Override
    public String domyRepository(Double score) {
        String result="";
        if(score<60){
            result="不及格";
        }else if(score>=60&&score<80){
            result="合格";
        }else {
            result="优秀";
        }
        return result;
    }
}

2.

package com.southwind.Service;

import org.springframework.stereotype.Component;


public interface myService {
    public String doSrvice(Double score);
}

package com.southwind.Service.impl;

import com.southwind.Repository.myRepository;
import com.southwind.Service.myService;
import lombok.Setter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;


@Setter
@Service
public class myServiceImpl implements myService {
    @Autowired
    private myRepository  myRepository;
    @Override
    public String doSrvice( Double score) {
        return myRepository.domyRepository(score);
    }
}

3.

package com.southwind.Controller;

import com.southwind.Service.myService;
import lombok.Data;
import lombok.Setter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

@Controller(value = "a")
@Data
public class myControlller {
//客户端请求
    @Autowired
    private com.southwind.Service.myService myService;
;    public String service(Double score){
        return myService.doSrvice(score);
    }
}

配置:

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




    <context:component-scan base-package="com.southwind">context:component-scan>







beans>

测试类:

package com.southwind.test;

import com.southwind.Controller.myControlller;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test9 {
    public static void main(String[] args) {
        ApplicationContext applicationContext =new ClassPathXmlApplicationContext("spring-annotation.xml");
//        String[] s= applicationContext.getBeanDefinitionNames();
//        for(String name :s){
//            System.out.println(name);
//        }
//        客户端请求
        myControlller myControlller =(myControlller) applicationContext.getBean("a") ;
        String result = myControlller.service(new Double(77));
        System.out.println(result);
    }
}

Spring IoC的底层实现:

核心技术: XML解析+反射

具体思路:

  1. 根据需求编写XML文件,配置需要的创建的Bean.
  2. 编写程序需要的XML文件,获取Bean的相关信息,类,属性,id
  3. 根据第二步骤获得到的信息,结合反射机制动态的创建对象,同时完成属性的赋值
  4. 将创建好的bean存入Map集合中,设置key就是bean的id的值,value就是bean的对象
  5. 提供方法从Map中获得对应的value

相关