Spring从入门到精通

1.spring了解

  1. spring重要性
    在当前的系统中,spring的重要性and占比性高达50%,无论是在ssm、ssh等框架中,spring始终屹立在前方,所以对于一个程序员来说,spring技术是每一个程序员必备的技术。好了,那我们就开始学习spring了吧~
    ···········
    在java程序中创建对象是必然的,只要需要对象就会去创建一个对象,但是呢创建后就没有销毁等操作了,这就意味着对象和内存就得不到更好的管理,虽然有垃圾回收机制,但是至于什么时候回收这也是jvm的事情,所以也不好判断,为了解决对象和内存的问题,spring就来的刚刚好。

  2. Spring概念
    spring可以看作是一个容器,容器里面装了很多的对象(bean)并且维护起来,要使用对象的时候,直接在容器里面取就可以了

  3. Spring作用
    Spring最主要的作用就是管理的对象的完整生命周期(对象的创建、使用、销毁等)包括对象之间的依赖关系给,spring都可以去管理

2. Spring实现

2.1 添加依赖

在maven项目中,要使用某一个框架呀啥的都是需要去导入对应的jar包的
依赖:

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

2.2 Spring实现

2.2.1 xml配置实现

当然哈,在使用配置文件进行操作的时候,实体类吖、dao层啊、service层的代码的连接自己要写好哟,spring的实现都是在这些基础上的哈。
在这里插入图片描述

  1. xml配置文件:
    第一种实现方式xml配置实现,既然是用xml配置文件实现,那就要去配置一下spring的xml文件了,在spring中的xml配置文件一般是用ApplicationContext.xml来命名存放的(记得是放在resource里面哟~)
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd">
         <!--先放在这里,先去完成controller、serviceImpl里面的对象创建再来填补这里代码-->  

注意:每一个xml配置文件,包括mybatis的config.xml吖、mapper.xml啊这些的xml文件,都会是有一个头的,这个头相当于就是告诉我们的编译器,这个xml文件是一个什么类型的xml文件

  1. 改变对象的创建方式
    以前使用方式:创建PetController的对象去调用service对象,service对象再去调用dao对象去完成,但是这样的话就很不方便,每一次要用对象的时候都要去new一个来用
    private PetService petService = new PetServiceImpl();
    spring方法:将对象都真装在容器里面,这样的话每一次要用直接调用set方法就行。这样的话不管什么时候想用都可以,所以就将controller和serviceImpl中的对象创建方式换一下:
    在这里插入图片描述
  2. 配置xml完整
    所有类都创建好后,就可以通过去配置xml文件,去反射出相应的对象,然后又因为ref的连接,所有对象又可以按照controller调用service调用dao去连接有了关系
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--    这里面就是放每一个对象啦(bean),每一个bean就是每一个对象,根据id去判断具体是那个类、接口的对象,然后通过反射就会去创建对应id的对象-->
    <bean id="petDao" class="com.xiaowang.dao.impl.PetDaoImpl">
<!--        获取dao层的对象,完成对数据库信息的管理-->
    </bean>
    
    <bean id="petService" class="com.xiaowang.service.impl.PetServiceImpl">
<!--        获取service层的对象,去调用dao层内对象,所以需要去与dao层进行关联-->
<!--        property标签内的name就是跟对象创建set的方法后面的方法名,也就是方法名去掉set的部分,
            比如:setPetDao——>petDao   setPetService——>petService
            然后ref里面的就是要连接容器中对象的id,-->
        <property name="petDao" ref="petDao"/>
    </bean>
    
    <bean id="petController" class="com.xiaowang.controller.PetController">
        <property name="petService" ref="petService"/>
    </bean>
    
<!--    相当于现在就在容器中放了三个对象了,三个对象的关系也由ref给连接起来了-->
    
</beans>
  1. 测试spring的代码
package com.xiaowang;

import static org.junit.Assert.assertTrue;

import com.xiaowang.controller.PetController;
import com.xiaowang.entity.Pet;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * Unit test for simple App.
 */
public class AppTest 
{
    /**
     * Rigorous Test :-)
     */
    @Test
    public void shouldAnswerWithTrue()
    {
        //创建容器对象,容器就是刚刚配置的xml文件
        ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("ApplicationContext.xml");
        //从容器中获取对象
        //getBean里面的name就是xml文件里面controller的id,根据这个id和后面的类类型,这样就可以拿到容器里面对应的对象
        PetController petController = classPathXmlApplicationContext.getBean("petController", PetController.class);
        //因为在xml配置文件中,controller、service、dao的对象关系已经连接了,所以也不用自己去实例化了
        Pet xiaowang = petController.add("xiaowang", "123456");
        System.out.println(xiaowang);
    }
}

结果:
在这里插入图片描述

2.2.1.1 Bean标签属性
id 表示bean在容器中的唯一标识 一般是类名首字母小写 如果没有写 默认值为 全路径#第几个  com.zlt.controller.UserController#0
        class 类的全路径
        init-method 初始化方法 对象创建后会被调用一次
        destroy-method 销毁方法 容器销毁之前会被调用一次
        scope="singleton" 作用范围
            singleton 单例模式 默认值 
            prototype 工厂模式 设置为工厂模式的时候销毁方法不会执行
            如果是在web项目中 request 请求作用域 session 会话作用域 globalSession 全局作用域
        autowire 自动装配
            byType 默认从容器中寻找对应的类型的bean注入进去  如果匹配到多个就会不知道注入谁进去
            byName 根据id和属性名进行自动注入
            constructor 通过构造来进行注入
            no 和 default 都相当于不自动注入
        lazy-init 懒加载 设置为true的时候容器创建时不会去初始化对象 默认false
2.2.2 注解实现

在一般的情况下,使用注解完成项目是更方便的,但是注解的实现一般都是自己的类才能去用注解完成,要是要使用外部的资源的话,就要用xml去配置完成,所以一般都是xml和注解一起使用。

  1. 注解的配置文件
    注解的配置都一样,都会有一个头部,所以这里注解的也会有一个:
<?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
         http://www.springframework.org/schema/beans/spring-beans.xsd
         http://www.springframework.org/schema/context
         http://www.springframework.org/schema/context/spring-context.xsd">
         <!--进行注解的配置-->
</beans>
  1. 开启注解
    扫描注解的时候。默认有开启注解
<!--    开启注解:注解是需要开启的-->
    <context:annotation-config></context:annotation-config>
<!--    扫描注解:扫描注解的话,是辉自动开启注解的,所以上面开启注解语句就可以不要了-->
    <context:component-scan base-package="com.xiaowang">
<!--        一般扫描的注解直接在包上就行了,这样的话,这个包下面的所有注解都可以被扫描了,不然要一个一个路径地去扫描-->
    </context:component-scan>
  1. 注解设置(各类)
    将需要放入spring容器的类加上对应的注解,将其放入spring容器中,然后就可以用了,如图:
    在这里插入图片描述
    注解解释:
    @Controller 一般写在类上 标记当前是控制器 将当前类的对象放入容器中 id默认是类名首字母小写
    @Service 一般写在类上 标记当前是业务层 将当前类的对象放入容器中 id默认是类名首字母小写
    @Repository 一般写在类上 标记当前是持久层 将当前类的对象放入容器中 id默认是类名首字母小写
    @Component 一般写在类上 不标记是哪一层 将当前类的对象放入容器中 id默认是类名首字母小写

  2. 注入值
    当spring容器中有了类的对象后,但是这些类对象的值是并没有设置的,所以我们需要去通过注解注入值的方式去完成赋值。并且虽然现在各类注解写了,但是还没有关联,所以可以通过注解去完成注解连接。

在这里插入图片描述
注入解释:

@Autowired 自动装配 默认从容器中获取bean并且自动注入到标记的内容上 可以标记在属性上 可以标记在set方法上 还可以标记在构造器上
    required 表示是否必须注入 如果是true 没找到注入的值会报错 如果是false就不会报错  可以自己去设置required的值
    	默认通过byType 没有就通过byName 
    @Qualifier("userServiceImpl")  一般配合@Autowired  一起使用
    @A
    @Resource(name = "userDaoImpl") 可以指定名称去进行注入
    
    @Value("aaa")  将aaa直接赋值给了变量a
    private String a ;

    @Value("${ccc}") 将properties文件中的ccckey的值赋值给了变量b
    private String b;

代码使用案例解释:

package com.xiaowang.controller;

import com.xiaowang.entity.Pet;
import com.xiaowang.service.PetService;
import com.xiaowang.service.impl.PetServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;

@Controller
public class PetController {
    //以前使用方式:创建PetController的对象去调用service对象,service对象再去调用dao对象去完成,但是这样的话就很不方便,每一次要用对象的时候都要去new一个来用
   // private PetService petService = new PetServiceImpl();

    //spring方法:将对象都真装在容器里面,这样的话每一次要用直接调用set方法就行。这样的话不管什么时候想用都可以
  //  @Resource(name = "petServiceImpl")//这个注解会在spring的容器中去找到name对应的id值,给注入到下面去,这个注解必须指定id
    @Autowired //自动装配,也就是通过byType去spring里面找到对应的资源注入进去,如果type没有就通过byName去找
   // @Qualifier("petServiceImpl")// 这个就是通过名称去找,一般和@Autowired配合使用
    private PetService petService;

    @Value("aaa")//这样子使用Value注解的话,就是直接将aaa赋值给了a,这还不如直接声明的时候=aaa,所以这个Value注解一般不这样用
    private String a;

    @Value("${url}")//注入配置文件中的数据进来,一般value注入用于将配置文件的值注入进来,注意这里要在spring的配置文件中,将要注入的properties文件加载到spring中
    private String b;

    //初始化方法的注解
    @PostConstruct //故名思意  构造器之前
    public void init(){
        System.out.println("petController的init");
    }

    //销毁方法的注解
    @PreDestroy //顾名思义  销毁之前
    public void destroy(){
        System.out.println("petController的destroy");
    }

  /*  public void setPetService(PetService petService) {
        this.petService = petService;
    }*/

    public Pet add(String username, String password){
        System.out.println("controller执行");
        System.out.println(a);
        System.out.println(b);
        return petService.add(username,password);
    }
}

2.2.2.1 注解解释
  1. 类注解
    @Controller 一般写在类上 标记当前是控制器 将当前类的对象放入容器中 id默认是类名首字母小写
    @Service 一般写在类上 标记当前是业务层 将当前类的对象放入容器中 id默认是类名首字母小写
    @Repository 一般写在类上 标记当前是持久层 将当前类的对象放入容器中 id默认是类名首字母小写
    @Component 一般写在类上 不标记是哪一层 将当前类的对象放入容器中 id默认是类名首字母小写

  2. 值注入注解
    @Autowired 自动装配,默认从spring中获取bean并且自动注入到标记的内容上,可以是类、属性、方法、字段等;这个注解有一个required属性值为true或false,默认是true,代表必须要找到注入的值,不然要报错
    @Qualifier( ) 具体注入的位置,一般配合着@Autowired使用,
    @Value(“aaa”) 直接赋值
    @Value(“${url}”) 通过取配置文件中的properties的具体name取注入所标记的值

  3. 作用范围注解
    @Scope(“prototype”) 一般加在类上 指定作用范围
    @PostConstruct 初始化方法注解
    @PreDestroy 销毁方法注解

3.Bean的生命周期

4. 代理模式

代理模式:代理模式是Java中一种常用的设计模式,主要就是提供一个代理对象对外提供一个方法,然后用过代理对象去访问目标表对象;

通俗理解:
实际就是创建一个与目标对象(实际要操作的对象)相同类型的代理对象proxy,使用这个proxy对象去访问目标对象完成操作,在这个proxy对象中还可以有其他的功能去丰富目标对象的功能。服务器最后调用的就是这个proxy对象,这样就完成了代理增强。

代理模式最主要的就是在不改变原来代码(就是目标对象)的情况下实现功能的增强

4.1 静态代理

4.1.1 静态代理理解

静态代理:相当于是自己写了一个代理类,在调用的时候调用的是代理类,代理类中的处理还是原生的处理逻辑,不过在前后添加上需要增强功能的代码。

缺点:需要为每一个被代理的对象都创建一个代理类。

4.1.2 静态代理实现
  1. 创建接口
public interface PetService {
    Pet add(String username, String password);
}
  1. 实现目标对象
public class PetServiceImpl implements PetService {
    public Pet add(String username, String password) {
        System.out.println("目标对象:petService执行");
        return petDao.add(username,password);
    }
}
  1. 实现代理对象
//代理对象
public class ProxyPetService implements PetService {
//    代理对象自己是不做事的,是交给目标对象做,相当于就是创建个目标对象,然后通过目标对象去完成方法,所以需要引入目标对象
    private PetService petService;
    //通过构造器去完成目标对象的创建
    public ProxyPetService(PetService petService) {
        this.petService = petService;
    }

    @Override
    public Pet add(String username, String password) {
        //可以加功能啥的了,就是要实现的方法,为了方便,就写一句输出就行
        System.out.println("代理增强功能1....");
        Pet add = petService.add(username, password);
        //增加代理功能
        System.out.println("代理增强功能2....");
        return add;
    }
}
  1. 测试代码
@Test
    public void testJingTai(){
        //要实现静态代理,就要将代理对象和目标对象进行关联起来,相当于就是要将目标对象放到代理对象中去
        PetService petService = new PetServiceImpl();//创建目标对象
        PetService proxyPetService = new ProxyPetService(petService);//创建代理对象
        //外部调用目标对象去完成增强功能呢
        Pet xiaowang = proxyPetService.add("xiaowang", "123456");
    }

注意:目标对象和代理对象要实现用一个接口,目标对象完成自己的事情,代理对象调用目标对象,不仅可以完成目标对象的事情,自己还可以再加一些功能上去

4.2 动态代理

动态代理模式最大的优势就是不用自己去写一个代理对象,它的代理对象会在java文件编译的时候,通过Java反射(javac的过程)去创建的。所以减少了程序员的工作。动态代理的实现有两种方式,现在来介绍一下

4.2.1 JDK动态代理

注意:JDK动态代理的目标对象必须有接口实现

jdk实现动态代理理解:
主要是通过Java反射包里面的类和接口去完成的。反射包里面有三个类:InvocationHandler、Method、Prixy

  1. 创建接口
public interface PetDao {
    Pet add(String username, String password);
}
  1. 目标对象
public class PetDaoImpl implements PetDao {
    @Override
    public Pet add(String username, String password) {
        System.out.println("petDao执行");
        return new Pet(username,password);
    }
}

  1. 代理对象执行器invoke
    要通过jdk反射来完成的话,要先去将代理对象的执行器invoke方法给构造好,所以需要实现反射包里面的InvovationHandler接口来完成了,相当于就是通过代理对象的执行器来完成
public class PetDaoInvoinvokecation implements InvocationHandler {

    //在执行器中还是需要有目标对象呀
    private Object obj;

    public PetDaoInvoinvokecation(Object obj) {
        this.obj = obj;
    }

    //invoke参数解释:proxy:代理对象,Method:代理对象的方法,args:代理对象所需的参数
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //动态代理模式不需要自己去写代理对象,而是在程序运行编译的时候就会创建的
        //真正的操作是由目标对象来完成的,所以通过method方法去完成执行器,里面参数就是目标对象以及目标对象要操作的方法的参数
        System.out.println("jdk增强之前..");
        Object invoke = method.invoke(obj, args);
        System.out.println("jdk增强之后..");
        return invoke;
    }
}

注意:是反射包( java.lang.reflect )里面的InvovationHandler接口哈

  1. 测试类
 @Test
    public void testJDK(){
        PetDao petDao = new PetDaoImpl();//目标对象
        // 代理对象执行器
        PetDaoInvoinvokecation petDaoInvoinvokecation = new PetDaoInvoinvokecation(petDao);
        /*
        代理对象,通过反射完成Proxy.newProxyInstance()
         newProxyInstance参数:
         类加载器:(代理对象的类型,也就是目标对象的)、
         目标对象所实现的接口:(返回是一个数组,因为一个类可以实现多个接口嘛)、
         执行器:
         */
        //代理对象的类型,是目标对象所实现的接口类型之一,就相当于静态代理的时候一样,目标对象和代理对象都是实现的同一个接口
        PetDao o = (PetDao) Proxy.newProxyInstance(petDao.getClass().getClassLoader(), petDao.getClass().getInterfaces(), petDaoInvoinvokecation);
        Pet xiaowang = o.add("xiaowang", "123456");//代理对象执行方法
        System.out.println(xiaowang);
    }

jdk动态模式原理:
主要是由反射包( java.lang.reflect )里面的InvocationHandler、Method、Prixy三个类来完成的。
①通过实现InvocationHandler接口去创建代理对象的执行器(重写invoke方法)
invoke方法:
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { }
invoke方法里面就是通过method去执行具体的代理对象的方法

②然后通过Prixy的newProxyInstance方法去获取代理对象
newProxyInstance参数:类加载器:(代理对象的类型,也就是目标对象的)、 目标对象所实现的接口:(返回是一个数组,因为一个类可以实现多个接口嘛)、 执行器:
③通过②里面的代理对象去调用目标对象的方法

注意代码中的注释!!

4.2.2 CJLIB动态代理

cglib代理模式是生成一个子类去完成的,并且不需要去实现接口

  1. 导入依赖
<!-- https://mvnrepository.com/artifact/cglib/cglib -->
<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>2.2.2</version>
</dependency>
  1. 创建目标对象
@Repository //将此类定义成持久层,然后将其放入spring中,里面可以加value参数的,加了就是这个持久层的id,默认是类名首字母是小写
//@Component //这个注解就是直接将此类放入spring中,不会标记此类的类型,一般用于普通类要放入spring的
public class PetDaoImplCGLIB{
    public Pet add(String username, String password) {
        System.out.println("目标对象 petDao执行");
        return new Pet(username,password);
    }
}
  1. MethodInterceptor拦截器
    cglib的实现最重要的就是去实现这个MethodInterceptor接口来完成,就像jdk时候的InvocationHandler一样
//拦截器去完成,记得是cglib包下面的哈
public class PetDaoImplCGLIBIntercepter implements MethodInterceptor {
    /*
        intercept参数介绍:
        Object:目标对象
         Method:目标对象的方法
         Object:目标对象方法的参数
         MethodProxy:代理方法
      */
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("cglib代理增强1.....");
        //调用目标对象执行方法
        Object o1 = methodProxy.invokeSuper(o, objects);
        System.out.println("cglib代理增强2.....");
        return o1;
    }
}

4. 测试
cglib的原理就是在运行的时候,cglib会自动去生成一个子类,在子类里面去完成增强操作(就是拦截器里面),这里我们来验证cglib就用保存它的子类来查验,也就是将它自动生成的类放在一个指定路径下去看。
在这里插入图片描述
编写cglib的测试类

 @Test
    public void testCGLIB(){
        //设置生成动态代理类的路径
        System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY,"E:\\xiaowang\\kuangjia\\spring\\cglib存放位置");
        //创建Enhancer对象,就相当于jdk中的proxy类一样的,作用就是去执行方法的啦~
        Enhancer enhancer = new Enhancer();
        //设置代理类的目标对象
        enhancer.setSuperclass(PetDaoImplCGLIB.class);
        //创建拦截器
        PetDaoImplCGLIBIntercepter petDaoImplCGLIBIntercepter = new PetDaoImplCGLIBIntercepter();
        //设置回调函数 设置增强对象
        enhancer.setCallback(petDaoImplCGLIBIntercepter);
        //创建代理对象,类型是目标对象类型哈
        PetDaoImplCGLIB o = (PetDaoImplCGLIB) enhancer.create();
        //执行方法
        Pet zhangsan = o.add("zhangsan", "123456");
        System.out.println(zhangsan);
    }

执行结果:
在这里插入图片描述
也执行出来了呀
在这里插入图片描述
注意:我们可以将生成的类反编译一下,就可以看到生成的类继承了我们的目标类,所以可以说明,cglib的原理其实就是cglib在底层继承了目标类然后去实现增强的
在这里插入图片描述

cglib动态代理原理:
①创建拦截器:继承MethodInterceptor的 intercepter的类,在拦截器中重写intercerpt( )方法,就是增强+目标对象的方法调用,返回拦截器

②在测试这边创建一个类似proxy的子类对象enhancer,然后设置这个代理对象的类型(setSuperclass(目标对象的类型.class完成))

③创建一个拦截器,enhancer通过去设置回调函数(setCallback(拦截器))

④创建代理对象enhancer.create(),代理对象的类型要和目标对象一致哈,然后通过代理对象去完成方法的调用

4.2.3 JDK和CGLIB区别
  1. JDK代理是基于有接口的情况下,而CGLIB没有接口也可以实现
  2. jdk是通过java的反射包的三个类(InvocationHandler、Method、Proxy)来完成的,而cglib是只针对类来实现的,原理就是对指定的目标类生成一个子类,并覆盖目标类的方法实现增强。
  3. cglib底层是采用了ASM字节码生成框架,使用字节码技术生成代理类,比使用java的反射效率要高一点
  4. cglib动态代理采用的是继承后重写,所以不能对final修饰的类进行代理,

4.3 静态动态代理区别

静态代理就是自己需要手动去写一个代理对象,实现目标对象所实现的接口,而动态代理却简化了这一步,不需要自己去写代理对象,而是在java编译的时候,通过反射完成了对象的创建。

5. AOP

5.1 AOP理解

OOP (Object Oriented Programming) 面向对象编程

AOP (Aspect Oritented Programming) 面向切面编程)

两者不是替代的关系而是互补的,AOP主要就是在不改变原本代码功能的情况下去新增功能

在spring中AOP很重要,可以理解为,AB业务互不影响且要去实现C的业务,但是我们需要在执行A业务的时候,在C业务功能的基础上,让A业务完成想要的功能,让B业务完成B业务需要的更强大的功能,前提就是C业务是基础业务是不能被更改的,不然就要影响其他业务。

所以在这个时候,AOP就做出了一个动作,A业务在C业务的想要添加的方法前面砍断,添加一个新的A自己的业务上去后,再将重新组合好的业务给织入原来的C业务方法那里去,继续执行C业务后面的功能。B业务一样的。

5.2 AOP实现

5.2.1 aop注解实现
  1. 添加依赖
<!-- https://mvnrepository.com/artifact/org.springframework/spring-aop -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aop</artifactId>
    <version>5.3.18</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjrt -->
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjrt</artifactId>
    <version>1.9.6</version>
    <scope>runtime</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-aspects -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aspects</artifactId>
    <version>5.3.18</version>
</dependency>

  1. 修改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
         http://www.springframework.org/schema/beans/spring-beans.xsd
         http://www.springframework.org/schema/context
         http://www.springframework.org/schema/context/spring-context.xsd
         http://www.springframework.org/schema/aop
         http://www.springframework.org/schema/aop/spring-aop.xs">

    <!--    注解实现:-->

<!--    开启注解:注解是需要开启的-->
<!--    <context:annotation-config></context:annotation-config>-->
<!--    扫描注解:扫描注解的话,是辉自动开启注解的,所以上面开启注解语句就可以不要了-->
    <context:component-scan base-package="com.xiaowang">
    </context:component-scan>

<!--    加载配置文件到spring里面,这样就可以去获取/置文件中的数据了-->
<!--    classpath:就是加载resource类路径下面的配置文件-->
    <context:property-placeholder location="classpath:db.properties"/>
    <!--
    开启动态代理
    proxy-target-class:
    如果为true那就是类代理,也就是jdk实现动态代理
    如果是false那就是cglib实现动态代理
    默认是false
    -->
    <aop:aspectj-autoproxy proxy-target-class="false"/>
</beans>

最主要的就是加上了:

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

http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xs

注意:使用AOP的话是需要开启动态代理的哈,proxy-target-class的值true代表jdk实现,false代表cglib实现

  1. 创建切面类
    创建切面类,将其放入spring中,我们这里来通过测试类中testJDK方法来演示,在UserServiceImpl中的public User login(String username, String password) { }这里进行切入:先看一下未切入之前的输出结果:
    在这里插入图片描述

开始创建切入类

//放入spring中
@Component
@Aspect //这个标签是标记这个类是一个切面
public class PetAspect {

    /**
     * 标记再哪里什么时候执行切入
     * @param joinPoint
     */


//    execution:里面写的就是切入点,切入点有很多种语法,下面这个是最精准的切入点,直接定位到了具体的方法,切入点的语法有很多,下面一一介绍
    @Before("execution(public com.xiaowang.entity.User com.xiaowang.PetService.impl.PetServiceImpl.login(java.lang.String,java.lang.String))")
    //想将下面这个方法切入到测试类中testJDK()方法的前面执行
    public void before(JoinPoint joinPoint){//JoinPoint参数是切入点的意思,具体的切入点通过before注解去填写就行
        //切入面中,是可以获取很多被拦截的东西,
        System.out.println("before之前执行");
        System.out.println("拦截的参数为:"+ Arrays.toString(joinPoint.getArgs()));
        System.out.println("拦截的方法为:"+joinPoint.getSignature().getDeclaringTypeName() + joinPoint.getSignature().getName());
        System.out.println("拦截的位置为:"+joinPoint.getStaticPart());
        System.out.println("代理对象为:"+joinPoint.getThis());
        System.out.println("目标对象为:"+joinPoint.getTarget());
    }
}

执行结果:
在这里插入图片描述
我们可以看到,就在login方法的前面就添加进去了我们的对象的方法,我们拦截的东西也可以看到了,这里同时还有多种类似于@before的注解,其功能就是在这个方法切入点的哪一个位置进行切入,例如还有:

/**
     * 标记再哪里什么时候执行切入,
     * @befor 代表在标记位置的前面切入
     * @param joinPoint
     */

//    execution:里面写的就是切入点,切入点有很多种语法,下面这个是最精准的切入点,直接定位到了具体的方法,切入点的语法有很多,下面一一介绍
    @Before("execution(public com.xiaowang.entity.Pet com.xiaowang.dao.impl.PetDaoImpl.add(java.lang.String,java.lang.String))")
    //想将下面这个方法切入到测试类中testJDK()方法的前面执行
    public void before(JoinPoint joinPoint){//JoinPoint参数是切入点的意思,具体的切入点通过before注解去填写就行
        //切入面中,是可以获取很多被拦截的东西,
        System.out.println("before之前执行");
        System.out.println("拦截的参数为:"+ Arrays.toString(joinPoint.getArgs()));
        System.out.println("拦截的方法为:"+joinPoint.getSignature().getDeclaringTypeName() + joinPoint.getSignature().getName());
        System.out.println("拦截的位置为:"+joinPoint.getStaticPart());
        System.out.println("代理对象为:"+joinPoint.getThis());
        System.out.println("目标对象为:"+joinPoint.getTarget());
    }

    /**
     * @After 在切入点的后面切入方法功能进去
     * 相当于finally执行,就是必备执行
     * @param joinPoint
     */

    @After("execution(public com.xiaowang.entity.Pet com.xiaowang.dao.impl.PetDaoImpl.add(java.lang.String,java.lang.String))")
    //想将下面这个方法切入到测试类中testJDK()方法的前面执行
    public void after(JoinPoint joinPoint){//JoinPoint参数是切入点的意思,具体的切入点通过before注解去填写就行
        //切入面中,是可以获取很多被拦截的东西,
        System.out.println("after执行");
        System.out.println("拦截的参数为:"+ Arrays.toString(joinPoint.getArgs()));
        System.out.println("拦截的方法为:"+joinPoint.getSignature().getDeclaringTypeName() + joinPoint.getSignature().getName());
        System.out.println("拦截的位置为:"+joinPoint.getStaticPart());
        System.out.println("代理对象为:"+joinPoint.getThis());
        System.out.println("目标对象为:"+joinPoint.getTarget());
    }

    /**
     * @AfterReturning 相当于正常执行,就是拦截方法正确执行后就可以执行
     * @param joinPoint
     */
    @AfterReturning("execution(public com.xiaowang.entity.Pet com.xiaowang.dao.impl.PetDaoImpl.add(java.lang.String,java.lang.String))")
    //想将下面这个方法切入到测试类中testJDK()方法的前面执行
    public void afterReturning(JoinPoint joinPoint){//JoinPoint参数是切入点的意思,具体的切入点通过before注解去填写就行
        //切入面中,是可以获取很多被拦截的东西,
        System.out.println("afterReturning执行");
        System.out.println("拦截的参数为:"+ Arrays.toString(joinPoint.getArgs()));
        System.out.println("拦截的方法为:"+joinPoint.getSignature().getDeclaringTypeName() + joinPoint.getSignature().getName());
        System.out.println("拦截的位置为:"+joinPoint.getStaticPart());
        System.out.println("代理对象为:"+joinPoint.getThis());
        System.out.println("目标对象为:"+joinPoint.getTarget());
    }

    /**
     * 拦截的语句那里抛出异常后被执行
     * @param joinPoint
     */
    @AfterThrowing("execution(public com.xiaowang.entity.Pet com.xiaowang.dao.impl.PetDaoImpl.add(java.lang.String,java.lang.String))")
    //想将下面这个方法切入到测试类中testJDK()方法的前面执行
    public void afterThrowing(JoinPoint joinPoint){//JoinPoint参数是切入点的意思,具体的切入点通过before注解去填写就行
        //切入面中,是可以获取很多被拦截的东西,
        System.out.println("afterThrowing执行");
        System.out.println("拦截的参数为:"+ Arrays.toString(joinPoint.getArgs()));
        System.out.println("拦截的方法为:"+joinPoint.getSignature().getDeclaringTypeName() + joinPoint.getSignature().getName());
        System.out.println("拦截的位置为:"+joinPoint.getStaticPart());
        System.out.println("代理对象为:"+joinPoint.getThis());
        System.out.println("目标对象为:"+joinPoint.getTarget());
    }

①拦截方法正常执行的时候结果:在这里插入图片描述

②拦截方法有异常的时候结果:
在这里插入图片描述

如果使用AOP去管理事务的话,那我们就可以在before里面写事务的开启,在afterReturning中提交事务,在afterThrowing中去回滚事务,

所以在@afterThrowing这里的话就可以再加一点属性,去设置哪些地方需要回滚,哪些地方不需要回滚

/**
     * 拦截的语句那里抛出异常后被执行,相当于catch
     * @param joinPoint
     */
    @AfterThrowing(value = "execution(public com.xiaowang.entity.Pet com.xiaowang.dao.impl.PetDaoImpl.add(java.lang.String,java.lang.String))",throwing = "e")
    //想将下面这个方法切入到测试类中testJDK()方法的前面执行
    public void afterThrowing(JoinPoint joinPoint,Exception e){//JoinPoint参数是切入点的意思,具体的切入点通过before注解去填写就行
        //切入面中,是可以获取很多被拦截的东西,
        System.out.println("afterThrowing执行");
        System.out.println("拦截的参数为:"+ Arrays.toString(joinPoint.getArgs()));
        System.out.println("拦截的方法为:"+joinPoint.getSignature().getDeclaringTypeName() + joinPoint.getSignature().getName());
        System.out.println("拦截的位置为:"+joinPoint.getStaticPart());
        System.out.println("代理对象为:"+joinPoint.getThis());
        System.out.println("目标对象为:"+joinPoint.getTarget());

        //事务
        System.out.println("抛出异常进行回滚"+e.getMessage());
    }

在这里插入图片描述
独特的环绕执行:

/**
     * 环绕执行,就像过滤器一样,再dofilt前面执行,后面执行
     * @param proceedingJoinPoint
     * @return
     */

    @Around(value = "execution(public com.xiaowang.entity.Pet com.xiaowang.dao.impl.PetDaoImpl.add(java.lang.String,java.lang.String))")
    //想将下面这个方法切入到测试类中testJDK()方法的前面执行
    public Object around(ProceedingJoinPoint proceedingJoinPoint){//JoinPoint参数是切入点的意思,具体的切入点通过before注解去填写就行
        //切入面中,是可以获取很多被拦截的东西,
        System.out.println("around之前执行");
        Object proceed = proceedingJoinPoint.proceed();//代理的方法执行
        System.out.println("around之后执行");
        return proceed;
    }
5.2.2 xml实现

使用xml实现当然前期的依赖呀、配置文件的头部那些基本的都是要有哈,和注解实现的前面一样,区别就在于对切面类的编写的时候,切入点不用写在注解上了,而是写在xml文件里了,也就是删掉or注释掉切面类中的注解呀


//放入spring中
@Component
@Aspect //这个标签是标记这个类是一个切面
public class PetAspect {

    /**
     * 标记再哪里什么时候执行切入,
     * @befor 代表在标记位置的前面切入
     * @param joinPoint
     */

//    execution:里面写的就是切入点,切入点有很多种语法,下面这个是最精准的切入点,直接定位到了具体的方法,切入点的语法有很多,下面一一介绍
  //  @Before("execution(public com.xiaowang.entity.Pet com.xiaowang.dao.impl.PetDaoImpl.add(java.lang.String,java.lang.String))")
    //想将下面这个方法切入到测试类中testJDK()方法的前面执行
    public void before(JoinPoint joinPoint){//JoinPoint参数是切入点的意思,具体的切入点通过before注解去填写就行
        //切入面中,是可以获取很多被拦截的东西,
        System.out.println("before之前执行");
        System.out.println("拦截的参数为:"+ Arrays.toString(joinPoint.getArgs()));
        System.out.println("拦截的方法为:"+joinPoint.getSignature().getDeclaringTypeName() + joinPoint.getSignature().getName());
        System.out.println("拦截的位置为:"+joinPoint.getStaticPart());
        System.out.println("代理对象为:"+joinPoint.getThis());
        System.out.println("目标对象为:"+joinPoint.getTarget());
    }

    /**
     * @After 在切入点的后面切入方法功能进去
     * 相当于finally执行,就是必备执行
     * @param joinPoint
     */

  //  @After("execution(public com.xiaowang.entity.Pet com.xiaowang.dao.impl.PetDaoImpl.add(java.lang.String,java.lang.String))")
    //想将下面这个方法切入到测试类中testJDK()方法的前面执行
    public void after(JoinPoint joinPoint){//JoinPoint参数是切入点的意思,具体的切入点通过before注解去填写就行
        //切入面中,是可以获取很多被拦截的东西,
        System.out.println("after执行");
        System.out.println("拦截的参数为:"+ Arrays.toString(joinPoint.getArgs()));
        System.out.println("拦截的方法为:"+joinPoint.getSignature().getDeclaringTypeName() + joinPoint.getSignature().getName());
        System.out.println("拦截的位置为:"+joinPoint.getStaticPart());
        System.out.println("代理对象为:"+joinPoint.getThis());
        System.out.println("目标对象为:"+joinPoint.getTarget());
    }

    /**
     * @AfterReturning 相当于正常执行,就是拦截方法正确执行后就可以执行
     * @param joinPoint
     */
  //  @AfterReturning("execution(public com.xiaowang.entity.Pet com.xiaowang.dao.impl.PetDaoImpl.add(java.lang.String,java.lang.String))")
    //想将下面这个方法切入到测试类中testJDK()方法的前面执行
    public void afterReturning(JoinPoint joinPoint){//JoinPoint参数是切入点的意思,具体的切入点通过before注解去填写就行
        //切入面中,是可以获取很多被拦截的东西,
        System.out.println("afterReturning执行");
        System.out.println("拦截的参数为:"+ Arrays.toString(joinPoint.getArgs()));
        System.out.println("拦截的方法为:"+joinPoint.getSignature().getDeclaringTypeName() + joinPoint.getSignature().getName());
        System.out.println("拦截的位置为:"+joinPoint.getStaticPart());
        System.out.println("代理对象为:"+joinPoint.getThis());
        System.out.println("目标对象为:"+joinPoint.getTarget());
    }

    /**
     * 拦截的语句那里抛出异常后被执行,相当于catch
     * @param joinPoint
     */
  //  @AfterThrowing(value = "execution(public com.xiaowang.entity.Pet com.xiaowang.dao.impl.PetDaoImpl.add(java.lang.String,java.lang.String))",throwing = "e")
    //想将下面这个方法切入到测试类中testJDK()方法的前面执行
    public void afterThrowing(JoinPoint joinPoint,Exception e){//JoinPoint参数是切入点的意思,具体的切入点通过before注解去填写就行
        //切入面中,是可以获取很多被拦截的东西,
        System.out.println("afterThrowing执行");
        System.out.println("拦截的参数为:"+ Arrays.toString(joinPoint.getArgs()));
        System.out.println("拦截的方法为:"+joinPoint.getSignature().getDeclaringTypeName() + joinPoint.getSignature().getName());
        System.out.println("拦截的位置为:"+joinPoint.getStaticPart());
        System.out.println("代理对象为:"+joinPoint.getThis());
        System.out.println("目标对象为:"+joinPoint.getTarget());

        //事务
        System.out.println("抛出异常进行回滚"+e.getMessage());
    }

  /*  *//**
     * 环绕执行,就像过滤器一样,再dofilt前面执行,后面执行
     * @param proceedingJoinPoint
     * @return
     *//*

    //@Around(value = "execution(public com.xiaowang.entity.Pet com.xiaowang.dao.impl.PetDaoImpl.add(java.lang.String,java.lang.String))")
    //想将下面这个方法切入到测试类中testJDK()方法的前面执行
    public Object around(ProceedingJoinPoint proceedingJoinPoint){//JoinPoint参数是切入点的意思,具体的切入点通过before注解去填写就行
        //切入面中,是可以获取很多被拦截的东西,
        System.out.println("around之前执行");
        Object proceed = proceedingJoinPoint.proceed();//代理的方法执行
        System.out.println("around之后执行");
        return proceed;
    }
*/
}

注意:我们在切面类上面加了@Aspect 这个注解后,就代表着这是一个切面了,就不用在xml中去通过<aop:aspect ref=“userAspect”>去定义这个类未切面类,两种方法二选一即可。

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

    <!--    注解实现:-->

<!--    开启注解:注解是需要开启的-->
<!--    <context:annotation-config></context:annotation-config>-->
<!--    扫描注解:扫描注解的话,是辉自动开启注解的,所以上面开启注解语句就可以不要了-->
    <context:component-scan base-package="com.xiaowang"> </context:component-scan>

<!--    加载配置文件到spring里面,这样就可以去获取/置文件中的数据了-->
<!--    classpath:就是加载resource类路径下面的配置文件-->
    <context:property-placeholder location="classpath:db.properties"/>

<!--    装配注解,也就是将各个注解进行关联起来-->

    <!--
    开启动态代理
    proxy-target-class:
    如果为true那就是类代理,也就是jdk实现动态代理
    如果是false那就是cglib实现动态代理
    默认是false
    -->
<aop:aspectj-autoproxy proxy-target-class="false"/>

<!--    使用xml去实现aop-->
    <aop:config>
<!--        定义切面信息,如果切面类上使用了@Aspect注解,就可以不用定义这个切面类信息,但是切面点啥的还是要配置-->
        <aop:aspect ref="petAspect">
<!--            定义切面点-->
            <aop:pointcut id="add" expression="execution(public com.xiaowang.entity.Pet com.xiaowang.dao.impl.PetDaoImpl.add(java.lang.String,java.lang.String))"/>
<!--            实现切面类的增强功能-->
            <aop:before method="before" pointcut-ref="add"/>
            <aop:after-returning method="afterReturning" pointcut-ref="add"/>
            <aop:after-throwing method="afterThrowing" throwing="e" pointcut-ref="add"/>
            <aop:after method="after" pointcut-ref="add"/>
        </aop:aspect>
    </aop:config>
</beans>
5.2.3 切入点语法
直接精准到一个方法上面去
execution( public com.zlt.entity.User com.zlt.service.impl.UserServiceImpl.login(java.lang.String,java.lang.String))
任意权限修饰符
execution(  com.zlt.entity.User com.zlt.service.impl.UserServiceImpl.login(java.lang.String,java.lang.String))
无返回类型
execution( void com.zlt.service.impl.UserServiceImpl.login(java.lang.String,java.lang.String))
有返回类型
execution( !void com.zlt.service.impl.UserServiceImpl.login(java.lang.String,java.lang.String))
任意返回类型
execution( * com.zlt.service.impl.UserServiceImpl.login(java.lang.String,java.lang.String))
任意参数
execution( * com.zlt.service.impl.UserServiceImpl.login(..))
类中的任意方法
execution( * com.zlt.service.impl.UserServiceImpl.*(..))
类中以指定内容开头的方法
execution( * com.zlt.service.impl.UserServiceImpl.select*(..))
包中的任意类的任意方法不包含子包下面的类
execution( * com.zlt.service.impl.*.*(..))
包中及其下的任意类的任意方法
execution( * com.zlt.service..*.*(..))

5.3 AOP应用场景

  1. 事务管理的时候(before里开启事务、afterThowning回滚事务,after提交事务)
  2. 获取某个功能的执行时间(before设置开始时间、after设置结束时间)
  3. …等等

6. spring整合mybatis

通过事务来完成spring于muybatis的整合,流程:

  1. 导入所有依赖
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
<!--    spring依赖-->
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.3.18</version>
    </dependency>
<!--     AOP的依赖-->
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-aop -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aop</artifactId>
      <version>5.3.18</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.aspectj/aspectjrt -->
    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjrt</artifactId>
      <version>1.9.6</version>
      <scope>runtime</scope>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-aspects -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aspects</artifactId>
      <version>5.3.18</version>
    </dependency>

<!--    spring事务相关的依赖-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-tx</artifactId>
      <version>5.3.24</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-orm</artifactId>
      <version>6.0.6</version>
    </dependency>

<!--    mybatis相关依赖-->
    <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
      <version>3.4.6</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.38</version>
    </dependency>

<!--    !!!!spring和mybatis整合,需要用一个插件依赖!!!!-->
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis-spring</artifactId>
      <version>3.0.0</version>
    </dependency>

<!--    使用自己的连接池德鲁伊-->
    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>druid</artifactId>
      <version>1.1.21</version>
    </dependency>

<!--    使用逆向工程完成数据库操作-->
    <dependency>
      <groupId>org.mybatis.generator</groupId>
      <artifactId>mybatis-generator-core</artifactId>
      <version>1.4.0</version>
    </dependency>

<!--    分页-->
    <dependency>
      <groupId>com.github.pagehelper</groupId>
      <artifactId>pagehelper</artifactId>
      <version>5.2.0</version>
    </dependency>

<!--    日志-->
    <dependency>
      <groupId>log4j</groupId>
      <artifactId>log4j</artifactId>
      <version>1.1</version>
    </dependency>
    <dependency>
      <!--      添加一个lombok依赖,这样一会实体类的构造器、get、set方法就不用手写了-->
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <version>1.18.16</version>
    </dependency>

  </dependencies>
  1. 编写所有的配置文件
<?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"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="
         http://www.springframework.org/schema/beans
         http://www.springframework.org/schema/beans/spring-beans.xsd
         http://www.springframework.org/schema/context
         http://www.springframework.org/schema/context/spring-context.xsd
         http://www.springframework.org/schema/aop
         http://www.springframework.org/schema/aop/spring-aop.xsd
         http://www.springframework.org/schema/tx
         http://www.springframework.org/schema/tx/spring-tx.xsd">
    <!--注解扫描 默认开启注解支持-->
    <context:component-scan base-package="com.xiaowang"> </context:component-scan>
    <!--开启动态代理-->
    <aop:aspectj-autoproxy/>
    <!--引入外部文件,这里是为了将db.properties里面的数据源给引入,然后后面放入mybatis的配置中-->
    <context:property-placeholder location="classpath:db.properties"/>

<!--    创建数据源-->
    <!--    因为我们要使用的是外部的德鲁伊连接池,所以需要用xml去配置数据源,这样就和数据库连接上了-->
    <bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
    <!--    将db.propertise中的连接池数据给注入到我们的数据源中-->
        <property name="driverClassName" value="${jdbc.driver}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    <!--    这里还可以根据数据库连接池去配置最大连接数等等-->
    </bean>

             <!--配置mybatis东西-->
<!--    首先配置会话工厂,这个工厂是mybatis-spring这个插件里面的-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <!--    注入数据源-->
        <property name="dataSource" ref="druidDataSource"/>
    <!--    在mybatis中还会有很多映射文件,比如mapper包里面的mapper.xml那些对某一个类进行xml操作的配置文件-->
        <property name="mapperLocations" value="classpath:mapper/**.xml"/>

    <!--   别名配置呀,我使用spring的就可以注释了-->
            <!--<property name="typeAliasesPackage" value="com.xiaowang.entity"/>-->

    <!--   引入mybatis自己的配置文件,我使用spring的就可以注释了-->
            <!-- <property name="configLocation" value="classpath:mapper_config.xml"/>-->

    <!--   添加插件,这里演示分页插件-->
        <property name="plugins">
    <!--   直接使用spring的分页插件,需要注入数据,分页的对象是数组,所以要用数组的方式去注入数据-->
            <array>
                <bean class="com.github.pagehelper.PageInterceptor">
    <!--        分页里面还可以定义自己的东西-->
                    <property name="properties" >
                        <props>
    <!--                方言-->
                            <prop key="helperDialect">mysql</prop>
    <!--                分页参数合理化-->
                            <prop key="reasonable">true</prop>
                        </props>
                    </property>
                </bean>
            </array>
        </property>

    <!--     一些配置,比如开启缓存啥的-->
    </bean>

<!--    接口扫描,
        也就是mybatis中我们去getMapper的时候一样的意思,spring可以去扫描这些接口,然后我们就可以拿到对应的数据-->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    <!--    扫描的接口,也就是需要扫描哪些包里面的接口,一般放包名是最好的-->
        <property name="basePackage" value="com.xiaowang.mapper"/>
    <!--    设置会话工厂,也就是相当于去会话工厂的数据里面去扫描接口,sqlSessionFactory-->
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
    </bean>

<!--    事务管理-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <!--   注入数据源,也就是要对哪些进行事务管理-->
        <property name="dataSource" ref="druidDataSource"/>
    </bean>
    <!--    事务是注解管理的-->
    <tx:annotation-driven transaction-manager="transactionManager"/>
    <!--    注意事务管理对象的id和注解管理的manager要一致才行哈-->
</beans>
  1. mybatis逆向工程导入
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
        PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
    <!--数据库驱动-->
    <classPathEntry    location="E:\MySQL\mysql-connector-java-5.1.16\mysql-connector-java-5.1.16\mysql-connector-java-5.1.16-bin.jar"/>
    <context id="DB2Tables"    targetRuntime="MyBatis3">
        <commentGenerator>
            <property name="suppressDate" value="true"/>
            <property name="suppressAllComments" value="true"/>
        </commentGenerator>
        <!--数据库链接地址账号密码-->
        <jdbcConnection driverClass="com.mysql.jdbc.Driver" connectionURL="jdbc:mysql:///weibo67?useUnicode=true&amp;useSSL=false&amp;characterEncoding=utf-8&amp;rewriteBatchedStatements=true" userId="root" password="youngc777">
        </jdbcConnection>
        <javaTypeResolver>
            <property name="forceBigDecimals" value="false"/>
        </javaTypeResolver>
        <!--生成Model类存放位置-->
        <javaModelGenerator targetPackage="com.xiaowang.entity" targetProject="src/main/java">
            <property name="enableSubPackages" value="true"/>
            <property name="trimStrings" value="true"/>
        </javaModelGenerator>
        <!--生成映射文件存放位置-->
        <sqlMapGenerator targetPackage="mapper" targetProject="src/main/resources">
            <property name="enableSubPackages" value="true"/>
        </sqlMapGenerator>
        <!--生成Dao类存放位置-->
        <javaClientGenerator type="XMLMAPPER" targetPackage="com.xiaowang.mapper" targetProject="src/main/java">
            <property name="enableSubPackages" value="true"/>
        </javaClientGenerator>
        <!--生成对应表及类名-->
        <table tableName="weibo" domainObjectName="Weibo" enableCountByExample="true" enableUpdateByExample="true" enableDeleteByExample="true" enableSelectByExample="true" selectByExampleQueryId="true"></table>
        <table tableName="user" domainObjectName="User" enableCountByExample="true" enableUpdateByExample="true" enableDeleteByExample="true" enableSelectByExample="true" selectByExampleQueryId="true"></table>
         </context>
</generatorConfiguration>

mybatis逆向工程就完成了呀,可以看见那些功能都创建了,然后就可以去创建controller、servcie进行操作了呀
在这里插入图片描述

  1. 执行测试文件
    执行后,就可以了呀,mybatis将该有的都自动生成了,

所有的配置都是一条线的,所以弄清楚这条线,就知道该怎么一步步去配置了,可以记一下:线路:
①添加对应的依赖
②在spring中配置相应的bean对象。并且开启注解扫描、开启动态代理、引入外部文件等
③bean对象:
1. 创建数据源: 数据源里面存的就是对数据库连接的参数信息,相当于与数据库进行连接
2. 配置mybatis:先创建会话工厂、然后注入数据源、还可以配置一些别名呀、添加插件呀什么的,那些你需要mybatis操作的东西
3. 接口扫描:配置要扫描的接口,这些接口一般就是mapper里面的接口了,还有就是会话工厂里面要实现的接口了,具体要实现什么接口就配置对应的接口就好了呀
4. 事务管理:通过spring的jdbc去进行事务管理,在配置事务管理的时候,需要将数据源给注入到事务管理中去噢,注意这里的 id 必须要和实现事务管理的transaction-manager一致
5.注解实现事务:通过注解去完成事务的管理,也就是在对应的service呀等要对事务进行管理的时候,加上注解@Transaction,就可以实现事务管理了

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值