1 Star 0 Fork 0

ace.kevin / StudyNotes

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
Spring学习笔记.md 35.74 KB
一键复制 编辑 原始数据 按行查看 历史
ace.kevin 提交于 2022-01-14 16:48 . go go go

0、课程准备

环境:

  • jdk1.8
  • maven 3.6.1
  • mysql 5.7
  • IDEA

依赖:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.3.12</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId> <!--spring操作数据库还需要spring-jdbc-->
    <version>5.3.12</version>
</dependency>
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.7</version>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.16</version>
</dependency>
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.7</version>
</dependency>
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis-spring</artifactId>
    <version>2.0.6</version>
</dependency>
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
</dependency>

1、Spring

1.1 简介

文档:

core的文档:

https://docs.spring.io/spring-framework/docs/current/reference/html/core.html

Spring框架

SSH:Struts2 + Spring + Hibernate

SSM: SpringMVC + Spring + Mybatis

Spring依赖配置:

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

1.2 优点

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

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

1.3 组成

这里写图片描述

  • Spring Boot

    • 一个快速开发脚手架

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

    • 约定大于配置

  • Spring Cloud

    • SpringCloud是基于Spring Boot实现的

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

唯一弊端:发展太久,违背了原来的理念,配置十分繁琐,称为配置地狱。

2、IOC推导

原本的实现

  1. UserDao接口

  2. UserDaoImpl

  3. UserService业务接口

  4. UserServiceImpl实现

在我们之前的业务中,用户的需求可能会影响我们原来的代码,我们需要根据用户的需求去修改原代码。如果程序量代码十分大,修改一次的代价成本十分昂贵

使用一个Set接口实现,优点在:

private UserDao userDao;
// 利用set方法动态实现值的注入
public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

之前,程序时主动创建对象,控制权在程序员手上;使用set注入后,程序不再具有主动性,而是变成动态被动地接收对象。

没有IoC的程序,对象的创建与对象间的依赖关系完全硬编码在程序中,对象的创建由程序自己控制,IoC后将对象的创建转移给第三方,“获得依赖对象的方式反转了”。

image-20211201154917741

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

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

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

3、 HelloSpring

The following example shows the basic structure of XML-based configuration metadata:

<?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">
	
    <!--解释:
        类型 变量名 = new 类型();
        Hello hello = new Hello();

        id = 变量名
        class = new 的类型
        property 设置对象的属性    -->
    <bean id="..." class="...">  
        <!-- collaborators and configuration for this bean go here -->
        <property name="name" value="Spring" />
    </bean>
    <!-- more bean definitions go here -->
</beans>
ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");

控制反转:

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

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

依赖注入:就是利用set方法来进行注入,所有property中要设置的值必须要有**对应(名字对应)**的set方法。

对象由Spring创建、管理和装配。\

<bean id="mysqlImpl" class="com.kuang.dao.UserDaoMysqlImpl"/>
<bean id="oracleImpl" class="com.kuang.dao.UserDaoOracleImpl"/>

<bean id="userServiceImpl" class="com.kuang.service.UserServiceImpl">
    <!--ref:引用Spring容器中创建好的对象
		value:具体的值,比如基本数据类型-->
    <property name="userDao" ref="mysqlImpl"/>
</bean>
// 获取ApplicationContext:拿到Spring容器
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml"); 
UserService userService = (UserService) context.getBean("userServiceImpl");
userService.getUser();

4、IoC构造方式

  1. 默认使用无参构造器,默认!
<bean id="user" class="com.kuang.pojo.User">
    <property name="name" value="秦疆"/>
</bean>
  1. 有参构造器

    1. 下标赋值
    <bean id="user" class="com.kuang.pojo.User">
        <constructor-arg index="0" value="秦疆"/>
    </bean>
    1. 根据类型赋值,加入两个参数都是同样类型,就无法区分,因此该方法不建议使用
    <bean id="user" class="com.kuang.pojo.User">
        <constructor-arg type="java.lang.String" value="qinjiang"/>
    </bean>
    1. 通过参数名
    <bean id="user" class="com.kuang.pojo.User">
        <constructor-arg name="name" value="qinjiang"/>
    </bean>

5、Spring配置

1、别名

<alias name="user" alias="userdfas"/>

2、Bean的配置

id 唯一标识符,相当于对象名

class:bean对象所对应的类型

name:别名,name比alias高级。可以取多个别名。

<bean id="user" class="com.kuang.pojo.User" name="userA, userB userC">
    <constructor-arg name="name" value="qinjiang"/>
</bean>

3、import,假设项目由多个成员开发,bean需要注册在不同的类中,可以利用import合并为一个总的。applicationContext.xml

<import resource="bean2.xml"/>

如果存在重名,下面的会覆盖上面的。

6、DI依赖注入

6.1构造器注入

6.2 Set方式注入【重要】

依赖注入:set注入

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

注入:bean对象中的所有属性,由容器来注入

普通值的注入:

<bean id="student" class="com.kuang.pojo.Student">
        <!--普通值注入-->
        <property name="name" value="秦疆" />
    </bean>

完善测试信息

<bean id="adresss" class="com.kuang.pojo.Address">
    <property name="address" value="北京"/>
</bean>
<bean id="student" class="com.kuang.pojo.Student">
    <!--普通值注入-->
    <property name="name" value="秦疆" />
    <property name="address" ref="adresss"/>
    <!--String[]注入-->
    <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="cards">
        <map>
            <entry key="身份证" value="111111222222223333"/>
            <entry key="学生卡" value="1111222233"/>
        </map>
    </property>
    <!--set注入-->
    <property name="games">
        <set>
            <value>COC</value>
            <value>BOB</value>
        </set>
    </property>
    <!--null注入-->
    <property name="wife">
        <null/>
    </property>
    <!-- <java.util.Properties> 配置类型注入-->
    <property name="info">
        <props>
            <prop key="adminstrator">guanliyuan</prop>
            <prop key="user">yonghu</prop>
        </props>
    </property>
</bean>

集合

bean | ref | idref | list | set | map | props | value | null

6.3 扩展方式注入

p命名空间和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 http://www.springframework.org/schema/beans/spring-beans.xsd">

<!--    p命名空间,必须有无参构造器,可以直接直接注入属性的值,p:代表property-->
    <bean name="user" class="com.kuang.pojo.User" p:name="秦疆" p:age="18"/>
<!--    c命名空间,必须使用有参构造器,通过构造器注入,c:代表construct-args-->
    <bean name="user2" class="com.kuang.pojo.User" c:name="高大翔" c:age="200"/>
</beans>

注意:

p命名和c命名不能直接使用,必须导入xml约束

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

6.4 bean作用域

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 Scopes a single bean definition to the lifecycle of a single HTTP request. That is, each HTTP request has its own instance of a bean created off the back of a single bean definition. Only valid in the context of a web-aware Spring ApplicationContext.
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.

singleton单例

singleton

<bean id="accountService" class="com.something.DefaultAccountService"/>
<!-- the following is equivalent, though redundant (singleton scope is the default) --> 
<bean id="accountService" class="com.something.DefaultAccountService" scope="singleton"/>

2、原型模式prototype

每次从容器中get,都会产生一个新对象

prototype

7、bean的自动装配

  • 自动装配是Spring满足bean依赖的一种方式
  • Spring会在上下文中自动寻找,并给bean装配属性。

在Spring中有三种装配的方式:

  1. 在xml中显式配置
  2. 在java中显式配置
  3. 隐式的 自动装配bean

7.1 测试

搭建环境:

一个人有两个宠物,一只猫、一只狗

原先的装配方式

<bean id="cat" class="com.kuang.pojo.Cat"/>
<bean id="dog" class="com.kuang.pojo.Dog"/>
<bean id="people" class="com.kuang.pojo.People">
    <property name="name" value="狂神"/>
    <property name="cat" ref="cat"/>
    <property name="dog" ref="dog"/>
</bean>

7.2 byName 自动装配

自动装配

<bean id="cat" class="com.kuang.pojo.Cat"/>
<bean id="dog" class="com.kuang.pojo.Dog"/>
<bean id="people" class="com.kuang.pojo.People" autowire="byName">
    <property name="name" value="狂神"/>
</bean>
  • 需要保证bean id唯一
  • 会自动在容器上下文中查找和自己对象set方法后面对应的bean id=dog222 就找不到,id必须匹配

7.3 byType 自动装配

  • 不需要有id
  • 必须保证这个类型bean class全局唯一

7.4 注解实现自动装配

jdk 1.5、Spring2.5 开始i支持注解

要使用注解,须知:

  • 导入约束context
  • 配置注解的支持<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

科普

// @Nullable 加了这个注解,可以为null 
// @Autowired(required=false) 说明这个对象可以为null 
// @Qualifier 配合@Autoweired使用,指定id名
@Autowired
@Qualifier(value = "dog222")
private Dog dog;

先通过bytype,不匹配再用byname

如果@Autowired不能唯一自动装配上属性,则需要通过@Qualifier(value="xxx")来指定名称。

@Resource实现自动装配

@Resource(name="bean id")

小结:

@Autowired和@Resource的区别

  1. 都是自动装配,可以放在属性字段上
  2. Autowired默认通过type,@Resource默认通过名字匹配

8、使用Spring注解开发

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

使用注解需要导入context约束,增加注解的支持。

DAO层: DAO层叫数据访问层,全称为data access object,属于一种比较底层,比较基础的操作,具体到对于某个表的增删改查,也就是说某个DAO一定是和数据库的某一张表一一对应的,其中封装了增删改查基本操作,建议DAO只做原子操作,增删改查。

Service层: Service层叫服务层,被称为服务,粗略的理解就是对一个或多个DAO进行的再次封装,封装成一个服务,所以这里也就不会是一个原子操作了,需要事物控制。

Controler层: Controler负责请求转发,接受页面过来的参数,传给Service处理,接到返回值,再传给页面。

总结: DAO面向数据,Service面向业务。后端开发时先数据库设计出所有表,然后对每一张表设计出DAO层,然后根据具体的业务逻辑进一步封装DAO层成一个Service层,对外提供成一个服务。

1、Bean注入

@Component 组件,放在类上,说明这个类被Spring管理了

// 等价于 <bean id="user" class="com.kuang.pojo.User"/>
@Component
public class User {
    public String name = "qinjiang";
}
@Component  // 等价于<bean id="user" class="com.kuang.pojo.User"/>
public class User {
    @Value("狂神")  // 相当于<property name="name" value="狂神"/>
    public String name;
}

复杂的注入还是需要用配置文件

2、属性如何注入

@Value("狂神2")
public void setName(String name) {
    this.name = name;
}

3、衍生的注解

@component 有几个衍生注解,在web开发中,会按照mvc三层进行分层

  • Dao【@Repository】:功能和@component相同,只不过是在Dao层用
  • Controller【@Controller】
  • Service【@Service】

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

4、(自动装)配置

(后面单讲)

5、作用域

@Scope(value="singleton")

@Scope(value="prototype")

6、小结

xml 与注解

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

最佳实践:

  • xml用来管理bean
  • 注解只负责完成属性的注入
  • MyBatis建议使用Xml进行配置,可以实现相当全功能的配置

使用过程中,需要注意一个问题,需要开启注解的支持:

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

9、基于Java的方式配置spring

可以使用java 的配置完全替代xml的配置

// 这个注解就是说明这个类被Spring接管了,注册到容器中,本身就是一个@Component
// @Configuration 代表这是一个配置类,和beans.xml一样
@Configuration
@ComponentScan("com.kuang.pojo")
public class KuangConfig {
    @Bean
    public User getUser() {
    /* 相当于写了一个bean标签
     * 方法名:就是Bean id Bean名
     * 返回值:bean中的class
     **/
        return new User();
    }
}
/** 等价于xml
<bean id="myService" class="com.acme.services.MyServiceImpl"/>
**/

JavaConfig是Spring的一个子项目,在Spring4之后变成Spring 的核心功能。

image-20211203215334444

测试:

@Test
public void test01() {
    // 如果完全使用配置类方式去做,就只能通过AnnotationConfig上下文来获取容器,通过配置类的class对象来加载
    ApplicationContext context = new AnnotationConfigApplicationContext(KuangConfig.class);
    User user = context.getBean("getUser", User.class);
    System.out.println(user.getName());
}

Bean可能存在多个

@Configuration
@ComponentScan("com.kuang.pojo")
@Import(KuangConfig.class)
public class KuangConfig2 {
}

纯Java的配置,在SpringBoot中随处可见!

10、AOP前情:代理模式

为什么学习AOP之前要学代理模式?因为代理模式是SpringAOP的底层 【SpringAOP和SpringMVC面试必问】

代理模式的分类:

  • 静态代理
  • 动态代理

代理和被代理的都得有共同要做的事情

image-20211203222907038

10.1 静态代理

角色分析:

  • 抽象角色:首先得存在抽象的角色,一般会使用接口或抽象类来解决。“共同要做的事情”
  • 真实角色:被代理的角色
  • 代理角色;代理真实角色,代理真实角色后,一般会做一些附属操作。
  • 客户:访问代理对象的人

image-20211203224716170

代码步骤:

1、抽象接口

/*租房*/
public interface Rent {
    public void rent();
}

2、真实角色

/*房东*/
public class Host implements Rent{
    @Override
    public void rent() {
        System.out.println("房东要往外出租房子");
    }
}

3、代理角色

public class Proxy implements Rent{
    private Host host;

    public Proxy() {
    }
    
    public Proxy(Host host) {
        this.host = host;
    }
    
    @Override
    public void rent() {
        seeHouse();
        host.rent();
        hetong();
        fare();
    }
    
    /*看房(附属操作)*/
    public void seeHouse() {
        System.out.println("中介带你看房");
    }
    
    /*收中介费(附属操作)*/
    public void fare() {
        System.out.println("收中介费");
    }
    
    /*签合同呢(附属操作)*/
    public void hetong() {
        System.out.println("签合同呢");
    }
}

4、客户端访问代理角色

public class Client {
    public static void main(String[] args) {
        Host host = new Host();
        // 代理:中介帮房东租房子,但是呢,代理一般会有一些附属操作。
        Proxy proxy = new Proxy(host);
        // 不用面对房东,直接找中介租房即可!
        proxy.rent();
    }
}

代理模式的好处:

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

缺点:

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

10.2 加深理解

扩展:《面向对象七大原则》之:单一职能原则

为什么不在原来的代码上添加扩展的功能:

1、改动源代码是公司的大忌。

代码对应08-demo02

聊聊AOP

image-20211203230750314

10.3 动态代理

动态代理:改变静态代理的缺点

  • 动态代理和静态代理角色一样
  • 动态代理的代理类是动态生成的,不是直接写好的
  • 动态代理分为两大类:基于接口的代理,基于类的代理
    • 基于接口的接口的代理:jdk动态代理【原生的】
    • 基于类:cglib
    • java字节码实现:javassist

需要了解两个类 Proxy、InvocationHandler调用处理程序

InvocationHandler

代码步骤:

1、创建抽象接口、真实角色、代理类

动态代理其实挺简单。就两个类。生成代理类Proxy.newProxyInvocation(参数1.参数2,参数3) 参数1:表明你要用那个类加载器去加载生成的代理类。(这个是JVM类加载的知识,这个类加载器只要是应用类的类加载器就行了,我管你哪一个,不过一般用当前类的类加载器)。 参数2:说明你要生成的代理类的接口。被代理类的对象 参数3:实现了InvocationHandle的类,这个类只有一个方法需要你要实现它。

invoke(Object proxy, Method method, Object【】 args) { 这个方法第一个参数,是生成的代理类,目前没发现用处,不管它。 第二个参数,是执行的方法(利用反射的原理,可以去看反射,也很简单。) 第三个参数,是执行某方法需要的参数。 第二个第三个参数解释执行的方法意思是:代理类不是要代理某个对象么,然后增强里面的方法么,指得就是这个方法,代理类会为几乎所有方法都增强,除非你在这里做判断。 返回值,是执行这个方法所返回的值。 然后你要去执行方法,就是用第二参数的invoke(obj,args);第一个参数是你要增强的对象。第二个是参数。object是你返回的类型 Object object= method.invoke(obj,args); }

InvocationHandler

/* 实现demo02的动态代理*/
/* 通过一个通用类,来实现,成为一个万能工具 */
public class ProxyInvocationHandler implements InvocationHandler {
    // 被代理的接口
    private Object target;

    public void setTarget(Object target) {
        this.target = target;
    }

    // 生成代理类
    public Object getProxy() {
        return Proxy.newProxyInstance(
                this.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        log(method.getName());
        Object result = method.invoke(target, args);
        return result;
    }

    // 日志方法 (实现代理的附属方法)
    public void log(String msg) {
        System.out.println("使用了" + msg + "方法");
    }
}

客户调用

public class Client {
    public static void main(String[] args) {
        // 真实角色
        UserService userService = new UserServiceImpl();
        // 获取代理角色,现在还不存在
        ProxyInvocationHandler pih = new ProxyInvocationHandler();
        pih.setTarget(userService);  // 设置要代理的对象
        // 动态生成代理类
        UserService proxy = (UserService) pih.getProxy();
        proxy.add();
    }
}

动态代理的好处:

  • 静态代理的好处+
  • 一个动态代理类(InvocationHandler)代理的是一个接口,一般对应的是一类业务
  • 一个动态代理类(InvocationHandler)可以代理多个类

11、 AOP

11.1 什么是AOP?

image-20211204012756443

image-20211204012820598

11.2 AOP在Spring中的应用

image-20211204012922537

image-20211204012952985

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

image-20211204013110847

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

11.3 使用Spring实现AOP

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

<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.7</version>
</dependency>

方式一:使用Spring的API接口

切面:

public class BeforeLog implements MethodBeforeAdvice {
    /**
     * Callback before a given method is invoked.
     * @param method the method being invoked  要执行的方法
     * @param args the arguments to the method  objects:参数
     * @param target the target of the method invocation. May be {@code null}. o
     * @throws Throwable if this object wishes to abort the call.
     * Any exception thrown will be returned to the caller if it's
     * allowed by the method signature. Otherwise the exception
     * will be wrapped as a runtime exception.
     */
    @Override
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println(target.getClass().getName() + "的" + method.getName() + "方法被执行");
    }
}

bean配置:

<bean id="userService" class="com.kuang.service.UserServiceImpl"/>
<bean id="beforeLog" class="com.kuang.log.BeforeLog"/>
<bean id="afterLog" class="com.kuang.log.AfterLog"/>

<!--方式一:使用原生Spring API接口-->
<!-- 配置aop-->
<aop:config>
    <!-- 首先需要一个切入点, expression表达式是固定的.要执行的位置execution([返回类型,*表示所有类型] 类名.方法名(参数))-->
    <aop:pointcut id="pointcut" expression="execution(* com.kuang.service.UserServiceImpl.*(..))"/>
    <!-- 执行环绕-->
    <aop:advisor advice-ref="beforeLog" pointcut-ref="pointcut"/>
</aop:config>

方式二:使用自定义类来实现AOP【主要是切面定义】

定义切面,代码:

public class DiyPointCut {
    public void before() {
        System.out.println("=======方法执行前==========");
    }
    public void after() {
        System.out.println("=======方法执行后==========");
    }
}

bean配置:

<bean id="userService" class="com.kuang.service.UserServiceImpl"/>
<bean id="beforeLog" class="com.kuang.log.BeforeLog"/>
<bean id="afterLog" class="com.kuang.log.AfterLog"/>

<!-- 方式二:自定义类-->
<bean id="diy" class="com.kuang.diy.DiyPointCut"/>
<aop:config>
    <!-- 切面:就是自定义的类-->
    <aop:aspect ref="diy">
        <!--切入点-->
        <aop:pointcut id="pointcut" expression="execution(* com.kuang.service.UserServiceImpl.*(..))"/>
        <aop:before method="before" pointcut-ref="pointcut"/>
        <aop:after method="after" pointcut-ref="pointcut"/>
    </aop:aspect>
</aop:config>

方式三:使用注解实现

image-20211204023151351

proxy-target-class="false" 默认就是jdk

切面代码

// 使用注解实现
@Aspect
public class AnnotationPointCut {
    @Before("execution(* com.kuang.service.UserServiceImpl.*(..))")
    public void before() {
        System.out.println("=======方法执行前==========");
    }

    @After("execution(* com.kuang.service.UserServiceImpl.*(..))")
    public void after() {
        System.out.println("=======方法执行后==========");
    }

    // 在环绕增强中,我们可以给定一个参数,代表我们要获取处理切入的点
    @Around("execution(* com.kuang.service.UserServiceImpl.*(..))")
    public void around(ProceedingJoinPoint jp) throws Throwable {
        System.out.println("=======方法执行前(环绕)==========");
        System.out.println(jp.getSignature());
        // 执行方法
        Object proceed = jp.proceed();
        System.out.println("=======方法执行后(环绕)==========");
    }
}

bean 配置:

<!-- 方式三:-->
<bean id="annotationPointCut" class="com.kuang.diy.AnnotationPointCut"/>
<!-- 开启注解支持  jdk(默认)  cglib -->
<aop:aspectj-autoproxy proxy-target-class="false"/>

切面代码输出:

=======方法执行前(环绕)==========
void com.kuang.service.UserService.add()
=======方法执行前==========
增加了一个用户
=======方法执行后==========
=======方法执行后(环绕)==========

12、整合Mybatis

步骤:

  1. 导入相关jar包
    • junit
    • mybatis
    • mysql
    • spring相关的
    • aop
    • mybatis-spring【新知识】、mybatis-spring-starter
  2. 编写配置文件
  3. 测试
MyBatis-Spring MyBatis Spring Framework Spring Batch Java
2.0 3.5+ 5.0+ 4.0+ Java 8+
1.3 3.4+ 3.2.2+ 2.1+ Java 6+

12.1 回忆Mybatis

1. 编写实体类

package com.kuang.pojo;
import lombok.Data;
@Data
public class User {
	private int id;
	private String name;
	private String pwd;
}

2. 编写核心配置文件: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>
    <typeAliases>
        <package name="com.kuang.pojo"/>
    </typeAliases>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="org.mariadb.jdbc.Driver"/>
                <property name="url" value="jdbc:mariadb://localhost:3306/mybatis"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>
    <!--注册接口-->
    <mappers>
        <mapper class="com.kuang.mapper.UserMapper"/> 
    </mappers>
</configuration>

3. 编写接口

package com.kuang.mapper;

import com.kuang.pojo.User;

import java.util.List;

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

4. 编写接口对应的xml: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.kuang.mapper.UserMapper">
    <select id="selectUser" resultType="user">
        select * from mybatis.user;
    </select>
</mapper>

5. 在mybatis-config.xml中注册接口,测试

public class MyTest {
    @Test
    public void test() throws IOException {
        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);
        }
    }
}

注:maven静态资源过滤问题,设置pom.xml

<build>
    <resources>
        <!-- maven静态资源过滤问题 -->
        <resource>
            <directory>src/main/java</directory>
            <includes>
                <include>**/*.properties</include>
                <include>**/*.xml</include>
            </includes>
            <filtering>true</filtering>
        </resource>
    </resources>
</build>

12.2 Mybatis-spring

mybatis-config.xml里的mappers 要删了,这个和 spring-dao的

<property name="mapperLocations" value="classpath:com/lzh/mapper/*.xml"/> 只能二选一!!!!!!不然会报错的,都是mapper的作用!

1、编写数据源配置

2、sqlSessionFactory

3、sqlSessionTemplete

4、给接口加实现类

spring整合mybatis,多了一个实现类,去自动创建

public class UserMapperImpl implements UserMapper{
    /*我们的所有操作,原来都是用SqlSession,现在使用SqlSessionTemplete*/
    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();

    }
}

5、将自己写的实现类,注入到spring中,测试使用

12.3 spring整合mybatis方式二:SqlSessionDaoSupport

【TODO:不太会,得补充一下mybatis】

13、声明式事务

1、回故事务

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

事务的ACID原则

原子性(Atomicity):所有的步骤要么全部完成,要么一个也不会完成

一致性(Consistency)即数据库事务不能破坏关系数据的完整性及业务逻辑上的一致性

隔离性(Isolation)

  • 多个业务可能操作同一个资源,防止数据破坏

持久性(Durability)

  • 事务一旦提交,无论系统发生什么问题,结果都不会被影响,被持久化的事务写到存储中。

2、spring中的事务

声明式事务:AOP应用,横切进去的,不影响业务

编程式事务:改变原有的代码。

image-20211205011125351

为什么需要声明式事务:

  • 如果不配置事务,可能存在数据提交不一致的情况
  • 如果不在啊Spring中配置声明式事务,就需要在代码中手动配置事务
  • 事务在项目的开发中十分重要,涉及到数据的一致性和完整性。
其他
1
https://gitee.com/acekevin/StudyNotes.git
git@gitee.com:acekevin/StudyNotes.git
acekevin
StudyNotes
StudyNotes
master

搜索帮助

53164aa7 5694891 3bd8fe86 5694891