spring学习

1,spring

Spring中国教育管理中心

Spring认证概述

Spring认证框架是一个开放源代码的J2EE应用程序框架,由Rod Johnson发起,是针对bean的生命周期进行管理的轻量级容器(lightweight container)。 [1] Spring是Java EE编程领域的一个轻量级开源框架,该框架由一个叫Rod Johnson的程序员在 2002 年最早提出并随后创建,是为了解决企业级编程开发中的复杂性,实现敏捷开发的应用型框架 。 [2]

教育中心概述

2021年2月,VMware公司授权北京中科卓望网络科技有限公司正式成为VMware Tunzu Spring中国教育管理中心,负责Spring国际认证体系标准在中国教育行业的推广工作。 [3]

Spring框架是由于[软件开发](https://baike.baidu.com/item/软件开发/3448966)的复杂性而创建的。Spring使用的是基本的JavaBean来完成以前只可能由[EJB](https://baike.baidu.com/item/EJB/144195)完成的事情。然而,Spring的用途不仅仅限于服务器端的开发。从简单性、可测试性和松耦合性角度而言,绝大部分Java应用都可以从Spring中受益。

Spring的形成,最初来自Rod Jahnson所著的一本很有影响力的书籍《Expert One-on-One J2EE Design and Development》,就是在这本书中第一次出现了Spring的一些核心思想,该书出版于2002年。另外一本书《Expert One-on-One J2EE Development without EJB》,更进一步阐述了在不使用EJB开发JAVA EE企业级应用的一些设计思想和具体的做法。

Spring的初衷:

1、JAVA EE开发应该更加简单。

2、使用接口而不是使用类,是更好的编程习惯。Spring将使用接口的复杂度几乎降低到了零。

3、为JavaBean提供了一个更好的应用配置框架。

4、更多地强调[面向对象](https://baike.baidu.com/item/面向对象)的设计,而不是现行的技术如JAVA EE。

5、尽量减少不必要的异常捕捉。

6、使应用程序更加容易测试。

Spring的目标:

1、可以令人方便愉快的使用Spring。

2、应用程序代码并不依赖于Spring APIs。

3、Spring不和现有的解决方案竞争,而是致力于将它们融合在一起。

Spring的基本组成:

1、最完善的轻量级核心框架。

2、通用的事务管理抽象层。

3、JDBC抽象层。

4、集成了Toplink, Hibernate, JDO, and iBATIS SQL Maps。

5、AOP功能。

6、灵活的MVC Web应用框架。

优点

◆JAVA EE应该更加容易使用。

◆面向对象的设计比任何实现技术(比如JAVA EE)都重要。

◆[面向接口编程](https://baike.baidu.com/item/面向接口编程/6025286),而不是针对类编程。Spring将使用接口的复杂度降低到零。(面向接口编程有哪些复杂度?)

◆代码应该易于测试。Spring框架会帮助你,使代码的测试更加简单。

◆JavaBean提供了应用程序配置的最好方法。

◆在Java中,已检查异常(Checked exception)被过度使用。框架不应该迫使你捕获不能恢复的异常。

简介

2002年:首次推出了Spring框架的雏形:interface 21 框架

Spring:

Spring是一个开源框架,它由[Rod Johnson](https://baike.baidu.com/item/Rod Johnson)创建。它是为了解决企业应用开发的复杂性而创建的。Spring使用基本的JavaBean来完成以前只可能由EJB完成的事情。然而,Spring的用途不仅限于服务器端的开发。从简单性、可测试性和松耦合的角度而言,任何Java应用都可以从Spring中受益。

Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架。

轻量——从大小与开销两方面而言Spring都是轻量的。完整的Spring框架可以在一个大小只有1MB多的JAR文件里发布。并且Spring所需的处理开销也是微不足道的。此外,Spring是非侵入式的:典型地,Spring应用中的对象不依赖于Spring的特定类。

控制反转——Spring通过一种称作控制反转(IoC)的技术促进了松耦合。当应用了IoC,一个对象依赖的其它对象会通过被动的方式传递进来,而不是这个对象自己创建或者查找依赖对象。你可以认为IoC与JNDI相反——不是对象从容器中查找依赖,而是容器在对象初始化时不等对象请求就主动将依赖传递给它。

面向切面——Spring提供了[面向切面编程](https://baike.baidu.com/item/面向切面编程)的丰富支持,允许通过分离应用的业务逻辑与系统级服务(例如审计(auditing)和事务(transaction)管理)进行内聚性的开发。应用对象只实现它们应该做的——完成业务逻辑——仅此而已。它们并不负责(甚至是意识)其它的系统级关注点,例如日志或事务支持。

容器——Spring包含并管理应用对象的配置和生命周期,在这个意义上它是一种容器,你可以配置你的每个bean如何被创建——基于一个可配置原型(prototype),你的bean可以创建一个单独的实例或者每次需要时都生成一个新的实例——以及它们是如何相互关联的。然而,Spring不应该被混同于传统的重量级的EJB容器,它们经常是庞大与笨重的,难以使用。

框架——Spring可以将简单的组件配置、组合成为复杂的应用。在Spring中,应用对象被声明式地组合,典型地是在一个XML文件里。Spring也提供了很多基础功能(事务管理、持久化框架集成等等),将应用逻辑的开发留给了你。

所有Spring的这些特征使你能够编写更干净、更可管理、并且更易于测试的代码。它们也为Spring中的各种模块提供了基础支持。

Spring框架由七个定义明确的模块组成(图1.1)。

img

(Spring框架概览图1.1)

如果作为一个整体,这些模块为你提供了开发企业应用所需的一切。但你不必将应用完全基于Spring框架。你可以自由地挑选适合你的应用的模块而忽略其余的模块。

就像你所看到的,所有的Spring模块都是在核心容器之上构建的。容器定义了Bean是如何创建、配置和管理的——更多的Spring细节。当你配置你的应用时,你会潜在地使用这些类。但是作为一名开发者,你最可能对影响容器所提供的服务的其它模块感兴趣。这些模块将会为你提供用于构建应用服务的框架,例如AOP和持久性。

核心容器

这是Spring框架最基础的部分,它提供了依赖注入(DependencyInjection)特征来实现容器对Bean的管理。这里最基本的概念是BeanFactory,它是任何Spring应用的核心。BeanFactory是工厂模式的一个实现,它使用IoC将应用配置和依赖说明从实际的应用代码中分离出来。

应用上下文(Context)模块

核心模块的BeanFactory使Spring成为一个容器,而上下文模块使它成为一个框架。这个模块扩展了BeanFactory的概念,增加了对国际化(I18N)消息、事件传播以及验证的支持。

另外,这个模块提供了许多企业服务,例如电子邮件、JNDI访问、EJB集成、远程以及时序调度(scheduling)服务。也包括了对模版框架例如Velocity和FreeMarker集成的支持。

Spring的AOP模块

Spring在它的AOP模块中提供了对面向切面编程的丰富支持。这个模块是在Spring应用中实现切面编程的基础。为了确保Spring与其它AOP框架的互用性,Spring的AOP支持基于AOP联盟定义的API。AOP联盟是一个开源项目,它的目标是通过定义一组共同的接口和组件来促进AOP的使用以及不同的AOP实现之间的互用性。通过访问他们的站点,你可以找到关于AOP联盟的更多内容。

Spring的AOP模块也将元数据编程引入了Spring。使用Spring的元数据支持,你可以为你的源代码增加注释,指示Spring在何处以及如何应用切面函数。

JDBC抽象和DAO模块

使用JDBC经常导致大量的重复代码,取得连接、创建语句、处理结果集,然后关闭连接。Spring的JDBC和DAO模块抽取了这些重复代码,因此你可以保持你的数据库访问代码干净简洁,并且可以防止因关闭数据库资源失败而引起的问题。

这个模块还在几种[数据库服务器](https://baike.baidu.com/item/数据库服务器/613818)给出的错误消息之上建立了一个有意义的异常层。使你不用再试图破译神秘的私有的SQL错误消息!

另外,这个模块还使用了Spring的AOP模块为Spring应用中的对象提供了事务管理服务。

对象/关系映射集成模块

对那些更喜欢使用对象/关系映射工具而不是直接使用JDBC的人,Spring提供了ORM模块。Spring并不试图实现它自己的ORM解决方案,而是为几种流行的[ORM框架](https://baike.baidu.com/item/ORM框架/15541111)提供了集成方案,包括Hibernate、JDO和iBATIS SQL映射。Spring的事务管理支持这些ORM框架中的每一个也包括JDBC。

Spring的Web模块

Web上下文模块建立于应用上下文模块之上,提供了一个适合于Web应用的上下文。另外,这个模块还提供了一些面向服务支持。例如:实现文件上传的multipart请求,它也提供了Spring和其它Web框架的集成,比如Struts、WebWork。

Spring的**MVC框架**

Spring为构建Web应用提供了一个功能全面的MVC框架。虽然Spring可以很容易地与其它MVC框架集成,例如Struts,但Spring的MVC框架使用IoC对控制逻辑和业务对象提供了完全的分离。

它也允许你声明性地将请求参数绑定到你的业务对象中,此外,Spring的MVC框架还可以利用Spring的任何其它服务,例如国际化信息与验证。

Spring框架Web页面乱码问题

在做java Web 项目时,乱码问题时常都会出现,解决方法也不尽相同,有简单也有复杂的;如果加入了Spring框架之后就不一样了,可以采用Spring框架自带的过滤器CharacterEncodingFilter,这样可以大大减轻了我们的工作量,即简单方便又容易理解,配置方式如下:在web.xml文件中filter的位置加上如下内容:

<filter>
    <filter-name>encodingFilter</filter-name >
    <filter-class>
        org.springframework.web.filter.CharacterEncodingFilter
    </filter-class>
    <init-param>
        <param-name>encoding</param-name>
        <param-value>UTF-8</param-value>
    </init-param>
    <init-param>
        <param-name>forceEncoding</param-name>
        <param-value>true</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>encodingFilter</filter-name>
    <url-pattern>*</url-pattern>
</filter-mapping>

SSH: struct2 spring hibernate

SSM: springMVC spring +Mybatis

官网: https://spring.io/projects/spring-framework

官方下载地址: http://repo.spring.io/release/org/springframework/spring

**GitHub地址:**https://github.com/spring-projects/spring-framework

Maven 依赖

<!--spring-webmvc 依赖-->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.3.4</version>
</dependency>

<!-- spring-jdbc 依赖-->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>5.3.4</version>
</dependency>

1.2、优点

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

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

img

Spring的官网介绍:现代化Java开发

  • Spring Boot

    • 一个快速开发的脚手架

    • 基于SpringBoot可以快速的开发单个微服务

    • 约定大于配置

  • Spring Cloud

    • SpringCloud 是基于SpringBoot实现的。

大多数公司都在使用Spring Boot进行快速开发

学习SpringBoot的前提,需要为完全掌握Spring及其SpringMVC

唯一弊端缺点:发展太久,配置十分繁琐,人称 “配置地狱”

2,IOC理论推导

传统的设计模式:
  1. 实体类接口 UserDao 接口

  2. 实体类接口实现类 UserDaoImpl 类

  3. 业务层实现接口 UserServive 接口

  4. 业务层实现类 UserServiceImpl 类

package com.hjf.dao;

public interface UserDao {
    void getuser();
}
package com.hjf.dao;
public class UserDaoImpl implements UserDao{

    public void getuser() {
        System.out.println("默认获取用户数据");
    }
}
package com.hjf.service;

public interface UserService {
    void getuser();
}
package com.hjf.service;

import com.hjf.dao.UserDao;
import com.hjf.dao.UserDaoImpl;
import com.hjf.dao.UserDaoMysolImpl;

public class UserServiceImpl implements UserService{

    private UserDao userDao = new UserDaoMysolImpl();

    public void getuser() {
        userDao.getuser();
    }
}
import com.hjf.dao.UserDaoImpl;
import com.hjf.service.UserServiceImpl;


public class MyTest {
    public static void main(String[] args) {
// 用户实际调用的是业务层,dao层他们不需要接触!
        UserServiceImpl userService = new UserServiceImpl();
        userService.getuser();
    }
}
问题提出
  1. 当实体类接口的实现类增加时
  2. 用户想要修改调用新的实体类接口时,就不得不修改 UserServiceImpl 实现类的代码。
package com.hjf.dao;
//新增的dao层实体类
public class UserDaoMysolImpl implements UserDao{

    public void getuser() {
        System.out.println("Mysql获取用户数据!");
    }
}
package com.hjf.service;

import com.hjf.dao.UserDao;
import com.hjf.dao.UserDaoImpl;
import com.hjf.dao.UserDaoMysolImpl;

public class UserServiceImpl implements UserService{
    //修改需要新实现的接口,如果接口过多,且用户需要过多,会大量增加程序员的负担
    private UserDao userDao = new UserDaoMysolImpl();

    public void getuser() {
        userDao.getuser();
    }
}
问题解决
  • 在 UserServiceImpl 实现类中使用 set 注入来解决,重复修改代码的方法
  • 将在 UserServiceImpl 业务层,需要什么接口的实现类,就可以调用什么接口的实现类
package com.hjf.service;

import com.hjf.dao.UserDao;
import com.hjf.dao.UserDaoImpl;
import com.hjf.dao.UserDaoMysolImpl;

public class UserServiceImpl implements UserService{
    //修改需要新实现的接口,如果接口过多,且用户需要过多,会大量增加程序员的负担
//   解决方法:新增一个setter方法,将选择权交给客户,让用户选择实现类
//核心思想,将类设计成变量,利用 set 注入,就可以减少程序员的工作量这就是 IOC理论 控制反转
    private UserDao userDao;

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

    public void getuser() {
        userDao.getuser();
    }
}
import com.hjf.dao.UserDaoImpl;
import com.hjf.dao.UserDaoMysolImpl;
import com.hjf.service.UserServiceImpl;


public class MyTest {
    public static void main(String[] args) {
// 用户实际调用的是业务层,dao层他们不需要接触!
        UserServiceImpl userService = new UserServiceImpl();
        userService.setUserDao(new UserDaoImpl());
        userService.getuser();
    }
}
  • 之前,程序是主动创建对象,控制权在程序员手上
  • 使用 set注入后,程序不再具有主动性,而是变成了被动接受对象!

IOC 思想,从本质上解决了问题,程序员不用再去管理对象,系统耦合度大大降低。这就是 IOC 原型

控制反转IoC(Inversion of Control),是一种设计思想,DI(依赖注入)是实现IoC的一种方法

img

IoC是Spring框架的核心内容,使用多种方式完美的实现了IoC,可以使用XML配置,也可以使用注解,新版本的Spring也可以零配置实现IoC。

Spring容器在初始化时先读取配置文件,根据配置文件或元数据创建与组织对象存入容器中,程序使用时再从Ioc容器中取出需要的对象。

采用XML方式配置Bean的时候,Bean的定义信息是和实现分离的,而采用注解的方式可以把两者合为一体,Bean的定义信息直接以注解的形式定义在实现类中,从而达到了零配置的目的。

控制反转是一种通过描述(XML或注解)并通过第三方去生产或获取特定对象的方式。在Spring中实现控制反转的是IoC容器,其实现方法是依赖注入(Dependency Injection,DI)。

container magic

3,第一个Spring

1、Hello Spring
  1. 导入依赖

  2. 创建实体类

    核心是用 set 注入,实体类必须要有 set 方法

  3. 编写类的配置文件

  4. 测试

package com.hjf.pojo;
//实体类
public class Hello {
    private String str ;
    

    public String getStr() {
        return str;
    }

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

    @Override
    public String toString() {
        return "Hello{" +
                "str='" + str + '\'' +
                '}';
    }
}

创建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
        https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--    使用spring来创建对象,在spring中这些都称为Bean-->
<!--      类型 变量名 = new 类型
          Hello hello = new Hello()
          id = 变量名
          class = new 的对象
          property 相当于给对象中的属性设置一个值-->
        <bean id="hello" class="com.hjf.pojo.Hello">
                <property name="str" value="Spring"/>
        </bean>

</beans>

测试类

import com.hjf.pojo.Hello;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyTest {
    public static void main(String[] args) {
//        获取spring的上下文对象
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
//        我们的对象现在都在spring中管理了,我们要使用,直接去里面取出来就可以
        Hello hello = (Hello) context.getBean("hello");
        System.out.println(hello.toString());

    }
}
IOC理论推导用另一个方法xml配置写

编写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
        https://www.springframework.org/schema/beans/spring-beans.xsd">

        <bean id="daoImpl" class="com.hjf.dao.UserDaoImpl"/>
        <bean id="daoMysqlImpl" class="com.hjf.dao.UserDaoMysolImpl"/>
        <bean id="daoOracalImpl" class="com.hjf.dao.UserDaoOrcalImpl"/>
        <bean id="UserServiceImpl" class="com.hjf.service.UserServiceImpl">
            <property name="userDao" ref="daoOracalImpl"/>
        </bean>
<!--    ref: 应用spring容器中创建号的对象
        value:具体的值,基本数据类型

        UserDaoMysolImpl
        UserDaoImpl

        就相当于MyTest里边的
        UserServiceImpl userService = new UserServiceImpl();
        userService.setUserDao(new UserDaoImpl());
        userService.getuser();

        new UserDaoImpl()

        需要用那个获取数据直接改
         ref = ""  即可-->

</beans>

编写测试类MyTest

//import com.hjf.dao.UserDaoImpl;
//
//import com.hjf.service.UserServiceImpl;


import com.hjf.service.UserServiceImpl;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyTest {
    public static void main(String[] args) {
//        第一种获取数据的方法
// 用户实际调用的是业务层,dao层他们不需要接触!
//        UserServiceImpl userService = new UserServiceImpl();
//        userService.setUserDao(new UserDaoImpl()
//        );
//        userService.getuser();

//        第二种获取数据的方法
//   获取ApplicationContext;拿到spring的容器
         // 获取操作类的 容器(框架)
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");

        //    容器在手,天下我有,需要什么,直接get什么!
         // 获取要操作的类的 变量
        UserServiceImpl userServiceImpl = (UserServiceImpl) context.getBean("UserServiceImpl");

         // 执行方法
        userServiceImpl.getuser();
    }
}

到了现在,我们彻底不用再程序中去改动了,要实现不同的操作,只需要在xmI配置文件中进行修改,所谓的IpC,-句话搞定:对象由Spring来创建,管理,装配!

4,IOC创建对象方式

1、Spring 无参构造

  • Spring 构建时,默认走无参构造.
  • 当无参构造被有参构造,消除时,有 3 种(有参构造方式)注入方式,进行配置 类的加载文件 beans.xml

2、Spring 有参构造

  1. 下标构造注入

    <!--第一种,下标赋值-->
            <bean id="user" class="com.hjf.pojo.User">
                <constructor-arg index="0" value="嘿嘿"/>
            </bean>
    

​ 2.类型匹配注入

<!--第二种,通过类型创建,不建议使用。原因:多个同类型的情况 如多个String类型-->
        <bean id="user" class="com.hjf.pojo.User">
            <constructor-arg type="java.lang.String" value="哈哈"/>
        </bean>

3.属性名注入(推荐使用)

<!--第三种,直接通过参数名来设置-->
        <bean id="user" class="com.hjf.pojo.User">
            <constructor-arg name="name" value="呵呵"/>
        </bean>

总结:在配置文件加载的时候,容器bean中管理的对象就已经初始化了

5,spring配置

1、别名
<!--        别名 :顾名思义,给对象名另起一个名字,一对一个-->
        <alias name="user" alias="user2"/>
2、Bean 配置
<!--       id : bean 的唯一标识符,也就是我们学的对象名,ApplicationContext中得到的getBean("dd")的名字 
           class : bean对象所对应的全限定名:包名+类名
           name : 也是别名,而且可以同时有多个-->
        <bean id="user" class="com.hjf.pojo.User" name="user3,df dd;wef">
            <property name="name" value="晓梦"/>
        </bean>
3、import

一般它用于团队开发,他可以将多个配置文件合并为一个 内容相同会自动优化

<!--
	一般项目时的所有人写的beans.xml都需要导入一个名叫 applicationContext.xml 的配置文件,
	import 就是将其他人写的配置文件导入进来
	
-->
<?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
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <import resource="beans.xml"/>
    <import resource="beans2.xml"/>
    <import resource="beans3.xml"/>
</beans>

6,依赖注入

1、构造器注入(上面已经写了)

2、Set注入【重点】
  • 依赖注入:Set注入!
    • **Dependency **依赖:bean对象的创建依赖于容器
    • Injection注入:bean对象中的所有属性,由容器来注入

【环境搭建】

  1. 复杂类型

    public class Address {
        private String address;
    
        public String getAddress() {
            return address;
        }
    
        public void setAddress(String address) {
            this.address = address;
        }
    }
    
  2. 真实测试对象

    public class Student {
        private String name;
        private Address address;
        private String[] books;
        private List<String> hobbys;
        private Map<String,String> card;
        private Set<String> games;
        private String wife;
        private Properties info;
    }
    

3.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
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="student" class="com.hjf.pojo.Student">
<!--        第一种,普通值注入,value-->
        <property name="name" value="雪女"/>
    </bean>

</beans>

4.测试类

public class MyTest {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        Student student = (Student) context.getBean("student");
        System.out.println(student.getAddress());
    }
}

5.不同对象类型注入方式

    <bean id="address" class="com.hjf.pojo.Address">
        <property name="address" value="华夏"/>
    </bean>

    <bean id="student" class="com.hjf.pojo.Student">
<!--        第一种,普通值注入,value-->
        <property name="name" value="雪女"/>
<!--        第二种,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="身份证" value="333223323233242343"/>
                <entry key="银行卡" value="242454656565656565"/>
            </map>
        </property>

<!--        set-->
        <property name="games">
            <set>
                <value>lol</value>
                <value>bob</value>
                <value>coc</value>
            </set>
        </property>

<!--        null-->
        <property name="wife">
            <null/>
        </property>

<!--        Properties-->
        <property name="info">
            <props>
                <prop key="driver">12334</prop>
                <prop key="性别">男</prop>
                <prop key="姓名">大法官</prop>
            </props>
        </property>

    </bean>

对应的测试及结果

public class MyTest {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        Student student = (Student) context.getBean("student");
        System.out.println(student.toString());
    }
/*    Student{
    name='雪女',
    address=Address{address='华夏'},
    books=[红楼梦, 三国演义, 水浒传, 西游记],
    hobbys=[唱歌, 看到电视, 听歌],
    card={
         身份证=333223323233242343,
         银行卡=242454656565656565},
    games=[lol, bob, coc],
    wife='null',
    info={
         性别=男,
         driver=12334,
         姓名=大法官}
    }*/
}
3,扩展方式注入

即 p 命名空间和 c 命名空间进行注入

官方解释

 

 

实现

  注意记得写       xmlns:p="http://www.springframework.org/schema/p"
                 xmlns:c="http://www.springframework.org/schema/c"

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

<!--p命名空间注入,可以直接注入属性的值:property-->
    <bean id="user" class="com.hjf.pojo.User" p:name="天明" p:age="15"/>

<!--c命名空间注入,通过构造器注入:constructor-arg  注:必须写其有参构造方法-->
    <bean id="user4" class="com.hjf.pojo.User" c:name="高月" c:age="15"/>






</beans>

测试

@Test
public void test2(){
    ApplicationContext context = new ClassPathXmlApplicationContext("Userbeans.xml");
    User user = (User) context.getBean("user4");
  /*  User user = context.getBean("user2", User.class);*/
    System.out.println(user);
xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"

测试时要导入junit依赖

<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.13</version>
</dependency>
4,Bean的作用域

官方文档

 

 

1,单列模式The Singleton Scope(Spring 默认机制)初始new 一次,后面都不new 快速 线程不安全 对象一样,是同一个,单线程使用

<bean id="user4" class="com.hjf.pojo.User" c:name="高月" c:age="15" scope="singleton"/>

2,原型模式The Prototype Scope:每次从容器getBean的时候,都会产生一个new对象 ,new浪费资源,但线程安全,多线程使用

<bean id="accountService" class="com.something.DefaultAccountService" scope="prototype"/>

3,其余request,application,websocket,session 这些只会在web开发中使用

7,bean的自动装配

  • 自动装配是 Spring 满足 Bean依赖的一种方式!

  • Spring 会在上下文中寻找,并给 Bean 自动装配属性!

    在 Spring 中的三种装配的方式

  1. 在 xml 中显示的装配
  2. 在 Java 中显示装配
  3. 隐式的自动装配 Bean 【重点】
1,测试

环境搭建:一个人两个宠物

package com.hjf.pojo;

public class Cat {
    public void shout(){
        System.out.println("miao~");
    }
}
package com.hjf.pojo;

public class Dog {
    public void shout(){
        System.out.println("wang~");
    }
}
package com.hjf.pojo;

public class People {
    private Cat cat;
    private Dog dog;
    private String name;

    @Override
    public String toString() {
        return "People{" +
                "cat=" + cat +
                ", dog=" + dog +
                ", name='" + name + '\'' +
                '}';
    }

    public Cat getCat() {
        return cat;
    }

    public void setCat(Cat cat) {
        this.cat = cat;
    }

    public Dog getDog() {
        return dog;
    }

    public void setDog(Dog dog) {
        this.dog = dog;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
<?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
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="cat" class="com.hjf.pojo.Cat"/>
    <bean id="dog" class="com.hjf.pojo.Dog"/>

    <bean id="people" class="com.hjf.pojo.People">
        <property name="cat" ref="cat"/>
        <property name="dog" ref="dog"/>
        <property name="name" value="卫庄"/>
    </bean>






</beans>

环境测试

import com.hjf.pojo.People;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyTest {
    @Test
    public void test1(){
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        People people = context.getBean("people", People.class);
        people.getCat().shout();
        people.getDog().shout();

    }
}
2,byName自动装配
   <bean id="cat" class="com.hjf.pojo.Cat"/>
    <bean id="dog" class="com.hjf.pojo.Dog"/>

<!--byName:会自动在容器上下文中查找,和自己对象set方法后面的值对应的beanid!  也就是需要写对应的setter方法,
    且需要注册beanid 并且id需要相对应-->
    <bean id="people" class="com.hjf.pojo.People" autowire="byName">
        <property name="name" value="卫庄"/>
    </bean>
3,byType自动装配
    <bean class="com.hjf.pojo.Cat"/>
    <bean class="com.hjf.pojo.Dog"/>

<!--byName:会自动在容器上下文中查找,和自己对象set方法后面的值对应的beanid!  也就是需要写对应的setter方法,
    且需要注册beanid 并且id需要相对应
    byType:会自动在容器上下文中查找,和自己对象属性类型相同的bean! 注:若写dog 和dog111时 会冲突,同一类型只能有一个
    也可以不写id ,直接class即可-->
    <bean id="people" class="com.hjf.pojo.People" autowire="byType">
        <property name="name" value="卫庄"/>
    </bean>

小结:byname的时候,需要保证所有bean的id唯一,并且这个bean的 id 需要和自动注入的属性的set方法的值一致!

bytype的时候,需要保证所有bean的class唯一,并且这个bean需要和自动注入的属性的类型一致!

4,使用注解实现自动装配

jdk1.5支持的注解,spring2.5就支持了!

The introduction of annotation-based configuration raised the question of whether this approach is “better” than XML

使用注解须知:

​ 1.导入约束:context约束

​ **xmlns:context="http://www.springframework.org/schema/context" **

​ 2.配置注解的支持:context:annotation-config/ 【重要】

<?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
    https://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context
    https://www.springframework.org/schema/context/spring-context.xsd">

    <context:annotation-config/>

</beans>    

@Autowired

直接在属性上使用即可,也可以在set方式上使用

使用 Autowired 就可以不用写Set方法了,前提是你自动装配的属性在IOC(Spring)容器中存在,且符合名字byname

@Nullable     字段标记了这个注解,说明这个字段可以null
boolean required() default true;
public class People {
//如果显示的定义Autowired的required 属性为 false,说明这个对象可以为null,否则不允许为空
    @Autowired(required = false)
    private Cat cat;

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

    <bean id="cat111" class="com.hjf.pojo.Cat"/>
    <bean id="cat222" class="com.hjf.pojo.Cat"/>
    <bean id="dog222" class="com.hjf.pojo.Dog"/>
    <bean id="people" class="com.hjf.pojo.People"/>
public class People {
//  @Resource(name = "cat111")也行,不指定时默认查找cat,没有就查找name里的,否则报错
    @Qualifier(value = "cat111")
    @Autowired
    private Cat cat;

小结:

@Resource 和 @Autowired 的区别

  • 都是用来自动装配的,都可以放在属性字段上
  • @Autowired通过bytype的方式实现,而且必须要求这个对象存在【常用】
  • @Resource默认通过byname的方式实现,如果找不到名字,则通过Bytype实现!若都找不到,则报错【常用】
  • 执行顺序不同:@Autowired通过bytype的方式实现,@Resource默认通过byname的方式实现

8.使用注解开发

在Spring4之后,要使用注解开发,必须要保证aop的包导入了

<bean id="user" class="com.hjf.pojo.User">
        <property name="name" value="嬴政"/>
    </bean>

相当于


//等价于<bean id="user" class="com.hjf.pojo.User"/>
//@Component 组件
@Component
public class User {
//    相当于 <property name="name" value="嬴政"/>
    @Value("嬴政")
    public String name;
}

也可以注入在set方法上
@Component
public class User {

    public String name;
    //    相当于 <property name="name" value="嬴政"/>
    @Value("嬴政")
    public void setName(String name) {
        this.name = name;
    }
}

建议:复杂的走配置文件

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

<!--指定要扫描的包,这个包下的注解就会生效-->
    <context:component-scan base-package="com.hjf.pojo"/>
    <context:annotation-config/>
</beans>
  1. 属性如何注入
@Component
public class User {

    public String name;
    //    相当于 <property name="name" value="嬴政"/>
    @Value("嬴政")
    public void setName(String name) {
        this.name = name;
    }
}
  1. 衍生的注解

​ @Component有几个衍生注解,我们在web开发中,会按照mvc三层架构分层

   -    dao【@Repository】
   -    service 【@Service】
   -    controller  【@Controller】

这四个注解功能都是一样的,都是代表将某个类注册到spring容器中(即装配bean)

  1. 自动装配
@Autowired
@Resource
@Qualifier
@Nullable
  1. 作用域
@Scope("singleton/prototype.....")
  1. 小结:

    xml与注解

    • xml 更加万能,适用于任何场合!维护简单方便
    • 注解 不是自己的类使用不了,维护相对复杂

    xml与注解最佳搭配

    • xml用来管理bean;
    • 注解只负责完成属性的注入;
    • 我们在使用的过程中,只需要注意一个问题:必须让注解生效,就需要开启注解的支持
    <!--指定要扫描的包,这个包下的注解就会生效-->
        <context:component-scan base-package="com.hjf"/>
        <context:annotation-config/>
    

9.使用Java的方式配置spring

完全不使用spring的xml配置,全权交给Java来做!

官方文档

@Configuration
public class AppConfig {

    @Bean
    public MyService myService() {
        return new MyServiceImpl();
    }
}

The preceding AppConfig class is equivalent to the following Spring <beans/> XML:

<beans>
    <bean id="myService" class="com.acme.services.MyServiceImpl"/>
</beans>

上面的Java类完全等价与下面的xml配置

Javaconfig在spring4之后,成为了核心功能【推荐使用】

 

 

实体类
package com.hjf.pojo;

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

@Component
public class User {
    private String name;

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                '}';
    }

    public String getName() {
        return name;
    }

    @Value("李斯")
    public void setName(String name) {
        this.name = name;
    }
}
配置类
package com.hjf.config;

import com.hjf.pojo.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

//会被spring容器托管,注册到容器中,因为它本就是一个@Component
// @Configuration代表他是一个配置类,和之前的bean.xml一样
@Configuration
@ComponentScan("com.hjf.pojo")
@Import(MyConfig2.class)
public class MyConfig {

//    <bean id="cat" class="com.hjf.pojo.Cat"/>
    //getUser相当于id="getUser"
    //User相当于class="com.hjf.pojo.User"
    @Bean
    public User getUser(){
        return new User();
    }
}
测试类
import com.hjf.config.MyConfig;
import com.hjf.pojo.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class MyTest {
    public static void main(String[] args) {
//        如果完全使用了配置类方式,就只能通过AnnotationConfig上下文来获取容器,然后对配置类的 class 对象进行加载
        ApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);
        User getUser = context.getBean("getUser", User.class);
        System.out.println(getUser.getName());
    }
}

这种纯Java的配置方式,在springboot随处可见

10.代理模式

SpringAOP的底层

代理模式分类:

  • 静态代理
  • 动态代理

 

 

 

 

10.1、静态代理

角色分析:

  • 抽象角色:一般会使用接口或者抽象类来解决
  • 真实角色:被代理的角色
  • 代理角色:代理真实角色,代理后会做一些附属操作
  • 客户:访问代理对象的人

代码步骤:

  1. 接口
package com.hjf.demo01;
//租房
public interface Rent {
    public void rent();
}
  1. 真实角色
package com.hjf.demo01;

public class Host implements Rent{
    @Override
    public void rent() {
        System.out.println("房东要出租房子");
    }
}
  1. 代理角色
package com.hjf.demo01;

public class Proxy implements Rent{
    private Host host;

    public Proxy(Host host) {
        this.host = host;
    }

    public Proxy() {
    }

    @Override
    public void rent() {
        host.rent();
        seeHouse();
        hetong();
    }
    //看房
    public void seeHouse(){
        System.out.println("中介代理看房");
    }
    //签合同
    public void hetong(){
        System.out.println("签合同");
    }
}
  1. 客户端访问代理角色
package com.hjf.demo01;

public class Client {
    public static void main(String[] args) {
        Host host = new Host();
        //代理
        Proxy proxy = new Proxy(host);
        proxy.rent();
    }
}

代理模式的好处:

  • 可以使真实角色的操作更加纯粹不用去关注一些公共的业务
  • 公共业务交给了代理角色,实现了业务的分工
  • 公共业务扩展的时候,方便管理

缺点:

  • 一个真实角色就会产生一个代理角色;代码量会翻倍,开发效率会变低

10.2、加深理解

代码:spring-08-proxy。demo02

aop

 

 

10.3动态代理

  • 动态代理和静态代理角色一样
  • 动态代理的代理类是动态生成的,不是我们直接写好的
  • 动态代理分为两大类:基于接口的动态代理,基于类的动态代理
    • 基于接口: JDK动态代理【我们使用这个】
    • 基于类: cglib
    • Java字节码实现: javasist

需要了解两个类:proxy: 代理 INvocationHandler: 调用处理程序

动态代理的好处:

  • 可以使真实角色的操作更加纯粹不用去关注一些公共的业务
  • 公共业务交给了代理角色,实现了业务的分工
  • 公共业务扩展的时候,方便管理
  • 一个动态代理类代理的是一个接口,一般就是对应的一类业务
  • 一个动态代理类可以代理多个类,只要实现了同一个接口即可

11、AOP

AOP为Aspect Oriented Programming的缩写,意为:[面向切面编程](https://baike.baidu.com/item/面向切面编程/6016335),通过[预编译](https://baike.baidu.com/item/预编译/3191547)方式和运行期间动态代理实现程序功能的统一维护的一种技术。AOP是[OOP](https://baike.baidu.com/item/OOP)的延续,是软件开发中的一个热点,也是[Spring](https://baike.baidu.com/item/Spring)框架中的一个重要内容,是[函数式编程](https://baike.baidu.com/item/函数式编程/4035031)的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的[耦合度](https://baike.baidu.com/item/耦合度/2603938)降低,提高程序的可重用性,同时提高了开发的效率。

11.2 AOP在Spring中的作用

提供声明式事务;允许用户自定义切面

  • 横切关注点:跨越应用程序多个模块的方法或功能。即是,与我们业务逻辑无关的,但是我们需要关注的部分,就是横切关注点。如日志,安全,缓存,事务等等…
  • 切面(ASPECT):横切关注点被模块化的特殊对象。即,它是一个类。
  • 通知(Advice):切面必须要完成的工作。即,它是类中的一个方法。
  • 目标(Target):被通知对象。
  • 代理(Proxy):向目标对象应用通知之后创建的对象。
  • 切入点(PointCut):切面通知执行的“地点”的定义。
  • 连接点(JointPoint):与切入点匹配的执行点。

SpringAOP中,通过Advice定义横切逻辑,Spring中支持5种类型的Advice:

即AOP在不改变原有代码的情况下,去增加新的功能。

11.3、使用Spring实现Aop

【重点】使用AOP织入,需要导入依赖包

<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.7</version>
</dependency>
方式一: 使用Spring的API接口【主要是SpringAPI接口实现】
  1. 在service包下,定义UserService业务接口和UserServiceImpl实现类
package com.hjf.service;

public interface UserService {
    public void add();
    public void delete();
    public void update();
    public void query();
}
package com.hjf.service;
public class UserServiceImpl implements UserService{
    @Override
    public void add() {
        System.out.println("增");
    }
    @Override
    public void delete() {
        System.out.println("删");
    }
    @Override
    public void update() {
        System.out.println("改");
    }
    @Override
    public void query() {
        System.out.println("查");
    }
}
  1. 在log包下,定义我们的增强类,一个Log前置增强和一个AfterLog后置增强类
package com.hjf.log;

import org.springframework.aop.AfterReturningAdvice;

import java.lang.reflect.Method;

public class AfterLog implements AfterReturningAdvice {
    @Override
//    returnValue:返回值
    public void afterReturning(Object returnValue, Method method, Object[] objects, Object o1) throws Throwable {
        System.out.println("执行了"+method.getName()+"方法,返回结果为:"+returnValue);
    }
}
package com.hjf.log;

import org.springframework.aop.MethodBeforeAdvice;

import java.lang.reflect.Method;

public class Log implements MethodBeforeAdvice {

//    method:要执行的目标对象的方法
//    args:参数
//    target:目标对象
    @Override
    public void before(Method method, Object[] args, Object target) throws Throwable {

        System.out.println(target.getClass().getName()+"的"+method.getName()+"被执行了");

    }
}
  1. 最后去spring的文件中注册 , 并实现aop切入实现 , 注意导入约束,配置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"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       https://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       https://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/aop
       https://www.springframework.org/schema/aop/spring-aop.xsd">

    <bean id="userService" class="com.hjf.service.UserServiceImpl"/>
    <bean id="log" class="com.hjf.log.Log"/>
    <bean id="afterLog" class="com.hjf.log.AfterLog"/>

<!--    方式一:使用原生态Spring API接口-->
<!--    配置Aop:上方需要导入aop的约束-->
    <aop:config>
<!--       切入点 :  expression:表达式,execution(要执行的位置!* * * * *)-->
        <aop:pointcut id="pointcut" expression="execution(* com.hjf.service.UserServiceImpl.*(..))"/>

<!--        执行环绕-->
        <aop:advisor advice-ref="log" pointcut-ref="pointcut"/>
        <aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>
    </aop:config>
</beans>

测试

import com.hjf.service.UserService;
import com.hjf.service.UserServiceImpl;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyText {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//        动态代理代理的是接口
        UserService userService = context.getBean("userService", UserService.class);
        userService.add();
    }
}
方式二:使用自定义类来实现【主要是切面定义】
  1. 在diy包下定义自己的DiyPointCut切入类
package com.hjf.diy;

public class DiyPiontCut {
    public void before(){
        System.out.println("==方法执行前===");
    }
    public void after(){
        System.out.println("==方法执行后===");
    }
}
  1. 去spring中配置文件
<!--方式二:自定义类-->
    <bean id="diy" class="com.hjf.diy.DiyPiontCut"/>
    
    <aop:config>
<!--        自定义切面,ref :要引用的类-->
        <aop:aspect ref="diy">
            <!--切入点-->
            <aop:pointcut id="point" expression="execution(* com.hjf.service.UserServiceImpl.*(..))"/>
<!--            通知-->
            <aop:before method="before" pointcut-ref="point"/>
            <aop:after method="after" pointcut-ref="point"/>
        </aop:aspect>
    </aop:config>
  1. 测试:和前面一样
方式三:注解实现Aop
  1. 在diy包下定义注解实现的AnnotationPointCut增强类
//方式三:使用注解方式实现Aop
@Aspect   //标注类是切面
public class AnnotationPointCut {
    @Before("execution(* com.hjf.service.UserServiceImpl.*(..))")
    public void before(){
        System.out.println("方法执行前");
    }
    @After("execution(* com.hjf.service.UserServiceImpl.*(..))")
    public void after(){
        System.out.println("方法执行后");
    }

    @Around("execution(* com.hjf.service.UserServiceImpl.*(..))")
    public void around(ProceedingJoinPoint jp) throws Throwable {
        System.out.println("环绕前");
        Object proceed = jp.proceed();  //执行方法
        System.out.println("环绕后");
    }
}
  1. 在Spring配置文件中,注册bean,并增加支持注解的配置。
<!--    方式三-->
    <bean id="annotationPointCut" class="com.hjf.diy.AnnotationPointCut"/>
<!--    开启注解支持    JDK(默认 proxy-target-class="false")   cglib(proxy-target-class="true")-->
    <aop:aspectj-autoproxy/>
  1. 测试,和上面一样,不需要改变

12.整合Mybatis

步骤:

  1. 导入相关jar包
    • Junit
    • mybatis
    • mysql数据库
    • spring相关的
    • aop织入
    • mybatis-spring【new】
<dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.26</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.7</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.3.10</version>
        </dependency>
<!--      Spring操作数据库的话,还需要一个Spring-jdbc-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.3.10</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.7</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>2.0.6</version>
        </dependency>

    </dependencies>

编写配置文件

测试

12.1回顾mybatis
  1. 编写实体类
public class User {
    private int id;
    private String name;
    private String pwd;
  1. 编写核心配置文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    
    <typeAliases>
        <package name="com.hjf.pojo"/>
    </typeAliases>


<!--    spring-dao.xml配置后就不要mabatis这段配置了-->
<!--    <environments default="development">-->
<!--        <environment id="development">-->
<!--            <transactionManager type="JDBC"/>-->
<!--            <dataSource type="POOLED">-->
<!--                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>-->
<!--                <property name="url" value="jdbc:mysql://localhost:3306/mybatis?		-->
<!--                                            useSSL=true&useUnicode=true&characterEncoding=UTF-8"/>-->
<!--                <property name="username" value="root"/>-->
<!--                <property name="password" value="hjf"/>-->
<!--            </dataSource>-->
<!--        </environment>-->
<!--    </environments>-->

<!--    <mappers>-->
<!--        <mapper class="com.hjf.mapper.UserMapper"/>-->
<!--    </mappers>-->

</configuration>
  1. 编写接口
public interface UserMapper {
    public List<User> selectUser();
}
  1. 编写mapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.hjf.mapper.UserMapper">

    <select id="selectUser" resultType="user">
        select * from mybatis.user ;
    </select>
</mapper>
  1. 测试
 @Test
    public void test() throws Exception {
       String resource = "mybatis-config.xml";
       InputStream in = Resources.getResourceAsStream(resource);
       SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(in);
       SqlSession sqlSession = sessionFactory.openSession(true);

       UserMapper mapper = sqlSession.getMapper(UserMapper.class);
       List<User> userList = mapper.selectUser();
       for (User user : userList) {
           System.out.println(user);
       }
   }
12.2Mybatis-spring(两种方式)

方式一:

  1. 编写数据源配置

    <!--DataSource:使用Spring的数据源替换Mybatis的配置   c3p0 dbcp  druid
        这里使用Spring提供的JDBC:org.springframework.jdbc.datasource-->
        <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
            <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
            <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=UTF-8"/>
            <property name="username" value="root"/>
            <property name="password" value="hjf"/>
        </bean>
    
  2. sqlSessionFactory

<!--sqlSessionFactory-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
<!--        绑定Mybatis配置文件-->
        <property name="configLocation" value="classpath:mybatis-config.xml"/>
        <property name="mapperLocations" value="classpath:com/hjf/mapper/*.xml"/>
    </bean>
  1. sqlSessionTemplate
<!--   SqlSessionTemplate:就是我们使用的 sqlSession-->
    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<!--        只能使用构造器注入sqlSessionFactory,因为它没有set方法-->
        <constructor-arg index="0" ref="sqlSessionFactory"/>
    </bean>
  1. 给接口加实现类
public class UserMapperImpl implements UserMapper{
    //我们的所有操作,都使用sqlSession来执行,在原来,现在都使用SqlSessionTemplate;
    private SqlSessionTemplate sqlSession;

    public void setSqlSession(SqlSessionTemplate sqlSession) {
        this.sqlSession = sqlSession;
    }

    @Override
    public List<User> selectUser() {
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        return mapper.selectUser();
    }
}
  1. 将写的实现类,注入到spring中
<bean id="userMapper" class="com.hjf.mapper.UserMapperImpl">
        <property name="sqlSession" ref="sqlSession"/>
    </bean>
  1. 测试
 @Test
    public void test(){
      ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
      UserMapper userMapper = context.getBean("userMapper", UserMapper.class);
      for (User user : userMapper.selectUser()) {
         System.out.println(user);
      }
   }

方式二:

SqlSessionDaoSupport

package com.hjf.mapper;

import com.hjf.pojo.User;
import org.apache.ibatis.session.SqlSession;
import org.mybatis.spring.support.SqlSessionDaoSupport;

import java.util.List;

public class UserMapperImpl2 extends SqlSessionDaoSupport implements UserMapper{
    @Override
    public List<User> selectUser() {
       /* SqlSession sqlSession = getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        return mapper.selectUser();*/
        return getSqlSession().getMapper(UserMapper.class).selectUser();
    }
}

sqlSessionFactory


    <bean id="userMapper2" class="com.hjf.mapper.UserMapperImpl2">
        <property name="sqlSessionFactory" ref="sqlSessionFactory"/>
    </bean>

测试

  @Test
    public void test2(){
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserMapper userMapper = context.getBean("userMapper2", UserMapper.class);
        for (User user : userMapper.selectUser()) {
            System.out.println(user);
        }
    }

13、声明式事务

1、回顾事务
  • 把一组业务当作一个业务来做;要么都成功,要么都失败
  • 开发中涉及到数据一致性问题
  • 确保完整性和一致性

事务ACID原则:

  • 原子性([Atom](https://so.csdn.net/so/search?from=pc_blog_highlight&q=Atom)icity)
  • 一致性(Consistency)
  • 隔离性(Isolation)
    • 多个业务可能操作同一个资源,防止数据破坏
  • 持久性(Durability)
    • 事务一旦提交,无论系统出现什么问题,之前操作后的数据不会被影响,被持久化的吓到存储器中
2、spring中的事务管理
  • 声明式事务:AOP
  • 编程式事务:需要在代码中,进行事务的管理

为什么需要事务?

  • 如果不配置事务,可能存在数据提交不一致的情况下;
  • 如果我们不在spring中去配置声明式事务,就需要在代码中手动配置事务
  • 事务在项目的开发中十分重要,涉及到数据的一致性和完整性问题,不容马虎!

<!--    配置声明式事务-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <constructor-arg ref="dataSource" />
<!--        也可以这样写-->
<!--        <property name="dataSource" ref="dataSource"/>-->
    </bean>
    
<!--    结合AOP实现事务的织入-->
<!--配置事务通知-->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
<!--        给哪些方法配置事务-->
<!--        配置事务的传播特性: propagation=  -->
        <tx:attributes>
            <tx:method name="add" propagation="REQUIRED"/>
            <tx:method name="delete" propagation="REQUIRED"/>
            <tx:method name="update" propagation="REQUIRED"/>
            <tx:method name="query" read-only="true"/>
            <tx:method name="*" propagation="REQUIRED"/>
        </tx:attributes>
    </tx:advice>
    
<!--    配置事务切入-->
    <aop:config>
        <aop:pointcut id="txPointCut" expression="execution(* com.hjf.mapper.*.*(..))"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>
    </aop:config>
posted @ 2021-11-30 15:29  喻嘿嘿  阅读(74)  评论(0)    收藏  举报