Spring概述 Spring IOC

1.Spring概述

1.1.Spring介绍

Spring是轻量级Java EE应用开源框架(官网: http://spring.io/ ),它由Rod Johnson创为了解决企业级编程开发的复杂性而创建
1、Spring是什么?

	Spring是轻量级的JAVAEE应用开源框架

2、Spring的好处?

	IOC:控制反转
	AOP:面向切面
	粘合剂:整合其他技术和框架

1.2.简化应用开发体现在哪些方面?

  1. IOC

    解决传统Web开发中硬编码所造成的程序耦合

  2. AOP

    实现在运行期间不修改源代码对程序进行增强

  3. 粘合剂

    Spring是一个超级粘合平台,除了自己提供功能外,还提供整合其他技术和框架的能力

1.3.Spring的体系结构

Spring 框架根据功能的不同大体可分为 Data Access/Integration(数据访问与集成)WebAOP、Aspects、Instrumentation(检测)、Messaging(消息处理)Core Container(核心容器)Test在这里插入图片描述

  • Core Container: 框架的最基础部分,提供控制反转和依赖注入特性
  • AOP :提供了面向切面的编程的实现
  • Data Access/Integration:简化了持久层的操作
  • Web:提供了Spring MVC Web 框架实现以及与Servlet、WebSocket的集成
  • Test:方便程序的测试

2.Spring IOC

2.1.程序的耦合

创建工程:
在这里插入图片描述

  • 耦合:耦合指的就是对象之间的依赖关系。对象之间的耦合越高,维护成本越高。
    • 产生耦合的原因:硬编码
  • 案例:没有引入IOC容器时系统的Web层、业务层、持久层存在耦合

持久层

package com.by.dao;

public class UserDaoImpl implements UserDao{
    @Override
    public void addUser(){
        System.out.println("insert into tb_user......");
    }
}

业务层

/**
 * 业务层实现类
 */
public class UserServiceImpl implements UserService {
    //硬编码:此处有依赖关系
    private UserDao userDao = new UserDaoImpl();

    public void addUser(){
        userDao.addUser();
    }
}

模拟表现层

/**
 * 模拟表现层
 */
public class Client {
    public static void main(String[] args) {
        //硬编码:此处有依赖关系
        UserService userService = new UserServiceImpl();
        userService.addUser();
    }
}
  • 问题分析:
    • 上述的代码service的代码依赖dao层的实现类,此时如果更改了dao层的实现类或者是没有dao层的实现类,编译将不能通过
  • 2、IOC
    控制:控制对象的创建
    IOC (Inverse of Control)即控制反转:正传是自己创建对象;反转是由工厂创建依赖对象
  • 3、工厂模式的IOC解决程序耦合
    1.把dao和service配置到beans.properties
    2.读取beans.properties
    3.通过反射创建对象,并装到容器中
    4.在使用时,直接从容器中获得

2.2 IOC解决程序耦合

2.2.1IOC(工厂模式)解耦

案例一

package com.by.factory;

import com.by.dao.UserDao;
import com.by.dao.UserDaoImpl;
import com.by.service.UserService;
import com.by.service.UserServiceImpl;

public class BeanFactory_v1 {

   public static UserDao getUserDao(){
       return new UserDaoImpl();
   }

   public static UserService getUserService(){
       return new UserServiceImpl();
   }
}

  • 业务实现层
package com.by.service;

import com.by.dao.UserDao;
import com.by.dao.UserDaoImpl;
import com.by.factory.BeanFactory_v1;
import com.by.factory.BeanFactory_v2;
import com.by.factory.BeanFactory_v3;

public class UserServiceImpl implements UserService{
    //高耦合:对象之间的依赖关系
   private UserDao userDao = new UserDaoImpl();
   private UserDao userDao = BeanFactory_v1.getUserDao();
    @Override
    public void addUser() {
        userDao.addUser();
    }
}

问题:我们在开发中会有很多个service和dao,此时工厂类就要添加无数个方法。

案例二

  • 配置文件beans.properties
#1、配置要使用的dao和service
UserDao=com.by.dao.UserDaoImpl
UserService=com.by.service.UserServiceImpl
  • 工厂 BeanFactory_v2
package com.by.factory;

import com.by.dao.UserDao;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

/*
问题:
1.每次都会创建新的对象
2.获得对象时才读取配置文件
 */
public class BeanFactory_v2 {
    public static Object getBean(String propertiesKey) {
        try {
            //不能使用:项目发布后没有是src目录
            //InputStream inputStream = new FileInputStream("src\\main\\resources\\Bean.properties");
            //getClassLoader  负责加载classes下的资源
            InputStream inputStream = BeanFactory_v2.class.getClassLoader().getResourceAsStream("Bean.properties");

            //Properties:继承了Hashtable,作用是读取 *.properties文件
            Properties properties = new Properties();
            properties.load(inputStream);

            /*************** 根据配置文件的values值创建反射对象********************/
            //通过反射 创建对象
            return Class.forName(properties.getProperty(propertiesKey)).newInstance();
        } catch (IOException e) {
            throw new RuntimeException(e);
        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }

    }

    public static void main(String[] args) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException {
        UserDao userDao = (UserDao) BeanFactory_v2.getBean("userDao");
        userDao.addUser();
    }
}

  • 业务实现层
package com.by.service;

import com.by.dao.UserDao;
import com.by.dao.UserDaoImpl;
import com.by.factory.BeanFactory_v1;
import com.by.factory.BeanFactory_v2;
import com.by.factory.BeanFactory_v3;

public class UserServiceImpl implements UserService{
    //高耦合:对象之间的依赖关系
   //private UserDao userDao = (UserDao) BeanFactory_v2.getBean("userDao");
    @Override
    public void addUser() {
        userDao.addUser();
    }
}

  • 模拟表现层
/**
 * 模拟表现层
 */
public class Client {
    public static void main(String[] args) {
        //直接引用接口实现类
      for (int i = 0; i < 5; i++) {
            UserService userService = 
              (UserService)BeanFactory.getBean("UserService");
            System.out.println(userService);
        }
    }
}

在这里插入图片描述

问题:

  • 1.每次都会创建对象
  • 2.程序运行时才会创建对象

案例三

  • 工厂
package com.by.factory;

import com.by.dao.UserDao;

import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

/*
问题:
1.每次都会创建新的对象
2.获得对象时才读取配置文件
 */
public class BeanFactory_v3 {
    private static Map<String,Object> iocMap = new HashMap<>();
    static {
        try {
            //解决 2.获得对象时才读取配置文件
            //读取配置文件
            InputStream inputStream = BeanFactory_v3.class.getClassLoader().getResourceAsStream("Bean.properties");
            Properties properties = new Properties();
            properties.load(inputStream);

            //解决 1.每次都会创建新的对象 在静态代码块中创建对象并装到Map中,
            // 每次调用getBean()都直接从Map中获取对象而无需在重新创建
            Set<Object> keySet = properties.keySet();
            for (Object key : keySet) {
                String propertyValue = properties.getProperty((String) key);
                iocMap.put((String) key,Class.forName(propertyValue).newInstance());
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    public static Object getBean(String propertiesKey) {
        return iocMap.get(propertiesKey);
    }

    public static void main(String[] args) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException {
        UserDao userDao = (UserDao) BeanFactory_v3.getBean("userDao");
        userDao.addUser();
    }
}

  • 业务层
package com.by.service;

import com.by.dao.UserDao;
import com.by.dao.UserDaoImpl;
import com.by.factory.BeanFactory_v1;
import com.by.factory.BeanFactory_v2;
import com.by.factory.BeanFactory_v3;

public class UserServiceImpl implements UserService{
    //高耦合:对象之间的依赖关系
   private UserDao userDao = (UserDao) BeanFactory_v3.getBean("userDao");

    @Override
    public void addUser() {
        userDao.addUser();
    }
}

  • 模拟表现层
package com.by.web;

import com.by.factory.BeanFactory_v1;
import com.by.factory.BeanFactory_v2;
import com.by.factory.BeanFactory_v3;
import com.by.service.UserService;
import com.by.service.UserServiceImpl;

public class Client {
    public static void main(String[] args) {
        //高耦合:硬编码
        UserService userService = (UserService) BeanFactory_v3.getBean("userService");
        userService.addUser();

        for (int i = 0; i < 5; i++) {
            UserService userService1 = (UserService) BeanFactory_v3.getBean("userService");
            System.out.println(userService1);
        }
    }
}

解决了每次都会创建对象以及获取对象时才读取配置文件的问题

2.2.2.spring的IOC解决程序耦合

创建工程
在这里插入图片描述

- 1.pom.xml
<dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.1.8.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.7.30</version>
        </dependency>
 </dependencies>
- 2.log4j.properties
log4j.rootLogger=DEBUG, stdout
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
-  3.applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<!--1、注意:要导入schema约束-->
<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">
    <!--2、把对象交给spring来创建-->
    <!--
		2、把对象交给spring来创建
       		id:给对象在容器中提供一个唯一标识。用于获取对象
		   	class:指定类的全限定类名。用于反射创建对象。默认情况下调用无参构造函数
	-->
    <bean id="userDao" class="com.by.dao.UserDaoImpl"></bean>
    <bean id="userService" class="com.by.service.UserServiceImpl"></bean>

</beans>

注意:命名无限制,约定俗成命名有:spring-context.xml、applicationContext.xml、beans.xml

  • 测试
package com.by.web;

import com.by.dao.UserDao;
import com.by.service.UserService;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.io.ClassPathResource;

public class Client {
    public static void main(String[] args) {
    //使用ApplicationContext 接口就是在Spring中获取容器
       ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
       //根据bean的id获取对象
       UserDao userDao = ac.getBean("userDao", UserDao.class);
       userDao.addUser();
       
       UserService userService = ac.getBean("userService", UserService.class);
       userService.addUser();


    }
}

2.2.3DI

  • 概述:DI(Dependency Injection)依赖注入,在Spring创建对象的同时,为其属性赋值,称之为依赖注入。
2.2.3.1构造器注入
  • 顾名思义,就是使用类中的构造函数,给成员变量赋值。注意,赋值的操作不是我们自己做的,而是通过配置的方式,让spring框架来为我们注入。具体代码如下:
package com.by.service;

import com.by.dao.UserDao;
import com.by.service.UserService;
import com.by.dao.UserDaoImpl;

/**
 * 业务层实现类
 */
public class UserServiceImpl implements UserService {

    private UserDao userDao;
    private String name;

    public UserServiceImpl() {
        System.out.println("UserServiceImpl对象创建了...");
    }
    public UserServiceImpl(UserDao userDao, String name) {
        this.userDao = userDao;
        this.name = name;

    }
    public void addUser(){
        System.out.println(name+","+age);
        userDao.addUser();
    }
}
  • applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<!--1、注意:要导入schema约束-->
<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">
    <!--2、把对象交给spring来创建-->
    <!--
		2、把对象交给spring来创建
       		id:给对象在容器中提供一个唯一标识。用于获取对象
		   	class:指定类的全限定类名。用于反射创建对象。默认情况下调用无参构造函数
	-->
    <bean id="userDao" class="com.by.dao.UserDaoImpl"></bean>
    <bean id="userService" class="com.by.service.UserServiceImpl">
<!--        构造器注入-->
<!--
     要求:类中需要提供一个对应参数列表的构造函数。
          标签:constructor-arg
               ==给谁赋值:==
				 index:指定参数在构造函数参数列表的索引位置
				 name:指定参数在构造函数中的名称
			   ==赋什么值:==
				 value:它能赋的值是基本数据类型和String类型
				 ref:它能赋的值是其他bean类型,也就是说,必须得是在配置文件中配置过的bean
        -->
        <constructor-arg name="userDao" ref="userDao"></constructor-arg>
        <constructor-arg name="name" value="666666~"></constructor-arg>
    </bean>

</beans>

2.2.3.2set注入
  • 顾名思义,就是在类中提供需要注入成员的set方法。具体代码如下:
package com.by.service;

import com.by.dao.UserDao;
import com.by.service.UserService;
import com.by.dao.UserDaoImpl;

/**
 * 业务层实现类
 */
public class UserServiceImpl implements UserService {

    private UserDao userDao;
    private String name;

    public UserServiceImpl() {
        System.out.println("UserServiceImpl对象创建了...");
    }
     public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void addUser(){
        System.out.println(userDao+"------------"+name);
        userDao.addUser();
    }
}

  • applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<!--1、注意:要导入schema约束-->
<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">
    <!--2、把对象交给spring来创建-->
    <!--
		2、把对象交给spring来创建
       		id:给对象在容器中提供一个唯一标识。用于获取对象
		   	class:指定类的全限定类名。用于反射创建对象。默认情况下调用无参构造函数
	-->
    <bean id="userDao" class="com.by.dao.UserDaoImpl"></bean>
    <bean id="userService" class="com.by.service.UserServiceImpl">
<!--        构造器注入-->
<!--
     要求:类中需要提供一个对应参数列表的set方法。
          标签:property
               ==给谁赋值:==
				 index:指定参数在构造函数参数列表的索引位置
				 name:指定参数在构造函数中的名称
			   ==赋什么值:==
				 value:它能赋的值是基本数据类型和String类型
				 ref:它能赋的值是其他bean类型,也就是说,必须得是在配置文件中配置过的bean
        -->
       <!--        SET注入-->
        <property name="userDao" ref="userDao"></property>
        <property name="name" value="浇给~~"></property>
    </bean>
</beans>

2.2.3.3自动注入
  • 不用在配置中 指定为哪个属性赋值,由spring自动根据某个 “原则” ,在工厂中查找一个bean并为属性注入值。具体代码如下:
/**
 * 业务层实现类
 */
public class UserServiceImpl implements UserService {

    private UserDao userDao;

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

    public void addUser(){
        userDao.addUser();
    }
}
<?xml version="1.0" encoding="UTF-8"?>
<!--1、注意:要导入schema约束-->
<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">
    <!--2、把对象交给spring来创建-->
    <bean id="userDao" class="com.by.dao.UserDaoImpl"></bean>
        <!--autowire="byType":按照类型自动注入值-->
    <bean id="userService" class="com.by.service.UserServiceImpl" autowire="byType">
    </bean>
</beans>
<?xml version="1.0" encoding="UTF-8"?>
<!--1、注意:要导入schema约束-->
<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">
    <!--2、把对象交给spring来创建-->
    <bean id="userDao" class="com.by.dao.UserDaoImpl"></bean>
    <!--autowire="byName":名字类型自动注入值-->
    <bean id="userService" class="com.by.service.UserServiceImpl" autowire="byName">
    </bean>
</beans>

2.3Spring中的工厂类

2.3.1ApplicationContext

  • ApplicationContext的实现类,如下图:
    在这里插入图片描述
    • ClassPathXmlApplicationContext:加载类路径下 Spring 的配置文件
    • FileSystemXmlApplicationContext:加载本地磁盘下 Spring 的配置文件

2.3.2BeanFactory

  • spring中工厂的类结构图
    在这里插入图片描述

  • 区别

  • ApplicationContext: 子接口 只要一读取配置就会创建对象

  • BeanFactory:顶级接口 是在 getBean 的时候才会创建对象。即使用对象的时候

  • ApplicationContext

/**
 * 业务层实现类
 */
public class UserServiceImpl implements UserService {

    private UserDao userDao;

    public UserServiceImpl() {
        System.out.println("UserServiceImpl对象创建了...");
    }

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

    public void addUser(){
        userDao.addUser();
    }
}
/**
 * 模拟表现层
 */
public class Client {
    public static void main(String[] args) {
        new ClassPathXmlApplicationContext("applicationContext.xml");
        System.out.println("Spring IOC容器创建好了");
    }
}
  • BeanFactory
/**
 * 业务层实现类
 */
public class UserServiceImpl implements UserService {

    private UserDao userDao;

    public UserServiceImpl() {
        System.out.println("UserServiceImpl对象创建了...");
    }

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

    public void addUser(){
        userDao.addUser();
    }
}
  /**
   * 模拟表现层
   */
  public class Client {
      public static void main(String[] args) {
          BeanFactory factory = new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));
          factory.getBean("userService", UserService.class);
          System.out.println("Spring IOC容器创建好了");
      }
  }

2.4bean的作用范围

2.4.1.概述

  • 在Spring中,bean作用域用于确定bean实例应该从哪种类型的Spring容器中返回给调用者。

2.4.2.五种作用域

  • 目前Spring Bean的作用域或者说范围主要有五种:

    作用域说明
    singleton默认值,Bean以单例方式存在spring IoC容器
    prototype每次从容器中调用Bean时都返回一个新的实例,相当于执行newInstance()
    requestWEB 项目中,Spring 创建一个 Bean 的对象,将对象存入到 request 域中
    sessionWEB 项目中,Spring 创建一个 Bean 的对象,将对象存入到 session 域中
    applicationWEB 项目中,Spring 创建一个 Bean 的对象,将对象存入到 ServletContext 域中
  • 可以通过 <bean> 标签的scope 属性控制bean的作用范围,其配置方式如下所示:

    <bean id="..." class="..." scope="singleton"/>
    
  • 需要根据场景决定对象的单例、多例模式

    单例:Service、DAO、SqlSessionFactory(或者是所有的工厂)

    多例:Connection、SqlSession

2.5bean的生命周期

2.5.1.单例bean

  • 案例
<bean id="userService" class="com.by.service.UserServiceImpl"
   scope="singleton" init-method="init" destroy-method="destroy">
/**
 * 业务层实现类
 */
public class UserServiceImpl implements UserService {

    private UserDao userDao;

    public UserServiceImpl() {
        System.out.println("调用构造方法创建bean...");
    }

    public void setUserDao(UserDao userDao) {
        System.out.println("调用set方法注入值...");
        this.userDao = userDao;
    }

    public void init(){
        System.out.println("调用init方法初始化bean...");
    }

    public void destroy(){
        System.out.println("调用destroy方法销毁bean...");
    }

    public void addUser(){
        userDao.addUser();
    }
}
/**
 * 模拟表现层
 */
public class Client {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext ac = 
        	new ClassPathXmlApplicationContext("applicationContext.xml");
        //关闭容器
        ac.close();
    }
}
[容器启动]--->构造方法(实例化)--->set方法(注入)--->init方法(初始化)--->[容器关闭]--->destroy方法(销毁)

2.5.2多例bean

<bean id="userService" class="com.by.service.UserServiceImpl"
    scope="prototype" init-method="init" destroy-method="destroy">
/**
 * 业务层实现类
 */
public class UserServiceImpl implements UserService {

    private UserDao userDao;

    public UserServiceImpl() {
        System.out.println("调用构造方法创建bean...");
    }

    public void setUserDao(UserDao userDao) {
        System.out.println("调用set方法注入值...");
        this.userDao = userDao;
    }

    public void init(){
        System.out.println("调用init方法初始化bean...");
    }

    public void destroy(){
        System.out.println("调用destroy方法销毁bean...");
    }

    public void addUser(){
        userDao.addUser();
    }
}
/**
 * 模拟表现层
 */
public class Client {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext ac = 
            	new ClassPathXmlApplicationContext("applicationContext.xml");
        //使用对象
        ac.getBean("userService");
    }
}
[使用对象]---->构造方法(实例化)--->set方法(注入)--->init方法(初始化)--->[JVM垃圾回收]--->destroy方法(销毁)
  • 20
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值