Singerw's Repository Singerw's Repository
首页
  • 相关文章

    • HTML相关文章
    • CSS相关文章
    • JavaScript相关文章
  • 学习笔记

    • JavaScript笔记
    • ES6笔记
    • Vue笔记
  • 相关文章

    • Spring相关文章
    • SpringBoot相关文章
    • MyBatis相关文章
    • MySQL相关文章
  • 学习笔记

    • SpringBoot笔记
    • Spring笔记
    • MyBatis笔记
    • MySQL笔记
    • JavaWeb笔记
    • JavaCore笔记
  • 学习笔记

    • Linux笔记
    • Git笔记
    • 技术文档
  • 偏门技术

    • GitHub技巧
    • 博客搭建
    • 科学上网
  • 安装教程

    • JDK
    • MySQL
    • Node.js
    • Linux
  • 终身学习
  • 面试人生
  • 心情杂货
  • 生活随笔
  • 归档
  • 标签
GitHub (opens new window)

Singerw

谁能够凭爱意将富士山私有
首页
  • 相关文章

    • HTML相关文章
    • CSS相关文章
    • JavaScript相关文章
  • 学习笔记

    • JavaScript笔记
    • ES6笔记
    • Vue笔记
  • 相关文章

    • Spring相关文章
    • SpringBoot相关文章
    • MyBatis相关文章
    • MySQL相关文章
  • 学习笔记

    • SpringBoot笔记
    • Spring笔记
    • MyBatis笔记
    • MySQL笔记
    • JavaWeb笔记
    • JavaCore笔记
  • 学习笔记

    • Linux笔记
    • Git笔记
    • 技术文档
  • 偏门技术

    • GitHub技巧
    • 博客搭建
    • 科学上网
  • 安装教程

    • JDK
    • MySQL
    • Node.js
    • Linux
  • 终身学习
  • 面试人生
  • 心情杂货
  • 生活随笔
  • 归档
  • 标签
GitHub (opens new window)
  • Spring

    • Spring5学习笔记
      • 1、Spring的优点
      • 2、为什么使用Spring?
      • 3、Spring能做什么?
      • 4、Spring核心思想
      • 5、Spring体系结构
      • 6、Spring弊端
      • 7、拓展
      • 1、理论推导
      • 2、IOC本质
      • 3、HelloSpring!
      • 4、IOC入门案例
      • 4、总结
      • 1、别名alias
      • 2、bean
      • 3、import
      • 1、Spring IOC容器解析
      • 2、ICO创建对象的方式
      • 1、构造器注入
      • 2、set注入
      • 3、拓展注入
      • 4、Bean的作用域
      • 1、测试环境搭建
      • 2、byName自动装配
      • 3、byType自动装配
      • 1、@Autowired
      • 2、@Resource注解
      • 3、@Autowired和@Resource的区别
      • 1、注解开发前提
      • 2、常用注解说明
        • 1、@Autowired
        • 2、 @Resource
        • 3、 @Nullable
        • 4、@Component
        • 5、 @Value(value = "XXX")
        • 6、@Component的衍生注解
        • 7、Scope(" singleton")
      • 3、 小结
        • XML和注解开发的区别:
        • XML和注解的最佳实践:
      • 1、AOP概念
        • 1.1 方面/切面(Aspect)
        • 1.2 连接点(Joinpoint)
        • 1.3 切入点(Pointcut)
        • 1.4 目标对象(Target Object)
        • 1.5 代理对象(AOP Proxy Object)
        • 1.6 织入(Weaving)
        • 1.7 通知类型
      • 2、基于XML的Spring AOP配置
      • 3、代理模式—静态代理
      • 4、代理模式—动态代理
        • 1、基于 applicationContext.xml 实现配置
        • 2、基于注解实现配置
        • 3、基于Java API/JavaConfig实现配置
    • Spring5-Annotation
    • Spring5-AOP
    • Spring5-IOC
  • SpringMVC

  • SSM整合

  • 《Spring》学习笔记
  • Spring
Singerw
2021-09-25

Spring5学习笔记

# 一、Spring 概述

​ Spring诞生之初,主要目的是用来替代更加重量级的企业级技术 尤其是EJB,相对于EJB来说Spring提供了更加轻量级和简单的编程模型。它增强了简单老式的Java对象POJO的功能,使其具备了之前只有EJB和其他企业级Java规范才有的功能。

# 1、Spring的优点

  • Spring是一个开源的免费的框架(容器)
  • Spring是一个轻量级、非入侵式的框架
  • 控制反转(IOC)、面向切面(AOP)
  • 支持事务处理、对框架整合的支持!

总结:Spring就是一个轻量级的控制反转(IOC)和面向切面(AOP)的框架!

非常轻量级的容器,低侵入,代码污染低。独立于各种应用服务器.DI(IOC)降低了业务对象替换复杂性

# 2、为什么使用Spring?

下面列出的是使用 Spring 框架主要的好处:

  • Spring 可以使开发人员使用 POJOs 开发企业级的应用程序。只使用 POJOs 的好处是你不需要一个 EJB 容器产品,比如一个应用程序服务器,但是你可以选择使用一个健壮的 servlet 容器,比如 Tomcat 或者一些商业产品。
  • Spring 在一个单元模式中是有组织的。即使包和类的数量非常大,你只需要选择你需要的部分,而忽略剩余的那部分。
  • Spring 不会让你白费力气做重复工作,它真正的利用了一些现有的技术,像几个 ORM 框架、日志框架、JEE、Quartz 和 JDK 计时器,其他视图技术。
  • 测试一个用 Spring 编写的应用程序很容易,因为 environment-dependent 代码被放进了这个框架中。此外,通过使用 JavaBean-style POJOs,它在使用依赖注入注入测试数据时变得更容易。
  • Spring 的 web 框架是一个设计良好的 web MVC 框架,它为 web 框架,比如 Structs 或者其他工程上的或者很少受欢迎的 web 框架,提供了一个很好的供替代的选择。
  • 为将特定技术的异常(例如,由 JDBC、Hibernate,或者 JDO 抛出的异常)翻译成一致的, Spring 提供了一个方便的 API,而这些都是未经检验的异常。
  • 轻量级的 IOC 容器往往是轻量级的,例如,特别是当与 EJB 容器相比的时候。这有利于在内存和 CPU 资源有限的计算机上开发和部署应用程序。
  • Spring 提供了一个一致的事务管理界面,该界面可以缩小成一个本地事务(例如,使用一个单一的数据库)和扩展成一个全局事务(例如,使用 JTA)。

# 3、Spring能做什么?

Spring能程序员简化开发:

  1. Spring根据配置文件来进行创建及组装对象间依赖关系(IOC),只需要改配置文件即可,无需重新编译。Spring能帮我们根据配置文件创建及组装对象之间的依赖关系。
  2. 重复业务逻辑的处理,在AOP思想中,Spring 面向切面编程能帮助我们无耦合的实现日志记录,性能统计,安全控制等。
  3. 原始的支持jdbc事务处理繁琐,Spring能非常简单的帮我们管理数据库事务。
  4. Spring还提供了与第三方ORM框架无缝集成,而且自己也提供了一套JDBC访问模板,来方便数据库访问。
  5. Spring还提供与第三方Web(如Struts、JSF)框架无缝集成,而且自己也提供了一套Spring MVC框架,来方便web层搭建。
  6. Spring能方便的与Java EE(如Java Mail、任务调度)整合,与更多技术整合(比如缓存框架)。

# 4、Spring核心思想

Spring 最核心的两个技术思想是:

  • IoC 即 Inversion of Control ,意为控制反转。

    Spring 最认同的技术是控制反转的**依赖注入(DI)**模式。控制反转(IoC)是一个通用的概念,它可以用许多不同的方式去表达,依赖注入仅仅是控制反转的一个具体的例子。

    当编写一个复杂的 Java 应用程序时,应用程序类应该尽可能的独立于其他的 Java 类来增加这些类可重用可能性,当进行单元测试时,可以使它们独立于其他类进行测试。依赖注入(或者有时被称为配线)有助于将这些类粘合在一起,并且在同一时间让它们保持独立。

    到底什么是依赖注入?让我们将这两个词分开来看一看。这里将依赖关系部分转化为两个类之间的关联。例如,类 A 依赖于类 B。现在,让我们看一看第二部分,注入。所有这一切都意味着类 B 将通过 IoC 被注入到类 A 中。

    依赖注入可以以向构造函数传递参数的方式发生,或者通过使用 setter 方法 post-construction。由于依赖注入是 Spring 框架的核心部分,所以我将在一个单独的章节中利用很好的例子去解释这一概念。

  • 面向方面的程序设计(AOP)框架

    Spring 框架的一个关键组件是**面向方面的程序设计(AOP)*框架。一个程序中跨越多个点的功能被称为*横切关注点,这些横切关注点在概念上独立于应用程序的业务逻辑。有各种各样常见的很好的关于方面的例子,比如日志记录、声明性事务、安全性,和缓存等等。

    在 OOP 中模块化的关键单元是类,而在 AOP 中模块化的关键单元是方面。AOP 帮助你将横切关注点从它们所影响的对象中分离出来,然而依赖注入帮助你将你的应用程序对象从彼此中分离出来。

    Spring 框架的 AOP 模块提供了面向方面的程序设计实现,允许你定义拦截器方法和切入点,可以实现将应该被分开的代码干净的分开功能。我将在一个独立的章节中讨论更多关于 Spring AOP 的概念。

# 5、Spring体系结构

  1. Core模块:封装了框架依赖的最底层部分,包括资源访问、类型转换及一些常用工具类。
  2. Beans模块:提供了框架的基础部分,包括反转控制和依赖注入。其中Bean Factory是容器核心(工厂),本质是“工厂设计模式”的实现,而且无需编程实现“单例设计模式”,单例完全由容器控制**,而且提倡面向接口编程,而非面向实现编程;所有应用程序对象及对象间关系由框架管理,从而真正把你从程序逻辑中把维护对象之间的依赖关系提取出来,所有这些依赖关系都由BeanFactory来维护。**
  3. Context模块:以Core和Beans为基础,集成Beans模块功能并添加资源绑定、数据验证、国际化、Java EE支持、容器生命周期、事件传播等;核心接口是ApplicationContext。
  4. EL模块:提供强大的表达式语言支持,支持访问和修改属性值,方法调用,支持访问及修改数组、容器和索引器,命名变量,支持算数和逻辑运算,支持从Spring 容器获取Bean,它也支持列表投影、选择和一般的列表聚合等。
  5. AOP模块:Spring AOP模块提供了符合 AOP Alliance规范的面向方(切)面的编程(aspect-oriented programming)实现,提供比如日志记录、权限控制、性能统计等通用功能和业务逻辑分离的技术,并且能动态的把这些功能添加到需要的代码中;这样各专其职,降低业务逻辑和通用功能的耦合。
  6. DataACCESS模块:Spring本身的 JDBC, 和其他的框架整合 ORM(Mybatis Hibernate)
  7. WEB模块: Web的部分(Spring MVC),和其他框架如:Struts2整合的部分;

# 6、Spring弊端

发展的太久了,违背的原来的理念,配置太繁琐了,简称:配置地狱!

# 7、拓展

  • Spring Boot
    • 一个快速开发的脚手架
    • 基于Spring-Boot可以快速开发单个微服务。
    • 和Maven一样、是约定大于配置。
  • Spring Cloud
    • 基于SpringBoot实现的。

现在大部分公司都在使用Spring Boot进行快速开发,学习SpringBoot的前提是需要完全掌握Spring及Spring MVC,是承上启下的作用!

# 二、Spring-IOC理论推导

# 1、理论推导

  1. UserDao接口
  2. UserDaoImpl实现类
  3. UserService业务接口
  4. UserServiceImpl业务实现类

在我们之前的业务中,用户的需求可能会影响到我们原来的代码,我们需要根据用户的需求去改写代码,修改代码量十分多,修改一次的成本与代价十分昂贵!

我们使用一个Set接口实现,就会发生革命性的变化!

package com.singerw.dao.impl;

import com.singerw.dao.UserDao;

public class UserDaoImpl implements UserDao {
    private UserDao userDao;
    //利用Set进行动态实现值得注入!
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }
}
1
2
3
4
5
6
7
8
9
10
11
  • 之前,程序是主动创建对象!控制权在程序员受伤!
  • 使用了Set注入后,程序不再具有主动权,而是变成了被动的接受对象!
  • 这种思想,从本质上解决了问题,我们程序员不用再用管理对象的创建了,系统的耦合性大大的降低,可以更加专注在业务的实现上!这就是IOC的原型!

# 2、IOC本质

控制反转IoC(Inversion of Control),是一种设计思想,DI(依赖注入)是实现IoC的一种方法,也有人认为DI只是IoC的另一种说法。没有IoC的程序中 , 我们使用面向对象编程 , 对象的创建与对象间的依赖关系完全硬编码在程序中,对象的创建由程序自己控制,控制反转后将对象的创建转移给第三方,个人认为所谓控制反转就是:获得依赖对象的方式反转了。

  • IoC是Spring框架的核心内容,使用多种方式完美的实现了IoC,可以使用XML配置,也可以使用注解,新版本的Spring也可以零配置实现IoC。
  • Spring容器在初始化时先读取配置文件,根据配置文件或元数据创建与组织对象存入容器中,程序使用时再从Ioc容器中取出需要的对象。
  • 采用XML方式配置Bean的时候,Bean的定义信息是和实现分离的,而采用注解的方式可以把两者合为一体,Bean的定义信息直接以注解的形式定义在实现类中,从而达到了零配置的目的。
  • 控制反转是一种通过描述(XML或注解)并通过第三方去生产或获取特定对象的方式。在Spring中实现控制反转的是IoC容器,其实现方法是依赖注入(Dependency Injection,DI)。

# 3、HelloSpring!

package com.singerw.pojo;

public class Hello {
    private String str;

    public String getStr() {
        return str;
    }

    public void setStr(String str) {
        this.str = str;
    }


    public Hello(String str) {
        this.str = str;
    }

    public Hello() {
    }

    @Override
    public String toString() {
        return "Hello{" +
                "str='" + str + '\'' +
                '}';
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<?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">

    <!--    使用Spring创建我们的对象
    Hello hello = new Hello();
    bean = 对象  new Hello();
    id = 变量名
    class = new 的对象
    property 相当于给对象中的属性设值。
    -->
    <bean id="hello" class="com.singerw.pojo.Hello">
        <property name="str" value="Spring"/>
    </bean>
</beans>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import com.singerw.pojo.Hello;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyTest {

    @Test
    public void Test() {
        // 获取Spring上下文的对象!
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
        //对象现在都在Spring中管理了,我们要使用,就直接去里面取出来就行了。
        Hello hello = (Hello) applicationContext.getBean("hello");
        System.out.println(hello.toString());
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

Hello{str='Spring'}

  • Hello对象是谁创建的?

hello对象是由Spring创建的

  • hello对象的属性是怎么设置的?

hello对象的属性使用Spring容器设置的

这个过程就叫做控制反转:

控制:谁来控制对象的创建,传统应用程序的对象是由程序本身控制创建的,使用Spring之后,对象是由Spring创建的

反转:程序本身不创建对象,而变成被动的接受对象。

依赖注入:就是利用set方法来进行注入的

IOC是一种编程思想,由主动的编程变成被动的接收。

不用再程序中去改动了,想要实现不同的操作,只需要再XML配置文件中进行修改,所谓的IOC,一句话搞懂就是:对象由Spring来创建,管理和装配!

# 4、IOC入门案例

# 步骤一:导入Jar包

注 : spring 需要导入commons-logging进行日志记录 . 我们利用maven , 他会自动下载对应的依赖项 .

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.1.10.RELEASE</version>
</dependency>
1
2
3
4
5

# 步骤二:编写代码

【接口】userDao.java

public interface  userDao {
    public void getUser();
}
1
2
3

【接口实现类】UserDaoImpl.java

public class UserDaoImpl implements UserDao {

    @Override
    public void getUser() {
        System.out.println("获取用户数据");
    }
}
1
2
3
4
5
6
7

【接口实现类】UserDaoMySqlImpl.java

public class UserDaoMySqlImpl implements UserDao {

    @Override
    public void getUser() {
        System.out.println("MySql获取用户数据");
    }
}
1
2
3
4
5
6
7

【接口实现类】UserDaoOracleImpl.java

public class UserDaoOracleImpl implements UserDao {

    @Override
    public void getUser() {
        System.out.println("Oracle获取用户数据");
    }
}
1
2
3
4
5
6
7

【业务层接口】UserService.java

public interface UserService {
    public void getUser();
}
1
2
3

【业务层接口】UserServiceImpl.java

public class UserServiceImpl implements UserService {

    private UserDao userDao;
    // 利用set实现
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    @Override
    public void getUser() {
        userDao.getUser();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13

【Spring配置文件】beans.xml

编写spring配置文件 , 这里我们命名为beans.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="MysqlImpl" class="com.singerw.dao.impl.UserDaoMySqlImpl"/>
    <bean id="OracleImpl" class="com.singerw.dao.impl.UserDaoOracleImpl"/>
    <bean id="ServiceImpl" class="com.singerw.service.impl.UserServiceImpl">
        <!--注意: 这里的name并不是属性 , 而是set方法后面的那部分 , 首字母小写-->
        <!--引用另外一个bean , 不是用value 而是用 ref
		ref: 引用Spring容器中创建好的对象
		value:具体的值,基本数据类型!
		-->
        <property name="userDao" ref="MysqlImpl"/>
    </bean>
</beans>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
  • ref: 引用Spring容器中创建好的对象

  • value :具体的值,基本数据类型!

【测试】MyTest.java

public void MyTest(){
    ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
    UserServiceImpl serviceImpl = (UserServiceImpl) context.getBean("ServiceImpl");
    serviceImpl.getUser();
}
1
2
3
4
5

输出:MySql获取用户数据

同理,在web.xml中改为oracle,输出就变成oracle了

<bean id="ServiceImpl" class="com.singerw.service.impl.UserServiceImpl">
    <!--注意: 这里的name并不是属性 , 而是set方法后面的那部分 , 首字母小写-->
    <!--引用另外一个bean , 不是用value 而是用 ref-->
    <property name="userDao" ref="Oracle"/>
</bean>
1
2
3
4
5

输出:Oracle获取用户数据

# 4、总结

所谓的IOC,就是对象由Spring创建、管理、装配!

# 三、Spring配置

# 1、别名alias

<alias name="userT" alias="userNew"/>
1

# 2、bean

<bean id="hello" name="hello2 h2,h3;h4" class="com.kuang.pojo.Hello">

    <property name="name" value="Spring"/>

</bean>
1
2
3
4
5
  • bean就是java对象,由Spring创建和管理
  • id 是bean的标识符,要唯一,如果没有配置id,name就是默认标识符
  • 如果配置id,又配置了name,那么name是别名
  • name可以设置多个别名,可以用逗号,分号,空格隔开
  • 如果不配置id和name,可以根据applicationContext.getBean(.class)获取对象,class是bean的全限定名=包名+类名

# 3、import

<import resource="{path}/beans.xml"/>
1

团队的合作通过import来实现 .

使用 @Bean、@Component、@Import 注解注册 Spring Bean。

这个import,一般用户团队开发使用,他可以将多个配置文件,导入合并为一个

假设,现在项目中有多个人同时开发,这桑耳复制不用的类开发,不同的类需要注册不同的bean中,我们可以利用import将所有人的beans.xml合并为一个总的!

  • 张三 zhangsan.xml
  • 李四 lisi.xml
  • 王五 wangwu.xml
  • applicationContext.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">
  
    <import resource="zhangsan.xml"></import>
    
    <import resource="lisi.xml"></import>
    
    <import resource="wangwu.xml"></import>
    
</beans>
1
2
3
4
5
6
7
8
9
10
11
12

使用的时候,使用总的配置文件xml就可以了,会自动合并xml和xml中重名的配置。

# 四、Spring-IOC

控制反转(IOC),不是什么技术,而是一种设计思想,其作用是实例化具体的bean,动态装配bean。

  • 类的一些属性: (例如UserService中的userDao成员属性)是由当前类(UserService)自己控制其实例化,现在不是由当前类(UserService)自己控制。现在Spring是利用接口来控制的。由原来控制实现转为spring现在来控制接口(向上反转).
  • 我们可以使用xml或者注解来进行相关配置,spring会根据配置和约定,对独享进行实例化和属性装配。

好处:IOC是Spring的核心机制,可以使Spring的bean以配置文件组织在一起,而不是硬编码方式耦合,耦合性相对来降低了;另外,注入是使用配置文件来实现,这样修改来非常的方便。

# 1、Spring IOC容器解析

​ Spring Ioc容器的代表就是org.springframework.beans包中的BeanFactory接口,BeanFactory接口提供了IoC容器最基本功能;而org.springframework.context包下的ApplicationContext接口扩展了BeanFactory,还提供了与Spring AOP集成、国际化处理、事件传播及提供不同层次的context实现 (如针对web应用的WebApplicationContext)。简单说, BeanFactory提供了IoC容器最基本功能,而 ApplicationContext 则增加了更多支持企业级功能支持。ApplicationContext完全继承BeanFactory,因而BeanFactory所具有的语义也适用于ApplicationContext。

# 2、ICO创建对象的方式

1、使用无参构造创建对象,默认!

public class User {

    private String name;
    public User() {
        System.out.println("user无参构造方法");
    }

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

    public void show(){
        System.out.println("name="+ name );
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

user无参构造方法

2、假设要使用有参构造创建对象!

public class UserT {

    private String name;

    public User() {
        System.out.println("user无参构造方法");
    }

    public UserT(String name) {
        this.name = name;
    }

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

    public void show(){
        System.out.println("name="+ name );
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
  • 下标赋值
<!-- 第一种根据index参数下标设置 -->

<bean id="userT" class="com.singerw.pojo.User">
    <!-- index指构造方法 , 下标从0开始 -->
    <constructor-arg index="0" value="singerw"/>
</bean>
1
2
3
4
5
6
  • 类型赋值【不推荐使用】
<bean id="userT" class="com.singerw.pojo.User">
    <!-- name指参数名 -->
    <constructor-arg name="name" value="singerw"/>
</bean>
1
2
3
4
  • 参数名赋值【重点掌握】
<!-- 第三种根据参数类型设置 -->
<bean id="userT" class="com.singerw.pojo.User">
    <constructor-arg type="java.lang.String" value="singerw"/>
</bean>
1
2
3
4

结论:配置文件中创建bean后,在配置文件加载的时候。其中管理的对象都已经初始化了!

# 五、DI依赖注入

​ 依赖注入是一种消除类之间依赖关系的设计模式。例如,A类要依赖B类,A类不再直接创建B类,而是把这种依赖关系配置在外部xml文件(或java config文件)中,然后由Spring容器根据配置信息创建、管理bean类。

  • 依赖注入(Dependency Injection,DI)
  • 依赖 : 指Bean对象的创建依赖于容器 . Bean对象的依赖资源
  • 注入 : 指Bean对象所依赖的资源 , 由容器来设置和装配

# 1、构造器注入

<bean id="p" class="com.singerw.entity.Person">
    <constructor-arg index="0" type="java.lang.String" value="singerw"></constructor-arg>
    <constructor-arg index="1" type="java.lang.Integer" value="18"></constructor-arg>
    <constructor-arg index="2" type="java.lang.Integer" value="男"></constructor-arg>
</bean>
1
2
3
4
5

# 2、set注入

<bean id="address" class="com.singew.pojo.Address"></bean>
<bean id="student" class="com.singew.pojo.Student">
    <!--第一种,普通值的注入,value-->
    <property name="name" value="张欣"></property>

    <!--第二种,Bean注入,ref-->
    <property name="address" ref="address"/>

    <!--第三种,数组的注入-->
    <property name="books">
        <array>
            <value>红楼梦</value>
            <value>西游记</value>
            <value>三国演义</value>
            <value>水浒传</value>
        </array>
    </property>

    <!--第四种,List注入-->
    <property name="hobbys">
        <list>
            <value>听歌</value>
            <value>掉代码</value>
            <value>看电影</value>
        </list>
    </property>

    <!--第五种,Map注入-->
    <property name="card">
        <map>
            <entry key="key" value="value"/>
            <entry key="身份证" value="5464556454645651415"/>
            <entry key="银行卡" value="8795461525678954645459845415"/>
        </map>
    </property>

    <!--第六种,Set注入-->
    <property name="games">
        <set>
            <value>LOL英雄联盟</value>
        </set>
    </property>

    <!--第七种,props空值注入-->
    <property name="wife" value=""/>

    <property name="info">
        <props>
            <prop key="学号">20171649</prop>
            <prop key="性别">男</prop>
            <prop key="姓名">小明</prop>
        </props>
    </property>
</bean>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54

# 3、拓展注入

  • P命名空间

导入约束 : xmlns:p="http://www.springframework.org/schema/p"

<!--P(属性: properties)命名空间 , 属性依然要设置set方法-->
<bean id="user" class="com.singerw.pojo.User" p:name="singerw" p:age="18"/>
1
2
  • C命名空间

导入约束 : xmlns:p="http://www.springframework.org/schema/p"

<!--C(构造: Constructor)命名空间 , 属性依然要设置set方法-->
<bean id="user" class="com.singerw.pojo.User" c:name="singerw" c:age="18"/>
1
2

发现问题:爆红了,是因为要写有参构造!

解决:把有参构造器加上,这里也能知道,c 就是所谓的构造器注入!

# 4、Bean的作用域

  • Singleton

当一个bean的作用域为Singleton,那么Spring IoC容器中只会存在一个共享的bean实例,并且所有对bean的请求,只要id与该bean定义相匹配,则只会返回bean的同一实例。Singleton是单例类型,就是在创建起容器时就同时自动创建了一个bean的对象,不管你是否使用,他都存在了,每次获取到的对象都是同一个对象。注意,Singleton作用域是Spring中的缺省作用域。要在XML中将bean定义成singleton,可以这样配置:

 <bean id="ServiceImpl" class="com.singerw.service.ServiceImpl" scope="singleton">
1
@Test

public void MyTest(){
    ApplicationContext context = newClassPathXmlApplicationContext("applicationContext.xml");
    User user1 = (User) context.getBean("user");
    User user2 = (User) context.getBean("user");
    System.out.println(user1==user2);
}
1
2
3
4
5
6
7
8

true

  • Prototype

当一个bean的作用域为Prototype,表示一个bean定义对应多个对象实例。Prototype作用域的bean会导致在每次对该bean请求(将其注入到另一个bean中,或者以程序的方式调用容器的getBean()方法)时都会创建一个新的bean实例。Prototype是原型类型,它在我们创建容器的时候并没有实例化,而是当我们获取bean的时候才会去创建一个对象,而且我们每次获取到的对象都不是同一个对象。根据经验,对有状态的bean应该使用prototype作用域,而对无状态的bean则应该使用singleton作用域。在XML中将bean定义成prototype,可以这样配置:

<bean id="account" class="com.foo.DefaultAccount" scope="prototype"/>  
1

或者

<bean id="account" class="com.foo.DefaultAccount" singleton="false"/>
1

测试:

@Test

public void MyTest(){
    ApplicationContext context = newClassPathXmlApplicationContext("applicationContext.xml");
    User user1 = (User) context.getBean("user");
    User user2 = (User) context.getBean("user");
    System.out.println(user1==user2);
}
1
2
3
4
5
6
7
8

flase

  • Request

当一个bean的作用域为Request,表示在一次HTTP请求中,一个bean定义对应一个实例;即每个HTTP请求都会有各自的bean实例,它们依据某个bean定义创建而成。该作用域仅在基于web的Spring ApplicationContext情形下有效。考虑下面bean定义:

 <bean id="loginAction" class=com.singerw.LoginAction" scope="request"/>
1

针对每次HTTP请求,Spring容器会根据loginAction bean的定义创建一个全新的LoginAction bean实例,且该loginAction bean实例仅在当前HTTP request内有效,因此可以根据需要放心的更改所建实例的内部状态,而其他请求中根据loginAction bean定义创建的实例,将不会看到这些特定于某个请求的状态变化。当处理请求结束,request作用域的bean实例将被销毁。

  • Session

当一个bean的作用域为Session,表示在一个HTTP Session中,一个bean定义对应一个实例。该作用域仅在基于web的Spring ApplicationContext情形下有效。考虑下面bean定义:

<bean id="userPreferences" class="com.singerw.UserPreferences" scope="session"/>
1

针对某个HTTP Session,Spring容器会根据userPreferences bean定义创建一个全新的userPreferences bean实例,且该userPreferences bean仅在当前HTTP Session内有效。与request作用域一样,可以根据需要放心的更改所创建实例的内部状态,而别的HTTP Session中根据userPreferences创建的实例,将不会看到这些特定于某个HTTP Session的状态变化。当HTTP Session最终被废弃的时候,在该HTTP Session作用域内的bean也会被废弃掉。

# 六、Bean的自动装配

自动装配说明:

  • 自动装配是使用spring满足bean依赖的一种方法
  • spring会在应用上下文中为某个bean寻找其依赖的bean。
  • 自动装配是Spring满足bean依赖的一种方式
  • Spring会在上下文中自动寻找,并且自动给bean装配属性!

Spring中bean有三种装配机制,分别是:

  • 在xml中显式配置;

  • 在java中显式配置;

  • 隐式的bean发现机制和自动装配。

这里我们主要讲第三种:

自动化的装配bean。Spring的自动装配需要从两个角度来实现,或者说是两个操作:

  1. 组件扫描(component scanning):spring会自动发现应用上下文中所创建的bean;
  2. 自动装配(autowiring):spring自动满足bean之间的依赖,也就是我们说的IoC/DI;

组件扫描和自动装配组合发挥巨大威力,使得显示的配置降低到最少。

**推荐不使用自动装配xml配置 , 而使用注解 **

# 1、测试环境搭建

【实体类】Cat.java Dog.java User.java

public class Cat {

    public void shout() {
        System.out.println("miao~");
    }
}
1
2
3
4
5
6
public class Dog {

    public void shout() {
        System.out.println("wang~");
    }
}
1
2
3
4
5
6
public class User {

    private Cat cat;
    private Dog dog;
    private String str;
}
1
2
3
4
5
6

【Spring配置文件】applicationContext.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="dog" class="com.singerw.pojo.Dog"/>
    <bean id="cat" class="com.singerw.pojo.Cat"/>
    <bean id="user" class="com.singerw.pojo.User">
        <property name="cat" ref="cat"/>
        <property name="dog" ref="dog"/>
        <property name="str" value="singerw.com"/>
    </bean>
</beans>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

【测试】UserTest.java

public class MyTest {

    @Test
    public void testMethodAutowire() {
        ApplicationContext context = newClassPathXmlApplicationContext("beans.xml");
        User user = (User) context.getBean("user");
        user.getCat().shout();
        user.getDog().shout();
    }
}
1
2
3
4
5
6
7
8
9
10

wang~

miao~

结果正常输出,环境OK

# 2、byName自动装配

autowire byName (按名称自动装配)

由于在手动配置xml过程中,常常发生字母缺漏和大小写等错误,而无法对其进行检查,使得开发效率降低。

采用自动装配将避免这些错误,并且使配置简单化。

<bean id="user" class="com.singerw.pojo.User" autowire="byName">
    <property name="str" value="singerw.com"/>
</bean>
1
2
3

wang~

miao~

再次测试,结果依旧成功输出!

小结:

当一个bean节点带有 autowire byName的属性时。

  1. 将查找其类中所有的set方法名,例如setCat,获得将set去掉并且首字母小写的字符串,即cat。
  2. 去spring容器中寻找是否有此字符串名称id的对象。
  3. 如果有,就取出注入;如果没有,就报空指针异常。

# 3、byType自动装配

autowire byType (按类型自动装配)

使用autowire byType首先需要保证:同一类型的对象,在spring容器中唯一。如果不唯一,会报不唯一的异常。

<bean id="dog" class="com.singerw.pojo.Dog"/>
<bean id="cat" class="com.singerw.pojo.Cat"/>
<bean id="cat2" class="com.singerw.pojo.Cat"/>
<bean id="user" class="com.singerw.pojo.User" autowire="byType">
    <property name="str" value="singerw.com"/>
</bean>
1
2
3
4
5
6

测试,报错:NoUniqueBeanDefinitionException

删掉cat2,将cat的bean名称改掉!测试!因为是按类型装配,所以并不会报异常,也不影响最后的结果。甚至将id属性去掉,也不影响结果。

<bean class="com.singerw.pojo.Dog"/>
<bean class="com.singerw.pojo.Cat"/>
<bean id="user" class="com.singerw.pojo.User" autowire="byType">
    <property name="str" value="singerw.com"/>
</bean>
1
2
3
4
5

这就是按照类型自动装配!

# 七、Annotation注解实现自动装配

要使用注解前提须知:

  • 导入约束:xmlns:context="http://www.springframework.org/schema/context"

  • 配置开启注解的支持:

<!--配置开启注解的支持-->
<context:annotation-config></context:annotation-config>
1
2

# 1、@Autowired

  • 直接在属性上
  • 也可以在Set方式上使用。
  • 使用@Autowired 我们可以不用编写Set方法了,前提是这个自动装配的属性在IOC容器中存在,且符合名字ByName

如果显示的定义了@Autowired (required = false)说明这个对象可以为null,否则不容许为空!

public class UsersEntity {
    @Autowired(required = false)
    private String username;
}
1
2
3
4

如果@Autowired 自动装配的环境比较复杂,自动装配无法通过一个注解【@Autowired 】完成的时候,我们可以使用@Qualifier(value = "zx")去配合@Autowired的使用,指定一个唯一的bean对象注入!

public class UsersEntity {
    @Qualifier(value = "singerw.com")
    private String username;
}
1
2
3
4

# 2、@Resource注解

@Resource默认通过ByName的方式实现,如果找不到名字,则通过byType实现,如果两个都找不到的情况下,就会报错

public class UsersEntity {
    @Resource(value = "singerw.com")
    private String username;
}
1
2
3
4

# 3、@Autowired和@Resource的区别

  • 都是用来自动装配的,都可以放在属性的字段上。
  • @Autowired 都过ByType的方式实现,而且必须要去这个对象存在,不然就会空指针异常!【常用的】
  • @Resource默认通过ByName的方式实现,如果找不到名字,则通过byType实现,如果两个都找不到的情况下,就会报错!

# 八、Spring使用注解开发

# 1、注解开发前提

注意点1:在Spring4后,要使用注解开发,必须要保证导入spring-aop的jar包

<!--依赖注入包-->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aop</artifactId>
    <version>5.3.6</version>
</dependency>
1
2
3
4
5
6

注意点2:在Spring4后,要使用注解开发,必须要保证让注解生效,就需要开启注解的支持!

<!--注解的支持-->
<context:annotation-config/>
1
2

注意点3:设置组件的扫描路径,指定要扫描的包,这个包下的注解就会生效

<!--指定要扫描的包,这个包下的注解就会生效-->
<context:component-scan base-package="com.singerw"/>
1
2

# 2、常用注解说明

# 1、@Autowired

自动装配通过类型,名字。

如果@Autowired 自动装配的环境比较复杂,自动装配无法通过一个注解【@Autowired 】完成的时候,我们可以使用@Qualifier(value = "zx")去配合@Autowired的使用,指定一个唯一的bean对象注入!

# 2、 @Resource

自动装配通过名字。类型

# 3、@Nullable

字段标记了这个注解,说明这个字段可以为null

# 4、@Component

组件。放在类上,说明这个类被Spring管理了。就是bean注入!

相当于<bean id="address" class="com.singew.pojo.Address"></bean>

# 5、 @Value(value = "XXX")

给值注解,相当于<property name="name" value="张欣"></property>

也可以放在set方法上

# 6、@Component的衍生注解

我们在web开发中,通常会采用MVC三层架构分层,所有每层的注解都不一样,但是作用都一样。

  • # @Component

  • # dao:@Repository(value = "usersDao")

  • # service:@Service(value = "usersService")

  • # controller:@Controller

  • # controller:@RestController

这四个注解的功能都是一样的。都是代表将类注册到Spring容器中,装配Bean。

# 7、Scope(" singleton")

关于作用域的注解,可以设置Scope(" singleton")单例模式和Scope(" prototype")原型模式

# 3、 小结

# XML和注解开发的区别:

  • XML更加万能,适合于任何场合,维护简单!
  • 注解不是自己类使用不了,维护比较复杂!

# XML和注解的最佳实践:

一般来说,XML和注解的最佳实践,就是用XML来管理bean,用注解来完成属性的注入!

# 九、Spring-AOP

  • 面向切面的程序设计框架

Aspect Oriented Programming(面向切面编程或面向方面编程)

  • AOP:Aspect Oriented Programming(面向切面编程或面向方面编程),是一种编程范式,提供从另一个角度来考虑程序结构从而完善面向对象编程(OOP)。
  • AOP为开发者提供一种进行横切关注点(比如日志关注点横切了支付关注点)分离并织入的机制,把横切关注点分离,然后通过某种技术织入到系统中,从而无耦合的完成了我们的功能。
  • 面向切面的编程和面向对象并不矛盾,是对面向对象的思维方式的有效补充。主要将程序中涉及公共问题集中解决,可以解决面向对象和过程化方法中不能很好解决的横切问题如:事务,安全,日志,异常处理等横切关注。

# 1、AOP概念

# 1.1 方面/切面(Aspect)

​ 方面/切面(Aspect)是切面的具体实现,在连接点上执行的行为,通知提供了在AOP中需要在切入点所选择的连接点处进行扩展现有行为的手段。以目标方法为参照点,根据放置的地方不同,可分为前置通知(Before)、后置通知(AfterReturning)、异常通知(AfterThrowing)、最终通知(After)与环绕通知(Around)5种。在实际应用中通常是切面类中的一个方法,具体属于哪类通知,同样是在配置中指定的。做什么?

# 1.2 连接点(Joinpoint)

​ 连接点(Joinpoint)表示需要在程序中插入横切关注点的扩展点,连接点可能是类初始化、方法执行、方法调用、字段调用或处理异常等等. 在哪里(很多可以连接的部分)做什么?

# 1.3 切入点(Pointcut)

​ 选择一组相关连接点的模式,即可以认为连接点的集合,Spring支持perl5正则表达式和AspectJ切入点模式,Spring默认使用AspectJ语法,在AOP中表示为“在哪里(确定下来)做的集合”.

# 1.4 目标对象(Target Object)

​ 需要被织入横切关注点的对象,即该对象是切入点选择的对象,需要被通知的对象,从而也可称为“被通知对象”;由于Spring AOP 通过代理模式实现,从而这个对象永远是被代理对象.对谁做这件事?

# 1.5 代理对象(AOP Proxy Object)

​ AOP框架使用代理模式创建的对象,从而实现在连接点处插入通知(即应用切面),就是通过代理来对目标对象应用切面。在Spring中,AOP代理可以用**JDK动态代理【返回接口实例】或CGLIB[可以是类实例]**代理实现,而通过拦截器模型应用切面。

# 1.6 织入(Weaving)

​ 将切面应用到目标对象从而创建一个新的代理对象的过程。这个过程可以发生在编译期、类装载期及运行期,当然不同的发生点有着不同的前提条件。譬如发生在编译期的话,就要求有一个支持这种AOP实现的特殊编译器;发生在类装载期,就要求有一个支持AOP实现的特殊类装载器;只有发生在运行期,则可直接通过Java语言的反射机制与动态代理机制来动态实现。

# 1.7 通知类型

  • 前置通知(Before Advice):在切入点选择的连接点处的方法之前执行的通知,该通知不影响正常程序执行流程(除非该通知抛出异常,该异常将中断当前方法链的执行而返回)。
  • 后置通知(After Advice): 在切入点选择的连接点处的方法之后执行的通知,包括如下类型的后置通知:
  • 后置返回通知(After returning Advice):在切入点选择的连接点处的方法正常执行完毕时执行的通知,必须是连接点处的方法没抛出任何异常正常返回时才调用后置通知。
  • 后置异常通知(After throwing Advice): 在切入点选择的连接点处的方法抛出异常返回时执行的通知,必须是连接点处的方法抛出任何异常返回时才调用异常通知。
  • 后置最终通知(After finally Advice): 在切入点选择的连接点处的方法返回时执行的通知,不管抛没抛出异常都执行,类似于Java中的finally块。
  • 环绕通知(Around Advices):环绕着在切入点选择的连接点处的方法所执行的通知,环绕通知可以在方法调用之前和之后自定义任何行为,并且可以决定是否执行连接点处的方法、替换返回值、抛出异常等.

# 2、基于XML的Spring AOP配置

# 3、代理模式—静态代理

代理模式是SpringAOP的底层!【SpringAOP和SpringMVC面试必问】

优点:业务类只需要关注业务逻辑本身,保证了业务类的重用性。这是代理的共有优点。 缺点:

  • 代理对象的一个接口只服务于一种类型的对象,如果要代理的方法很多,势必要为每一种方法都进行代理,静态代理在程序规模稍大时就无法胜任了。
  • 如果接口增加一个方法,除了所有实现类需要实现这个方法外,所有代理类也需要实现此方法。增加了代码维护的复杂度。

# 4、代理模式—动态代理

代理模式是SpringAOP的底层!【SpringAOP和SpringMVC面试必问】

Spring默认使用动态代理,要使用静态代理需要在XML中配置。

# 十三、Spring 提供了哪些IOC容器配置方式?

# 1、基于 applicationContext.xml实现配置

bean 所需的依赖项和服务在XML格式的配置文件中指定。这些配置文件通常包含许多bean定义和特定于应用程序的配置选项。它们通常以bean` 标签开头。

【例如】:

<bean id="address" class="com.singew.pojo.Address"></bean>
<bean id="student" class="com.singew.pojo.Student">
    <!--第一种,普通值的注入,value-->
    <property name="name" value="张欣"></property>

    <!--第二种,Bean注入,ref-->
    <property name="address" ref="address"/>

    <!--第三种,数组的注入-->
    <property name="books">
        <array>
            <value>红楼梦</value>
            <value>西游记</value>
            <value>三国演义</value>
            <value>水浒传</value>
        </array>
    </property>

    <!--第四种,List注入-->
    <property name="hobbys">
        <list>
            <value>听歌</value>
            <value>掉代码</value>
            <value>看电影</value>
        </list>
    </property>

    <!--第五种,Map注入-->
    <property name="card">
        <map>
            <entry key="key" value="value"/>
            <entry key="身份证" value="5464556454645651415"/>
            <entry key="银行卡" value="8795461525678954645459845415"/>
        </map>
    </property>

    <!--第六种,Set注入-->
    <property name="games">
        <set>
            <value>LOL英雄联盟</value>
        </set>
    </property>

    <!--第七种,props空值注入-->
    <property name="wife" value=""/>

    <property name="info">
        <props>
            <prop key="学号">20171649</prop>
            <prop key="性别">男</prop>
            <prop key="姓名">小明</prop>
        </props>
    </property>
</bean>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54

# 2、基于注解实现配置

可以通过在相关的类,方法或字段声明上使用注解,将 bean 配置为组件类本身,而不是使用XML 来描述 bean 装配。默认情况下,Spring容器中未打开注解装配。因此,需要在使用它之前在Spring配置文件中启用它。

【例如】:

<!--注解的支持-->
<context:annotation-config></context:annotation-config>
1
2
@Repository
public class BlogDaoImpl implements BlogDao {

    @Override
    public PageData getBlogList(int page, int pageSize) {
        String sql = "SELECT g_article.* FROM g_article WHERE acticle_status = 1";
        return DBUtil.exQueryByPage(sql, BlogEntity.class, page, pageSize);
    }
}
1
2
3
4
5
6
7
8
9

# 3、基于Java API/JavaConfig实现配置

完全使用Java的方式配置Spring,年轻人喜欢这么玩,上了年龄的程序员不想瞎搞。但以后看到Spring开源项目,这么没有bean,怎么没有xml?别说这不是Spring的,丢人了。

Spring 的 Java 配置是通过使用 @Bean 和 @Configuration 来实现。

  1. @Bean 注解扮演与<bean /> 元素相同的角色。
  2. @Configuration 类允许通过简单地调用同一个类中的其他 @Bean 方法来定义 bean 间依赖关系。

【例如】:

UserEntity:

@Component
public class UserEntity {
    private String name;

    public String getName() {
        return name;
    }

    @Value("张欣")
    public void setName(String name) {
        this.name = name;
    }

    public UserEntity() {
    }

    public UserEntity(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "UserEntity{" +
            "name='" + name + '\'' +
            '}';
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

SingerwConfig:

@Configuration
public class SingerwConfig {

    @Bean
    public UserEntity getUser(){
        return new UserEntity();
    }
}
1
2
3
4
5
6
7
8

TestUser:

public class TestUser {
    @Test
    public void getUserTest() {
        ApplicationContext context = new AnnotationConfigApplicationContext(SingerwConfig.class);
        UserEntity getUser = context.getBean("getUser", UserEntity.class);
        System.out.println(getUser.getName());
    }
}
1
2
3
4
5
6
7
8
编辑 (opens new window)
#Spring
Spring5-Annotation

Spring5-Annotation→

最近更新
01
Maven资源导出问题终极版
10-12
02
《MyBatis-Plus》学习笔记
10-07
03
MyBatis-Plus—配置日志
10-07
更多文章>
Theme by Vdoing | Copyright © 2020-2021 版权所有 | repository.singerw.com
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式
×