Spring框架概述

  • 百度一堆,不细说
  • 核心 IOC,AOP
  • 控制反转IOC,面向切面AOP

    • 创建对象过程交给spring进行管理 ioc
    • 面向切面,不修改源码的基础上进行功能增强aop

      IOC容器

      IOC底层原理

  • 控制反转,对象创建和对象之间的调用过程交给spring进行管理

  • 使用ioc目的:降低耦合度
  • 底层原理 xml解析,工厂模式,反射

image.png

  • 如果对上图不是很能理解思考一下是否应该复习javase 。

    IOC接口 (BeanFactory接口

  • ioc 思想基于ioc容器完成,ioc容器底层就是对象工厂

  • Spring提供ioc容器两种实现 两个接口
    • BeanFactory: ioc容器的基本实现,是spring内部使用接口,不提供给开发人员进行使用
      • 注意: 加载配置文件的时候不会创建对象,而是在获取对象(使用)的时候才去创建对象
    • ApplicationContext: BeanFactory 的自接口,提供更多更强大的实现,一般由开发人员进行使用
      • 注意:加载配置文件的时候就会吧配置文件中的bean对象进行创建 ```java @Test public void testBean(){ // 1 加载spring的配置文件 // 两种方式皆可,但是区别如上, ApplicationContext context = new ClassPathXmlApplicationContext(“bean1.xml”); BeanFactory context1 = new ClassPathXmlApplicationContext(“bean1.xml”); // 2 获取配置创建的对象 // User user = context.getBean(“user”, User.class); UserService userService = context.getBean(“userService”, UserService.class); userService.add(); }
  1. <a name="v6Xki"></a>
  2. ### ApplicationContext接口的两个实现类
  3. ![image.png](https://cdn.nlark.com/yuque/0/2021/png/1608527/1631541940999-1e989106-c5b4-4984-b561-40a793c89ed8.png#clientId=ue15a0847-cad6-4&from=paste&height=469&id=SbMT3&margin=%5Bobject%20Object%5D&name=image.png&originHeight=469&originWidth=876&originalType=binary&ratio=1&size=339874&status=done&style=none&taskId=ue5a37cb4-d683-4e0c-abad-24c242deca8&width=876)
  4. - 简要区别 FileSystem 开头的,按照文件系统的绝对路径,ClassPath 按照项目的相对路径。
  5. - 调用不同则决定去寻找xml配置文件的方式不同。
  6. <a name="WqT6N"></a>
  7. # IOC操作 Bean 管理 概念
  8. - 什么是bean的管理
  9. - bean的管理指的是两个操作
  10. - spring创建对象
  11. - spring注入属性
  12. - bean管理操作两种方式 如下
  13. <a name="ALu7r"></a>
  14. ## IOC 操作 Bean 管理 基于XML
  15. <a name="B1bk2"></a>
  16. ### 基于xml方式创建对象
  17. ```java
  18. <!-- 配置user对象创建 -->
  19. <bean id="user" class="com.addicated.spring5.User"></bean>
  • spring配置文件中使用bean标签,标签里面添加对应属性,实现对象创建
  • 在bean标签有很多属性,下面介绍常用
    • id 属性 : 唯一表示 web.xml下唯一
    • class 属性: 全类名,用于底层反射进行类对象创建
  • 创建对象的时候,默认也是执行无参数构造方法完成对象创建

    基于xml方式注入属性

  • DI: 依赖注入 ,就是注入属性

    传统方式

    ```java /**

  • 演示使用 set 方法进行注入属性 */ public class Book { //创建属性 private String bname; private String bauthor; //创建属性对应的 set 方法 public void setBname(String bname) { this.bname = bname; } public void setBauthor(String bauthor) { this.bauthor = bauthor; } }
    <a name="KKg31"></a>
    #### spring的xml 注入 通过set
    ```java
    <!--2 set 方法注入属性--> <bean id="book" class="com.atguigu.spring5.Book">
    <!--使用 property 完成属性注入
    name:类里面属性名称
    value:向属性注入的值
    --><property name="bname" value="易筋经"></property> <property name="bauthor" value="达摩老祖"></property>
    </bean>
    
  • 注意:需要注入的bean中提供set方法,原因不再赘述,文章一开头已经指出

    spring的xml注入 通过有参数构造

  • 创建类,定义属性,创建有参数构造器

    <!--3 有参数构造注入属性--> <bean id="orders" class="com.atguigu.spring5.Orders"> <constructor-arg name="oname" value="电脑"></constructor-arg> <constructor-arg name="address" value="China"></constructor-arg>
    </bean>
    

    spring的xml注入 p空间注入 了解

    ```java <?xml version=”1.0” encoding=”UTF-8”?>

```java
(1)使用 p 名称空间注入,可以简化基于 xml 配置方式
第一步 添加 p 名称空间在配置文件中
第二步 进行属性注入,在 bean 标签里面进行操作
<!--2 set 方法注入属性--> <bean id="book" class="com.atguigu.spring5.Book" p:bname="九阳神功" 
p:bauthor="无名氏"></bean>

spring的xml注入 其他类型属性

  • 字面量 与 特殊字符 避免转义
    • null值 ```java 演示null值注入 <![CDATA[<<测试字符>>]]]>
</bean>
<a name="UlwVM"></a>
#### spring的xml注入属性 外部bean

- 创建两个类 service 和dao
- 在service 中调用dao里面的方法
- 在spring配置文件中进行配置    
```java
---- service
package com.addicated.spring5.service;

import com.addicated.spring5.dao.UserDao;

public class UserService {

    private UserDao userDao;

    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    public void add(){
        System.out.println("添加用户");
        userDao.update();
    }
}
-- dao 
package com.addicated.spring5.dao;

public interface UserDao {

    public void update();
}
--- daoimpl
package com.addicated.spring5.dao;

public class UserDaoImpl implements UserDao {
    @Override
    public void update() {
        System.out.println("userdao接口的update方法得到了调用");
    }
}
  • spring中xml ```java

- 相当于在一个bean内通过ref吧另外一个bean对象关联进来,关联的bean要提供其的set方法
<a name="DPbvy"></a>
#### spring的xml注入属性 内部bean

- 案例
   - 一对多关系:部门和员工
   - 一个部门有多个与昂工,一个员工属于一个部门  
   - 部门为1,员工为多
   - 实体类中表示1对多关系。
```java
---- Dept
package com.addicated.spring5.dept;

public class Dept {

    private String dname;

    public void setDname(String dname) {
        this.dname = dname;
    }
}
---- Emp
package com.addicated.spring5.dept;

public class Emp {


    private String eName;
    private String gender;


    // 员工属于某一个部门,使用对象的形式进行表示

    private Dept dept;

    public void setDept(Dept dept) {
        this.dept = dept;
    }

    public void seteName(String eName) {
        this.eName = eName;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    @Override
    public String toString() {
        return "Emp{" +
                "eName='" + eName + '\'' +
                ", gender='" + gender + '\'' +
                ", dept=" + dept +
                '}';
    }
}
  • spring 配置 简单理解,bean中bean ```java
<a name="WcYCU"></a>
#### spring的xml注入属性 级联赋值

- 相当于引如外部bean 然后再进行修改赋值
```java
       <bean id="emp" class="com.atguigu.spring5.bean.Emp">
                     <!--设置两个普通属性-->
                     <property name="ename" value="lucy"></property>
                     <property name="gender" value="女"></property>
                     <!--级联赋值-->
                     <property name="dept" ref="dept"></property>
                     这种方式需要 在对应bean内 提供要设置的目标bean的get方法,否则会找不到要设置属性的bean,会覆盖外部bena的值
                     <property name="dept.dname" value="技术部"></property>
                 </bean>
                 <bean id="dept" class="com.atguigu.spring5.bean.Dept">
                     <property name="dname" value="财务部"></property>
                 </bean>

spring的xml 注入集合属性

  • 注入数组类型属性
  • 注入List集合类型属性
  • 注入Map集合类型属性

    • 创建类,定义数组,list,map,set类型属性,生成set方法
      public class Stu {
      //1 数组类型属性
      private String[] courses;
      //2 list 集合类型属性
      private List<String> list;
      //3 map 集合类型属性
      private Map<String,String> maps;
      //4 set 集合类型属性
      private Set<String> sets;
      public void setSets(Set<String> sets) {
      this.sets = sets;
      }
      public void setCourses(String[] courses) {
      this.courses = courses;
      }
      public void setList(List<String> list) {
      this.list = list;
      }
      public void setMaps(Map<String, String> maps) {
      this.maps = maps;
      } }
      
  • 编写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">
    
      <!--1 集合类型属性注入-->
      <bean id="stu" class="com.atguigu.spring5.collectiontype.Stu">
          <!--数组类型属性注入-->
          <property name="courses">
              <array>
                  <value>java课程</value>
                  <value>数据库课程</value>
              </array>
          </property>
          <!--list类型属性注入-->
          <property name="list">
              <list>
                  <value>张三</value>
                  <value>小三</value>
              </list>
          </property>
          <!--map类型属性注入-->
          <property name="maps">
              <map>
                  <entry key="JAVA" value="java"></entry>
                  <entry key="PHP" value="php"></entry>
              </map>
          </property>
          <!--set类型属性注入-->
          <property name="sets">
              <set>
                  <value>MySQL</value>
                  <value>Redis</value>
              </set>
          </property>
          <!--注入list集合类型,值是对象-->
          <property name="courseList">
              <list>
                  <ref bean="course1"></ref>
                  <ref bean="course2"></ref>
              </list>
          </property>
      </bean>
    
      <!--创建多个course对象-->
      <bean id="course1" class="com.atguigu.spring5.collectiontype.Course">
          <property name="cname" value="Spring5框架"></property>
      </bean>
      <bean id="course2" class="com.atguigu.spring5.collectiontype.Course">
          <property name="cname" value="MyBatis框架"></property>
      </bean>
    </beans>
    
  • 在集合里面设置对象类型

      <!--注入list集合类型,值是对象-->
          <property name="courseList">
              <list>
                  <ref bean="course1"></ref>
                  <ref bean="course2"></ref>
              </list>
          </property>
      </bean>
    
      <!--创建多个course对象-->
      <bean id="course1" class="com.atguigu.spring5.collectiontype.Course">
          <property name="cname" value="Spring5框架"></property>
      </bean>
      <bean id="course2" class="com.atguigu.spring5.collectiontype.Course">
          <property name="cname" value="MyBatis框架"></property>
      </bean>
    

    集合注入提取

    IOC 操作Bean 管理(FactoryBean)

  • spring中有两种bean ,一种普通bean,另外一种工厂bean (factoryBean

  • 普通bean , 在配置文件中定义bean类型就是返回类型
  • 工厂bean 在配置文件定义bean类型可以和返回类型不一样
    • 第一步 创建类,让这个类作为工厂bean,实现接口FactoryBean
    • 第二部 实现接口里面的方法 ```java package com.atguigu.spring5.factorybean;

import com.atguigu.spring5.collectiontype.Course; import org.springframework.beans.factory.FactoryBean;

public class MyBean implements FactoryBean {

//定义返回bean
@Override
public Course getObject() throws Exception {
    Course course = new Course();
    course.setCname("abc");
    return course;
}

@Override
public Class<?> getObjectType() {
    return null;
}

@Override
public boolean isSingleton() {
    return false;
}

}

@Test public void test3() { ApplicationContext context = new ClassPathXmlApplicationContext(“bean3.xml”); // 这里是因为上面实现 FacotryBean的时候定义了返回的bean类型 Course course = context.getBean(“myBean”,Course.class); System.out.println(course); }

<a name="hrOCj"></a>
## IOC操作Bean 作用域

- spring中,默认情况下 bean是单实例对象
```java
    @Test
    public  void testSpring(){
        ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
        Stu stu = context.getBean("Stu", Stu.class);
        Stu stu1 = context.getBean("Stu", Stu.class);
//        两个对象的hash值一致,代表默认单实例
        System.out.println(stu.hashCode());
        System.out.println(stu1.hashCode());
    }
  • 如何设置单例还是多例

    • spring配置文件 bean标签中有scope标签用于设置单还是多例实现
    • scope属性只说明
      • 第一个值 默认 singleton 单例
      • 第二个值 prototype 多例
        <bean id="myBean" class="com.addicated.factoryBean.MyBean" scope="singleton"></bean>
        <bean id="myBean" class="com.addicated.factoryBean.MyBean" scope="prototype"></bean>
        

        单/多区别

  • singleton 单实例 prototype多实例

  • 设置scope为 singleton 的时候,加载spring配置文件时就会创建单实例对象
  • 设置scope为 prototype的时候,不是在加载Spring配置文件的时候创建对象,而是在调用getBean方法的时候创建多实例对象

    IOC 操作 Bean 生命周期

  • 生命周期

    • 从对象创建到对象销毁的过程
  • bean生命周期
    • 通过构造器创建bean实例 无参构造器
    • 为bean的属性设置值和对其他bean进行引用 调用set方法
    • 调用bean的初始化方法 需要在配置中进行配置
    • bean可以使用了 (代表对象获取到了
    • 当容器关闭的时候,调用bean的销毁方法(同样需要在配置中进行配置 ```java package com.addicated.bean_;

public class Orders {

//无参数构造
public Orders() {
    System.out.println("第一步 执行无参数构造创建bean实例");
}

private String oname;
public void setOname(String oname) {
    this.oname = oname;
    System.out.println("第二步 调用set方法设置属性值");
}

//创建执行的初始化的方法
public void initMethod() {
    System.out.println("第三步 执行初始化的方法");
}

//创建执行的销毁的方法
public void destroyMethod() {
    System.out.println("第五步 执行销毁的方法");
}

}

       @Test
public  void testMyBean1(){
    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean4.xml");

// MyBean myBean = context.getBean(“myBean”, MyBean.class); Orders myBean = context.getBean(“Orders”, Orders.class); System.out.println(myBean); context.close(); }

![image.png](https://cdn.nlark.com/yuque/0/2021/png/1608527/1631632697124-d51b6f99-288c-4460-bdd4-a322a032db82.png#clientId=u64024d69-9a4d-4&from=paste&height=617&id=uabdc2ef4&margin=%5Bobject%20Object%5D&name=image.png&originHeight=617&originWidth=672&originalType=binary&ratio=1&size=364576&status=done&style=none&taskId=ue739ddb1-f337-4271-9907-c8d7df17060&width=672)
<a name="Wv73Q"></a>
### bean 的后置处理器
(1)通过构造器创建 bean 实例(无参数构造) <br />(2)为 bean 的属性设置值和对其他 bean 引用(调用 set 方法) <br />**(3)把 bean 实例传递 bean 后置处理器的方法 **postProcessBeforeInitialization <br />(4)调用 bean 的初始化的方法(需要进行配置初始化的方法)<br />**(5)把 bean 实例传递 bean 后置处理器的方法 **postProcessAfterInitialization <br />(6)bean 可以使用了(对象获取到了) <br />(7)当容器关闭时候,调用 bean 的销毁的方法(需要进行配置销毁的方法)
<a name="kvpoq"></a>
### 实现
```java
package com.addicated.bean_;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.lang.Nullable;
import org.springframework.util.SocketUtils;

public class MyBeanPost implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("在初始化之前执行的方法");
        return bean;
    }
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("在初始化之后执行的方法");
        return bean;
    }
}

<!-- 配置后置处理器      -->
   <bean id="MyBeanPost" class="com.addicated.bean_.MyBeanPost" >
   </bean>

image.png

IOC 操作 Bean管理 xml自动装配

  • * 之前在web.xml进行属性注入 都为手动
    1 什么是自动装配
    1)根据指定装配规则(属性名或者属性类型) Spring自动将陪陪的属性值进行注入
    2 演示自动装配过程 ```java

<a name="N7Kel"></a>
## IOC 操作 Bean 管理 (外部属性文件引入

- 引入 context 命名空间,具体可百度
```java
<?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"
       xmlns:util="http://www.springframework.org/schema/util"
       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/util http://www.springframework.org/schema/util/spring-util.xsd">


   <!--直接配置连接池-->
   <!--<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
       <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
       <property name="url" value="jdbc:mysql://localhost:3306/userDb"></property>
       <property name="username" value="root"></property>
       <property name="password" value="root"></property>
   </bean>-->

   <!--引入外部属性文件-->
   <context:property-placeholder location="classpath:jdbc.properties"/>

   <!--配置连接池-->
   <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
      <property name="driverClassName" value="${prop.driverClass}"></property>
      <property name="url" value="${prop.url}"></property>
      <property name="username" value="${prop.userName}"></property>
      <property name="password" value="${prop.password}"></property>
   </bean>

</beans>

----jdbc.properties 文件内容如下
prop.driverClass=com.mysql.jdbc.Driver
prop.url=jdbc:mysql://localhost:3306/userDb
prop.userName=root
prop.password=root