欢迎光临
我们一直在努力

【超详细】Spring 核心知识点全解析(IOC+AOP)

一、Spring 概述

1.1 Spring 介绍

Spring 是轻量级 Java EE 应用开源框架(全栈式开发框架,官网: http://spring.io ),由 Rod Johnson 创建,旨在解决企业级编程开发的复杂性。

1.2 Spring 的优点

  • IOC:解决传统 Web 开发中硬编码所造成的程序耦合(控制反转)
  • AOP:在运行期间不修改源代码对程序进行增强(切面编程)
  • 粘合剂:除自身功能外,还提供整合其他技术和框架的能力
  • 1.3 Spring 的体系结构

    Spring 框架按功能分为五大模块:

    模块分类核心功能
    Core Container(核心容器) 提供 IOC 和依赖注入特性,是框架最基础部分
    AOP、Aspects、Instrumentation(检测)、Messaging(消息处理) 提供面向切面编程实现、检测、消息处理等
    Data Access/Integration(数据访问与集成) 简化持久层操作
    Web 提供 Spring MVC 框架及与 Servlet、WebSocket 的集成
    Test 方便程序测试

    1.4 Spring 的发展历程

    • 1997 年 IBM 提出了 EJB 的思想
    • 1998 年,SUN 制定开发标准规范 EJB1.0
    • 1999 年,EJB1.1 发布
    • 2001 年,EJB2.0 发布
    • 2003 年,EJB2.1 发布Rod Johnson(spring 之父)
      • Expert One-to-One J2EE Design and Development(2002):阐述了 J2EE 使用 EJB 开发设计的优点及解决方案
      • Expert One-to-One J2EE Development without EJB(2004):阐述了 J2EE 开发不使用 EJB 的解决方式(Spring 雏形)
    • 2006 年,EJB3.0 发布
    • 2017 年 9 月发布了 Spring 的最新版本 Spring5.0 通用版
    • ……

    二、Spring IOC(重点)

    2.1 程序的耦合

    • 耦合:对象之间的依赖关系,耦合越高,维护成本越高
    • 传统开发耦合案例:没有引入 IOC 容器时系统的 Web 层、业务层、持久层存在耦合

    /**
    * 持久层实现类
    */
    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 实现类,编译失败
    • IOC (工厂模式) 解耦 步骤:
    • 把所有的 dao 和 service 对象使用配置文件配置起来
    • 当服务器启动时读取配置文件
    • 把这些对象通过反射创建出来并保存在容器(Map)中
    • 在使用的时候,直接从工厂拿

    2.2 工厂模式的 IOC 解决程序耦合

    2.2.1 什么是 IOC
    • IOC (Inverse of Control) 即控制反转:正转是自己创建依赖对象;反转是由IOC 工厂来创建依赖对象;
    • 传统方式:主动 new 创建依赖对象。

    • IOC 方式:被动从 IOC 工厂获取依赖对象。

      这种被动接收的方式获取对象的思想就是控制反转,它是 spring 框架的核心之一。

    2.2.2 工厂模式的 IOC 解耦
    • 案例一:

    /**
    * bean工厂
    */
    public class BeanFactory_v1 {

    /**
    * 获得UserServiceImpl对象
    * @return
    */
    public static UserService getUserService(){
    return new UserServiceImpl();
    }

    /**
    * 获得UserDaoImpl对象
    * @return
    */
    public static UserDao getUserDao(){
    return new UserDaoImpl();
    }
    }

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

    • 案例二:

    配置文件(bean.properties):

    properties

    #1、配置要使用的dao和service
    UserDao=com.hg.dao.UserDaoImpl
    UserService=com.hg.service.UserServiceImpl

    工厂类:

    /**
    * bean工厂
    */
    public class BeanFactory_v2 {

    private static Properties prop = new Properties();

    /**
    * 根据全类名获取bean对象
    * @param beanName
    * @return
    * @throws ClassNotFoundException
    */
    public static Object getBean(String beanName) {
    try {
    //不能使用:web工程发布后没有src目录
    //InputStream is = new FileInputStream("src/bean.properties");
    InputStream is =
    BeanFactory_v2.class.getClassLoader()
    .getResourceAsStream("bean.properties");
    prop.load(is);
    return Class.forName(prop.getProperty(beanName)).newInstance();
    } catch (Exception e) {
    e.printStackTrace();
    }
    return null;
    }

    public static void main(String[] args) {
    System.out.println(prop.get("UserService"));
    System.out.println(getBean("UserService"));
    }
    }

    业务层实现类:

    /**
    * 业务层实现类
    */
    public class UserServiceImpl implements UserService {
    private UserDao userDao = (UserDao) BeanFactory.getBean("UserDao");

    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_v2.getBean("UserService");
    System.out.println(userService);
    }
    }
    }

    问题:

  • 每次都会创建新的对象
  • 程序运行时才创建对象 (读取配置文件)
    • 案例三:

    package com.hg.factory;

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

    /**
    * bean工厂
    */
    public class BeanFactory_v3 {

    //定义一个容器,用于存放对象
    private static Map<String, Object> beans = new HashMap<>();

    /**
    * 加载配置文件
    */
    static {
    try {
    //2、读取配置文件
    //不能使用:web工程发布后没有src目录
    //InputStream is = new FileInputStream("src/bean.properties");
    InputStream is =
    BeanFactory_v3.class.getClassLoader()
    .getResourceAsStream("bean.properties");

    //3、通过反射创建对象,把对象存到容器中
    Properties prop = new Properties();
    prop.load(is);
    Set<Map.Entry<Object, Object>> entrySet = prop.entrySet();
    for (Map.Entry<Object, Object> entry : entrySet) {
    String key = entry.getKey().toString();
    String beanName = entry.getValue().toString();
    Object value = Class.forName(beanName).newInstance();
    beans.put(key, value);
    }

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

    /**
    * 4、在使用的时候,直接从工厂拿
    * @param beanName
    * @return
    */
    public static Object getBean(String beanName) {
    try {
    return beans.get(beanName);
    } catch (Exception e) {
    e.printStackTrace();
    }
    return null;
    }

    public static void main(String[] args) {
    System.out.println(getBean("UserService"));
    }
    }

    2.3 Spring 的 IOC 解决程序耦合

    2.3.1 创建工程

    2.3.1.1 pom.xml

    xml

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.hg</groupId>
    <artifactId>Spring_IOC_Xml</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
    <!– 项目源码及编译输出的编码 –>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <!– 项目编译JDK版本 –>
    <maven.compiler.source>8</maven.compiler.source>
    <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
    <!– Spring常用依赖 –>
    <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.2.8.RELEASE</version>
    </dependency>
    </dependencies>
    </project>

    注意:Jar 包彼此存在依赖,只需引入最外层 Jar 即可由 Maven 自动将相关依赖 Jar 引入到项目中。

    Spring 常用功能的 Jar 包依赖关系

    核心容器模块说明:

    • spring-beans + spring-core:提供 IOC/DI,BeanFactory(延迟加载)
    • spring-context:扩展 BeanFactory,ApplicationContext(立即加载)
    • spring-expression:Spring 表达式语言
    2.3.1.2 dao

    /**
    * 持久层实现类
    */
    public class UserDaoImpl implements UserDao {

    @Override
    public void addUser(){
    System.out.println("insert into tb_user……");
    }
    }

    2.3.1.3 service

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

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

    2.3.2 IOC
    2.3.2.1 applicationContext.xml

    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、<bean>标签作用:通过反射创建对象并交给spring的ioc容器去管理
    id:给对象在容器中提供一个唯一标识。用于获取对象
    class:指定类的全限定类名。用于反射创建对象。默认情况下调用无参构造函数
    –>
    <bean id="userDao" class="com.hg.dao.UserDaoImpl"></bean>
    <bean id="userService" class="com.hg.service.UserServiceImpl"></bean>
    </beans>

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

    2.3.2.2 测试

    运行

    /**
    * 模拟表现层
    */
    public class Client {
    public static void main(String[] args) {
    //1.使用ApplicationContext接口,就是在获取spring容器
    ApplicationContext ac = new
    ClassPathXmlApplicationContext("applicationContext.xml");
    //2.根据bean的id获取对象
    UserDao userDao = (UserDao) ac.getBean("userDao");
    System.out.println(userDao);

    UserService userService = (UserService) ac.getBean("userService");
    System.out.println(userService);
    userService.addUser();
    }
    }

    • 问题:service 层仍然耦合
    2.3.3 DI

    概述:DI(Dependency Injection)依赖注入:将依赖对象(userDao)从容器中拿出来赋值给调用者(userService)

    2.3.3.1 构造函数注入

    使用类中的构造函数,给成员变量赋值。注意,赋值的操作不是我们自己做的,而是通过配置的方式,让 spring 框架来为我们注入。具体代码如下:

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

    private UserDao userDao;
    private String name;
    private Integer age;

    public UserServiceImpl(UserDao userDao, String name, Integer age) {
    this.userDao = userDao;
    this.name = name;
    this.age = age;
    }

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

    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来创建–>
    <bean id="userDao" class="com.hg.dao.UserDaoImpl"></bean>
    <bean id="userService" class="com.hg.service.UserServiceImpl">
    <!–
    要求:类中需要提供一个对应参数列表的构造函数。
    标签:constructor-arg
    ==给谁赋值:==
    index:指定参数在构造函数参数列表的索引位置
    name:指定参数在构造函数中的名称
    ==赋什么值:==
    value:它能赋的值是基本数据类型和String类型
    ref:它能赋的值是其他bean类型,也就是说,必须得是在配置文件中配置过的bean
    –>
    <constructor-arg name="userDao" ref="userDao"></constructor-arg>
    <constructor-arg name="name" value="张三"></constructor-arg>
    <constructor-arg index="2" value="18"></constructor-arg>
    </bean>
    </beans>

    2.3.3.2 set 方法注入

    顾名思义,就是在类中提供需要注入成员的 set 方法。具体代码如下:

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

    private UserDao userDao;
    private String name;
    private Integer age;

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

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

    public void setAge(Integer age) {
    this.age = age;
    }

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

    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来创建–>
    <bean id="userDao" class="com.hg.dao.UserDaoImpl"></bean>
    <bean id="userService" class="com.hg.service.UserServiceImpl">
    <!–
    要求:必须提供set方法
    标签:property
    ==给谁赋值:==
    name:找的是类中set方法后面的部分
    ==赋什么值:==
    value:它能赋的值是基本数据类型和String类型
    ref:它能赋的值是其他bean类型,也就是说,必须得是在配置文件中配置过的bean
    –>
    <property name="userDao" ref="userDao"></property>
    <property name="name" value="张三"></property>
    <property name="age" value="18"></property>
    </bean>
    </beans>

    2.3.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

    <?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.hg.dao.UserDaoImpl"></bean>
    <!–autowire="byType":按照类型自动注入值–>
    <bean id="userService" class="com.hg.service.UserServiceImpl" autowire="byType">
    </bean>
    </beans>

    赞(0)
    未经允许不得转载:171主机测评 » 【超详细】Spring 核心知识点全解析(IOC+AOP)
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址