Spring5框架-cnblog

tanzhenfei / 2023-08-28 / 原文

Spring5框架

基础

使 用:JavaBean

目 的解决企业应用开发的复杂性

功 能:使用基本的JavaBean代替EJB,本身是一个大杂烩,整合了现有的技术框架

范 围: 任何Java应用

Spring框架以interface21框架为基础,经过重新设计,不断丰富,于2001年发布1.0正式版,轻量级的控制反转(IOC)h和面向切面编程的框架,非入侵式的框架,支持事物,对框架整合的支持

GitHub网址:Search · spring · GitHub

中文文档:https://www.docs4dev.com/docs/zh/spring-framework/5.1.3.RELEASE/reference

英文文档:Spring Framework Documentation

官方下载地址:https://repo1.maven.org/maven2/org/springframework/spring/

导maven以及jdbc包

<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.3.9</version>
</dependency>

<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>5.3.9</version>
</dependency>

spring范围

image-20210812214433363

spring学习路线

image-20210812214933622

  • spring boot

    • 一个快速开发的脚手架
    • 基于springboot可以快速开发单个微服务
    • 约定大于配置
  • spring Cloud

springcloud是基于springboot开发的,学习SpringBoot的前提,需要完全掌握Spring以及SpringMVC

Ioc理论

控制反转,是一种思想.

控制反转是一种通过描述(xml或者注解)并通过第三去生产或获取特定对象的方式。在spring中实现控制反转的是定义信息直接以注解的形式定义在实现类中,其实现方法是依赖注入(Dependency Injection,DI)

eg:注入set方法

dao类:

public interface UserDao {
    void getUser();
}
public class UserDaoImpl implements UserDao{
    public void getUser(){
        System.out.println("默认获取用户数据");
    }
}
public class UserDaoMysqlImpl implements UserDao{
    public void getUser() {
        System.out.println("获得mysql对象");
    }
}

service类:

public interface UserService {
    void getUser();
}
public class UserServiceImpl implements UserService{
   private UserDao userDao ;
//使用set进行动态实现值的注入
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

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

测试类:

public class MyTest {


    public static void main(String[] args) {
        //用户实际调用的是业务层,dao层他们不需要接触
        UserServiceImpl userService = new UserServiceImpl();
        userService.getUser();
        //----------------------------------
        //利用set进行动态实现值的注入
        ((UserServiceImpl)userService).setUserDao(new UserDaoImpl());
        userService.getUser();

    }
}

如果不用set方法,测试类每次在service类中访问dao资源时都要在service里面创建一个dao对象,对程序员的依赖性很强,使用set方法后,用户只需要在测试类中建一个dao对象,通过service的set方法直接调用dao资源,释放了程序员的工作,降低了系统的耦合度

image-20210812232458675

hello Spring

配置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="hello" class="com.dsm.pojo.Hello">
        <!-- collaborators and configuration for this bean go here -->
<!--        一个bean相当于一个对象(new Hello())-->
        <property name="str" value="Spring"></property>
    </bean>


    <!-- more bean definitions go here -->

</beans>

主类:
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 + '\'' +
                '}';
    }
}

测试类

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());
    }
}

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

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

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

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

IOC创建对象方式

无参构造创建(默认)

public User() {
    System.out.println("获取无参构造方法");
}
public static void main(String[] args) {
    ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
    User user = (User)context.getBean("user");
    user.toString();
}

有参构造创建

1.下标赋值创建

配置文件

<bean id="user1" class="com.dsm.pojo.User">
    <constructor-arg index="0" value="谭振飞">
    </constructor-arg>
</bean>

实体类

public User(String name) {
    this.name=name;
}
public void show() {
    System.out.println("name=" + name);
}

测试类

public class MyTest {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        User user = (User)context.getBean("user1");
        user.show();
    }
}

2.通过类型创建

不建议使用,可能有重复的类型

配置文件

<bean id="user2" class="com.dsm.pojo.User">
    <constructor-arg type="java.lang.String" value="谭振飞2"/>
</bean>

实体类与测试类与上种方法基本不变

3.通过参数名创建

<bean id="user3" class="com.dsm.pojo.User">
    <constructor-arg name="name" value="谭振飞"/>
</bean>

spring配置

别名(alias)

将user3起别名为user4

<alias name="user3" alias="user4"/>

bean

<bean id="user3" class="com.dsm.pojo.User" name="user4,u4;u5">
    <constructor-arg name="name" value="谭振飞"/>
</bean>

id:bean唯一的标识符,也就是我们所谓的对象名

class:对象对应的全限定名:包名+类型

name:别名,name可以取多个别名

import

一般用于团队开发,可以将多个配置文件合并为一个applicationContext.xml

<import resource="beans1.xml"/>
    <import resource="beans2.xml"/>
    <import resource="beans3.xml"/>
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

DI依赖注入

构造器(有参/无参)注入

前面已经记录

set方式注入(重要)

依赖:bean对象的创建依赖于容器

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

<bean id="address" class="com.dsm.pojo.AddRess">
    <property name="adress" value="郑州"/>
</bean>

<bean id="student" class="com.dsm.pojo.Student">
<!--    第一种普通值注入  value-->
    <property name="name" value="谭振飞"/>
<!--    第二种bean注入  ref-->
    <property name="addRess" ref="address"/>

<!--    数组注入-->
    <property name="books">
        <array>
            <value>平凡世界</value>
            <value>活着</value>
            <value>战争论</value>
        </array>
    </property>
<!--list注入-->
    <property name="hobby">
        <list>
            <value>听歌</value>
            <value>看书</value>
            <value>敲代码</value>
        </list>
    </property>
    <!--        map注入-->
    <property name="card">
        <map>
            <entry key="卡号" value="111111111"></entry>
            <entry key="密码" value="123456"></entry>
        </map>
    </property>
<!--    set注入-->
<property name="games">
    <set>
        <value>雪人兄弟</value>
        <value>魂斗罗</value>
        <value>超级玛丽</value>
    </set>
</property>
<!--    null注入-->
    <property name="wife">
        <null></null>
    </property>
<!--    property注入-->
    <property name="info">
        <props>
            <prop key="url">男</prop>
            <prop key="name">root</prop>
            <prop key="password">123456</prop>
        </props>
    </property>
</bean>

</beans>

实体类

package com.dsm.pojo;

import java.util.*;

public class Student {
    private  String name;
   private AddRess addRess;
   private String[] books;
   private List<String> hobby;
   private Map<String,String> card;
   private Set<String> games;
   private String wife;
   private Properties info;

    public String getName() {
        return name;
    }

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

    public AddRess getAddRess() {
        return addRess;
    }

    public void setAddRess(AddRess addRess) {
        this.addRess = addRess;
    }

    public String[] getBooks() {
        return books;
    }

    public void setBooks(String[] books) {
        this.books = books;
    }

    public List<String> getHobby() {
        return hobby;
    }

    public void setHobby(List<String> hobby) {
        this.hobby = hobby;
    }

    public Map<String, String> getCard() {
        return card;
    }

    public void setCard(Map<String, String> card) {
        this.card = card;
    }

    public Set<String> getGames() {
        return games;
    }

    public void setGames(Set<String> games) {
        this.games = games;
    }

    public String getWife() {
        return wife;
    }

    public void setWife(String wife) {
        this.wife = wife;
    }

    public Properties getInfo() {
        return info;
    }

    public void setInfo(Properties info) {
        this.info = info;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", addRess=" + addRess.toString() +
                ", books=" + Arrays.toString(books) +
                ", hobby=" + hobby +
                ", card=" + card +
                ", games=" + games +
                ", wife='" + wife + '\'' +
                ", info=" + info +
                '}';
    }
}
package com.dsm.pojo;

public class AddRess {
    private String adress;

    public String getAdress() {
        return adress;
    }

    public void setAdress(String adress) {
        this.adress = adress;
    }

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

测试类:

import com.dsm.pojo.Student;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

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());

    }



}

set注入与构造器注入如何选择

  1. 强制依赖使用构造器进行,使用setter注入有概率不进行注入导致null对象出现
  2. 可选依赖使用setter注入进行,灵活性强
  3. Spring框架倡导使用构造器,第三方框架内部大多数采用构造器注入的形式进行数据初始化,相对严谨
  4. 如果有必要可以两者同时使用,使用构造器注入完成强制依赖的注入,使用setter注入完成可选依赖的注入
  5. 实际开发过程中还要根据实际情况分析,如果受控对象没有提供setter方法就必须使用构造器注入
  6. 自己开发的模块推荐使用setter注入

其他注入方式

p命名空间注入

set方式注入,需要无参构造和set方法

可以直接注入属性的值

image-20210815095828897

c命名空间方式注入

构造器注入,需要有参构造器

image-20210815100318477

注意,不能直接使用p命名和c命名,需要导入xml

xmlns:p="http://www.springframework.org/schema/p"

xmlns:c="http://www.springframework.org/schema/c"

beean的作用域

Scope Description
singleton(单例模式,默认机制) (Default) Scopes a single bean definition to a single object instance for each Spring IoC container.
prototype(原型模式) Scopes a single bean definition to any number of object instances.
request
session Scopes a single bean definition to the lifecycle of an HTTP Session. Only valid in the context of a web-aware Spring ApplicationContext.
application Scopes a single bean definition to the lifecycle of a ServletContext. Only valid in the context of a web-aware Spring ApplicationContext.
websocket Scopes a single bean definition to the lifecycle of a WebSocket. Only valid in the context of a web-aware Spring ApplicationContext.

单例模式(默认)

调用多次同一个类,只会创建一个对象,后续调用该类的方法时候使用的是同个对象

image-20210815101603959

image-20210815101906806

原型模式

调用多次该类会创建不同对象,并使用不同对象调用该方法

image-20210815102432366

image-20210815102308770

其余开发模式只能在web开发中使用

加载properties文件

不加载系统属性
<context:property-placeholder location="jdbc.properties" system-properties-mode="NEVER" "/>

加载多个properties文件
<context:praperty-placeholderlocation="jdbc.properties,msg.properties" />

加载所有propertios文件
<context : property-placeholder location="*.preperties" / >

加载properties文件标准格式

从类路径或jar包中搜索并加载properties文件
<context:property-placeholder location="classpath*😗.properties" />

bean相关配置

<bean
id="bookDao"                            bean的Id
name="dao bookDaoImpl daoImpl"          bean别名
class="com.itheima.dao.impl.BookDaoImpl"      bean类型,静态工厂类,FactoryBean类
scope="singleton"               控制bean的实例数量
init-method="init"              生命周期初始化方法
destroy-method="destory"        生命周期销毁方法
autowire="byType"               自动装配类型
factory-method="getInstance"     bean工厂方法,应用于静态工厂或实例工厂
factory-bean="com.itheima.factory.BookDaoFactory"    实例工厂bean
lazy-init="true"                  控制bean延迟加载
/>

依赖注入相关配置

<constructor-arg name="bookDao" ref="bookDao" />
构造器注入引用类型
<constructor-arg name="userDao" ref="userDao" />
<constructor-arg name="msg" value="WARN"/>
构造器注入简单类型
<constructor-arg type="java.lang.String" index="3" value="WARN"/>
类型匹配与索引匹配
<property name="bookDao" ref="bookDao" />
setter注入引用类型
<property name="userDao" ref="userDao" />
<property name="msg" value="WARN" />
setter注入简单类型
<property name="names">
setter注入集合类型
<list>
list集合
<value>itcast</value>
集合注入简单类型
<ref bean="dataSource" />
集合注入引用类型
</list>
</ property></ bean>

Bean的自动装配(autowire)

spring会在上下文中自动寻找,并自动会给bean配备属性

在xml中显示的配置

在java中显示的配置

隐式的自动装配bean配置

1、byname自动装配

image-20210815105153191

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

<!--    
  byname:会自动在容器上下文中查找,和自己对象set方法后面的值对应的beanid,如"setDog"的set方法名,会寻找与‘set’后面的'Dog'相同的beanid的名字,将会找到'dog'并与之相匹配。也就是beanid中的‘dog’与方法名中的‘Dog’匹配
  需要保证beanid唯一
-->

    <bean id="people" class="com.dsm.pojo.People" autowire="byName">
        <property name="name" value="谭振飞"/>
    </bean>

2、bytype自动装配

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

<!--    byname:会自动在容器上下文中查找,和自己对象set方法后面的值对应的beanid,-->
    
    <!--    byType:会自动在容器上下文中查找,和自己对象属性类型对应的bean的Class类型,
       注意相同类型的多个bean无法使用此方法匹配
       好处是bean不需要配置id就可使用
       需要保证bean的class唯一
-->
    <bean id="people" class="com.dsm.pojo.People" autowire="byType">
        <property name="name" value="谭振飞"/>
    </bean>

前提所有的bean类型都是唯一的,如果出现两个相同的类型的bean,会报错

小结:

如果bean的id唯一,可以使用byname自动装配

如果bean的clas唯一,可以使用bytype自动装配

3、使用注解自动装配

导入约束

配置注解的支持

<?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>

注意:注解支持为

<context:annotation-config/>

很重要

@Autowired,

实体类中使用@Autowired注解开发,其可省略set方法

注意:

使用@Autowired注解实现自动装配需要保证beanid与属性名字相同

@Autowired
private Dog dog;//此处属性名字需要与beanid名字一致
@Autowired(required = false)//required定义此处是否可以为空
private Cat cat;

image-20210815222221609

科普:

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

 public void Student(@Nullable String name){
        this.name=name;
    }

@qualifier

一般设置为属性或者set方法

当有多个类型的时候,使用qualifiler可以指定某个bean去实现

eg:

image-20210815223419417

image-20210815223524451

@Resource

首先会用bytype匹配,如果匹配不到再用byname匹配,多个相同类型时需要配合qualifer()指定

@Autowired与@Qualifier是Spring注解,@Resource是java注解

@Resource(name = "dog2")
private Dog dog;
@Resource
private Cat cat;
private String name;

使用注解开发

步骤1:保证aop的包导入

image-20220813093619611

步骤二:xml添加扫描文件

<!--    指定要被扫描的包-->
<context:component-scan base-package="com.dsm.pojo"/>
<context:annotation-config/>

步骤三:使用注解

注意:注解是直接代替了bean,使该类被spring托管

@Component
public class User {
    @Value("谭振飞")
public String name;
}

属性注入

@component,@value

@Component
public class User {
    @Value("谭振飞")
public String name;
}
//@Component:组件,放在类上,说明这个类被spring管理了,就是bean!

注入值用注解@Value("value")代替

注册bean用注解@Comment代替

衍生注解

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

  • dao【@Repository】

  • service【@Service】

  • controller【@Controller】

    这三个注解功能与@Component都是一样的,都是代表将某个类注册到Spring中,装配Bean.

@Scope("...")

作用域

作用域(单列or原型模式)用注解@Scope代替

image-20210815230707937

小结:

xml与注解:

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

xml与注解最佳实践:

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

使用Config实现配置

不使用spring的xml配置而是完全使用java来配置

@Configuration

实体java类:

@Component//将该类注册到容器中,被spring托管了
public class User {
    @Value("谭振飞")//属性赋值
    private String name;

    public String getName() {
        return name;
    }

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

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

配置文件:

@Configuration
//这个也会spring容器托管,注册到容器中,因为他本来就是一个@Component
//@Configuration代表一个配置类,就和我们之前看到的beans.xml
@ComponentScan("com.dsm.pojo")//扫描包上下文
@Import(UserConfig2.class)
public class UserConfig {
    @Bean//注册一个bean,方法名字为id属性,返回值类型为class属性
    public User getUser(){
        return new User();
    }
}

测试类:

public class MyTest {
    public static void main(String[] args) {
      ApplicationContext context = new AnnotationConfigApplicationContext(UserConfig.class);
       User getUser =(User) context.getBean("getUser");
        System.out.println(getUser);
    }
}

注意注解区别:

1.@Component(包括@Service,@Controller,@Repository)作用相当于标签,将该类交给spring容器托管,配合@Value给属性注入值

2.@Configuration的类也会被spring容器托管,因为@Configuration也是由@Component注解实现的。区别是它表示一个配置类,相当于标签,不是bean。平时与@ComponentScan("")扫描包一起使用

3.@Bean相当于之前的一个bean,方法名就是bean的id,返回值是bean的class

代理模式

24种代理模式之一

SringAOP底层

image-20210816000632974

静态代理模式

image-20210816000750205

1.抽象角色(接口)

image-20210816002302401

2.真实角色(房东)

image-20210816001820660

3.代理角色(中介)image-20210816001643910

4.客户端访问代理角色

image-20210816001958581

代理的好处:

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

缺点:

  • 一个真实角色就会产生一个代理角色;代码量会翻倍-开发效率会变低(此问题我们会在动态代理解决)

image-20210816003434591

动态代理模式

动态代理分为两大类,基于接口的动态代理,基于类的动态代理

  • 基于接口-->JDK动态代理【我们在这里代理】
  • 基于类:cglib
  • java字节码实现:javasist

需要了解两个类:Proxy:代理,InvocationHandler调用处理程序

InvocationHandler

实现该类接口,即实现动态代理
//这个类自动生成代理
public class ProxyInvocationHandler implements InvocationHandler {
//被代理的接口
    private  Rent rent;
    public void setRent(Rent rent){
        this.rent=rent;
    }
//    生成得到代理类,Proxy.newProxyInstance得到代理对象返回的是object类
//this.getClass().getClassLoader():类加载器固定写法
    //rent.getClass().getInterfaces():接口数组
    //this:指定代理的功能,有哪些方法
public Object getProxy(){
        return Proxy.newProxyInstance(this.getClass().getClassLoader(),rent.getClass().getInterfaces(),this);
}
//    处理代理实例(需要代理完成的功能,代理需要干啥事需要invoke决定),并返回结果
    //Object proxy:代理对象
    //Method method:代理调用什么方法,传过来什么方法
    //Object[] args:method里的参数
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//动态代理的本质,就是利用反射机制实现
        seeHouse();
        fare();
        Object invoke = method.invoke(rent, args);
        return invoke;
    }

    public void seeHouse(){
        System.out.println("中介看房子");
    }
    public  void fare(){
        System.out.println("收中介费");
    }
}
测试类
public class Client {
    public static void main(String[] args) {
//        真实的角色
        Host host = new Host();
//        代理角色:现在没有
        ProxyInvocationHandler pith = new ProxyInvocationHandler();
//        通过调用程序处理角色来处理我们要调用的接口对象
        pith.setRent(host);

        Rent proxy =(Rent) pith.getProxy();//proxy动态生成的,我们并没有写

proxy.rent();
    }
}

实例2

image-20210817103515111

image-20210817103537696

image-20210817103731969

AOP

image-20210817104114113

【重点】使用AOP植入,需要导入一个依赖包

<dependencies>
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.9.4</version>
    </dependency>
</dependencies>

配置AOP的xml资源

方式一:使用Spring接口

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

<!--    注册bean-->
<bean id="userService" class="com.dsm.service.UserServiceImpl"/>
    <bean id="log" class="com.dsm.log.Log"/>
    <bean id="afterlog" class="com.dsm.log.AfterLog"/>
<!--    方式一,使用原生spring api接口-->
<!-- 配置aop:需要导入aop约束-->
<aop:config>
<!--    切入点:expression:表达式,execution(要执行的位置!修饰词,返回值,类名,方法名,参数)-->
    <aop:pointcut id="pointcut" expression="execution(* com.dsm.service.UserServiceImpl.*(..))"/>
<!--执行环绕增加-->

    <aop:advisor advice-ref="log" pointcut-ref="pointcut"/>
    <aop:advisor advice-ref="afterlog" pointcut-ref="pointcut"/>
</aop:config>

</beans>

测试类

public class MyTest {
    public static void main(String[] args) {
       ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserService userService =(UserService) context.getBean("userService");
        userService.add();

    }
}

方式二:自定义类

<!--    方式二:自定义类-->
    <bean id="diy" class="com.dsm.diy.DiyPointCut"/>
    <aop:config>
<!--        自定义切面,ref要引用的类-->
        <aop:aspect ref="diy">
<!--            切入点-->
            <aop:pointcut id="point" expression="execution(* com.dsm.service.UserServiceImpl.*(..))"/>
<!--            通知-->
            <aop:before method="before" pointcut-ref="point"/>
            <aop:after method="after" pointcut-ref="point"/>
        </aop:aspect>
    </aop:config>

切入点:在哪里执行

切入点即一个类,需要在该类的前后切入内容

通知:什么时候执行

通知即切面的方法,即向切入点切入的内容

方式三:使用注解来实现

<!--    方式三,注解实现-->
    <bean id="annotationPointCut" class="com.dsm.diy.AnnotationPointCut"/>
<!--    开启注解支持!  两种开启方式,JDK(默认 proxy-target-class="false"   cglib(proxy-target-class="true")-->
    <aop:aspectj-autoproxy/>
@Aspect//标注这个类是一个切面
public class AnnotationPointCut {
    @Before("execution(* com.dsm.service.UserServiceImpl.*(..))")
    public void before(){
        System.out.println("==方法执行前===");
    }
    @After("execution(* com.dsm.service.UserServiceImpl.*(..))")
    public void after(){
        System.out.println("==方法执行后==");
    }
    @Around("execution(* com.dsm.service.UserServiceImpl.*(..))")
    public void arround(ProceedingJoinPoint jp) throws Throwable {
        System.out.println("环绕前");
        Object proceed = jp.proceed();
        System.out.println("环绕前");
    }
}
public class MyTest {
    public static void main(String[] args) {
       ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//        代理接口
       UserService userService =(UserService) context.getBean("userService");
        userService.add();

    }
}

整合Mybatis

注意版本配置

image-20210817143607009

回忆mybatis创建步骤:

1.导入相关jar包

junit,mybatis,mysql数据库,spring相关,aop织入,mybatis-spring(专门整合spring和mybatis)

<dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>

        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.2</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.3.9</version>
        </dependency>
<!--        spring操作数据库,需要一个spring-jdbc-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.3.9</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.4</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>2.0.2</version>
        </dependency>
    </dependencies>

2.编写配置文件

<?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>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=false&amp;useUnicode=true&amp;characterEncoding=UTF-8"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>
<mappers>
    <mapper class="com.dsm.mapper.UserMapper"/>
</mappers>
</configuration>

3.编写mapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.dsm.mapper.UserMapper">
<select id="getUser" resultType="com.dsm.pojo.User">
    select * from mybatis.user1
</select>
</mapper>

4.测试

public class MyTest {
@Test
    public void test() throws IOException {
    String resourse="mybatis-config.xml";
    InputStream in = Resources.getResourceAsStream(resourse);
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);
    SqlSession sqlSession = sqlSessionFactory.openSession(true);


    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    List<User> userList = mapper.getUser();
    for (User user : userList) {
        System.out.println(user);
    }


}
}

mybatis-spring

第一种方法

image-20210817152233903

准备工作:

在pom.xml导入jar包

<dependency>
  <groupId>org.mybatis</groupId>
  <artifactId>mybatis-spring</artifactId>
  <version>2.0.6</version>
</dependency>

mybatis-config.xml:

<?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>
<!--    <environments default="development">-->
<!--        <environment id="development">-->
<!--            <transactionManager type="JDBC"/>-->
<!--            <dataSource type="POOLED">-->
<!--                <property name="driver" value="com.mysql.jdbc.Driver"/>-->
<!--                <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=false&amp;useUnicode=true&amp;characterEncoding=UTF-8"/>-->
<!--                <property name="username" value="root"/>-->
<!--                <property name="password" value="123456"/>-->
<!--            </dataSource>-->
<!--        </environment>-->
<!--    </environments>-->
<!--<mappers>-->
<!--    <mapper class="com.dsm.mapper.UserMapper"/>-->
<!--</mappers>-->
</configuration>

接口UserMapper:

public interface UserMapper {
    public List<User> getUser();
}

UserMapper.xml:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.dsm.mapper.UserMapper">
<select id="getUser" resultType="com.dsm.pojo.User">
    select * from mybatis.user1
</select>
</mapper>

接口实现类UserMapperImpl:

public class UserMapperImpl implements UserMapper {
    private SqlSessionTemplate sqlSession;

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

    public List<User> getUser() {
        return sqlSession.getMapper(UserMapper.class).getUser();
    }
}

总的配置文件: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: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/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd
        ">
<!--引入spring-dao.xml文件,后续还会引入其他文件-->
   <import resource="spring-dao.xml"/>
<!--实体类注册-->
    <bean id="UserMapper" class="com.dsm.mapper.UserMapperImpl">
        <property name="sqlSession" ref="sqlSession"/>
    </bean>

</beans>

(spring-dao.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: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/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd
        ">
<!--  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.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=false&amp;useUnicode=true&amp;characterEncoding=UTF-8"/>
        <property name="username" value="root"/>
        <property name="password" value="123456"/>
    </bean>

<!--使用SqlSessionFactoryBean来创建sqlSessionFactory,前提需要一个dataSource源-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!--        需要一个dataSource源-->
        <property name="dataSource" ref="dataSource"/>
<!--        绑定mybatis配置文件-->
        <property name="configLocation" value="classpath:mybatis-config.xml"/>
        <property name="mapperLocations" value="classpath:com/dsm/mapper/*.xml"/>
    </bean>

<!--  ***Template是一个模板,即SqlSessionTemplate就是SqlSession-->
    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<!--        只能用构造器注入,SqlSessionTemplat没有set方法不能set注入,将SqlSessionFactoryBean的id引入-->
        <constructor-arg index="0" ref="sqlSessionFactory"/>
    </bean>


<!--将利用spring创建好的sqlsession注入到自己写的UserMapperImpl实现类里面,利用set注入,实现sqlsession的注入-->
<!--    <bean id="UserMapper" class="com.dsm.mapper.UserMapperImpl">-->
<!--        <property name="sqlSession" ref="sqlSession"/>-->
<!--    </bean>-->

</beans>


6.测试

public class MyTest {
@Test
    public void test() {

    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    UserMapper userMapper = context.getBean("UserMapper", UserMapper.class);
    List<User> users = userMapper.getUser();
    for (User user : users) {
        System.out.println(user);
    }

}
}

第二种方法

SqlSessionDaoSupport 是一个抽象的支持类,用来为你提供 SqlSession。调用 getSqlSession() 方法你会得到一个 SqlSessionTemplate,之后可以用于执行 SQL 方法

接口的实现类改为:

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

配置文件.xml,不需要注入SqlSessionTemplate,直接引入sqlSessionFactory即

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: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/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd
        ">
<!--引入spring-dao.xml文件,后续还会引入其他文件-->
   <import resource="spring-dao.xml"/>
<!--实体类注册-->
    <bean id="UserMapper" class="com.dsm.mapper.UserMapperImpl">
        <property name="sqlSession" ref="sqlSession"/>
    </bean>
    <bean id="UserMapper2" class="com.dsm.mapper.UserMapperImpl2">
<property name="sqlSessionFactory" ref="sqlSessionFactory"/>
    </bean>


</beans>

spring-dao.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: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/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd
        ">
<!--  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.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=false&amp;useUnicode=true&amp;characterEncoding=UTF-8"/>
        <property name="username" value="root"/>
        <property name="password" value="123456"/>
    </bean>

<!--  sqlSessionFactory  -->
<!--使用SqlSessionFactoryBean来创建sqlSessionFactory,前提需要一个dataSource源-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!--        需要一个dataSource源-->
        <property name="dataSource" ref="dataSource"/>
<!--        绑定mybatis配置文件-->
        <property name="configLocation" value="classpath:mybatis-config.xml"/>
        <property name="mapperLocations" value="classpath:com/dsm/mapper/*.xml"/>
    </bean>

<!--将利用spring创建好的sqlsession注入到自己写的UserMapperImpl实现类里面,利用set注入,实现sqlsession的注入-->
<!--    <bean id="UserMapper" class="com.dsm.mapper.UserMapperImpl">-->
<!--        <property name="sqlSession" ref="sqlSession"/>-->
<!--    </bean>-->

</beans>

测试类

public class MyTest {
@Test
    public void test() {
    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    UserMapper userMapper = context.getBean("UserMapper2", UserMapper.class);
    List<User> users = userMapper.getUser();
    for (User user : users) {
        System.out.println(user);
    }

}
}

步骤

image-20210817155508005

声明式事务

1.回顾事务

  • 把一组业务当成一个业务来做,要么成功,要么失败
  • 事务在项目开发中,十分重要,涉及到数据的一致性问题,不能马虎
  • 确保完整性和一致性;

事物的ACID原则:

  • 原子性:确保事务要么成功,要么失败
  • 一致性:事务完成,要么都提交,要么都失败
  • 隔离性:多个业务可能操作同一个资源,防止数据损坏
  • 持久性:事务一旦提交,无论系统发生什么问题,结果都不会再被影响,被持久化的写到存储器中

spring中的事务管理

  • 声明式事务:AOP
  • 编程式事务:需要在代码中进行事务的管理

配置文件

<?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:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/tx
        https://www.springframework.org/schema/tx/spring-tx.xsd
        ">
<!--  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.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=false&amp;useUnicode=true&amp;characterEncoding=UTF-8"/>
        <property name="username" value="root"/>
        <property name="password" value="123456"/>
    </bean>

<!--  sqlSessionFactory  -->
<!--使用SqlSessionFactoryBean来创建sqlSessionFactory,前提需要一个dataSource源-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!--        需要一个dataSource源-->
        <property name="dataSource" ref="dataSource"/>
<!--        绑定mybatis配置文件-->
        <property name="configLocation" value="classpath:mybatis-config.xml"/>
        <property name="mapperLocations" value="classpath:com/dsm/mapper/*.xml"/>
    </bean>


<!--    SqlSessionTemplate-->
<!--  ***Template是一个模板,即SqlSessionTemplate就是SqlSession-->
    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<!--        只能用构造器注入,SqlSessionTemplat没有set方法不能set注入,将SqlSessionFactoryBean的id引入-->
        <constructor-arg index="0" ref="sqlSessionFactory"/>
    </bean>

<!--    配置声明式事务-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>

<!--    结合AOP实现事务的植入-->
<!--    配置事务通知-->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
<!--给哪些方法配置事务-->
<!--        配置事务的传播特性 propagation-->
        <tx:attributes>
            <tx:method name="add" propagation="MANDATORY"/>
            <tx:method name="delete"/>
            <tx:method name="*"/>
        </tx:attributes>
    </tx:advice>

<!--    配置事务切入-->
<aop:config>
    <aop:pointcut id="txPointCut" expression="execution(* com.dsm.mapper.*.*(..))"/>
    <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>
</aop:config>
</beans>