淘先锋技术网

首页 1 2 3 4 5 6 7

Spring

1.1 简介

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

  • Spring maven:

    <dependency>
       <groupId>org.springframework</groupId>
       <artifactId>spring-webmvc</artifactId>
       <version>4.0.3.RELEASE</version>
    </dependency>
    

1.2 优点

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

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

2、set注入

  • 在不使用set注入以前时,用户每新增一个需求一个业务dao,程序员都需要在实现类中new这个业务类,使得代码改动量极大。

  • 使用set注入是在业务实现类xxxServiceImpl.java中添加用户属性setter方法,用该方式后,在业务层就只需要导入这个业务的接口实现类即可。

    //使用new 的方式使得每次更改需求都要重新new新的实现接口类
    //private UserDao userDao=new UserDaoImpl();
    private UserDao userDao;
    //使用setter方法可以动态实现值的注入
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }
    public void getUser() {
        userDao.getUser();
    }
    

测试类中代码就只需要改变业务实现类:

public class MyTest {
    public static void main(String[] args) {
        //不使用set之前的常规写法,每次new出要实现的业务实现类
        UserService userService=new UserServiceImpl();
        //使用set注入
        ((UserServiceImpl) userService).setUserDao(new UserDaoSqlImpl());
        userService.getUser();
    }
}

3、IOC控制反转

  • 配置文件的主要内容:

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
            https://www.springframework.org/schema/beans/spring-beans.xsd">
        <!--使用spring来创建对象,在spring中这些都称为bean-->
        <bean id="User" class="com.yl.dao.UserDaoImpl"/>
        <bean id="UserSql" class="com.yl.dao.UserDaoSqlImpl"/>
        <bean id="ha" class="com.yl.service.UserServiceImpl">
    <!--        ref:引用spring容器中的bean
                value:给对象属性赋值。例如给str=”spring“
    -->
            <property name="userDao" ref="UserSql"/>
        </bean>
    </beans>
    

需要注意:

  • property中的name属性是某个对象实例
  • ref是引用spring容器中的bean
  • value是给该对象属性赋值
  • 依赖注入就是通过set方法实现

测试类中:

//使用注解则ClassPathXmlApplicationContext固定
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
//getBean得到指定的bean
HelloSpring hello = (HelloSpring) context.getBean("hello");

总结:

IOC核心就是:对象由spring来创建、管理、装配!

4、IOC创建对象方式

  1. 使用无参构造创建对象

    <bean id="noCan" class="com.yl.pojo.User">
        <property name="name" value="yl"/>
    </bean>
    
  2. 使用有参构造创建对象

    • 使用下标赋值

      <bean id="youCanIndex" class="com.yl.pojo.User">
          <constructor-arg index="0" value="有参之下标方式"/>
      </bean>
      
    • 通过类型赋值(多个参数不好办了,所以不建议使用)

      <bean id="youCanType" class="com.yl.pojo.User">
          <constructor-arg type="java.lang.String" value="有参之类型"/>
      </bean>
      
    • 参数名

      <bean id="youCanType" class="com.yl.pojo.User">
          <constructor-arg name="name" value="有参之参数名"/>
      </bean>
      

总结:在配置文件加载的时候,容器中管理的对象就已经被实例化了!

5、Spring配置

5.1、别名

<!--    name:前面某个bean的id对应的变量名,alias:取的新别名-->
    <alias name="user" alias="haha"/>

5.2、Bean的配置

 <!--
        id:bean的唯一标识符
        class:bean 对象所对应的全限定名:包名+类型
        name:也是别名,且可以用空格、逗号、分号隔开
        -->
    <bean id="user" class="com.yl.pojo.User" name="u1 u2,u3;u4">
        <property name="name" value="str"/>
    </bean>

5.3、import

这个import用于团队开发,可以将多个bean的配置文件,合并导入到总的applicationContext.xml中。重名的对象也会被合并。

6、依赖注入

6.1、构造器注入

6.2、set方式注入

  • set依赖:所有的对象创建依赖于容器
  • 注入:所有的对象属性由容器注入

项目:spring-04-di

实体类属性:

    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;

配置文件中各种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.yl.pojo.Address">
        <property name="address" value="西华"/>
    </bean>
    <bean id="student" class="com.yl.pojo.Student">
        <!-- 第一种:普通值注入,value-->
        <property name="name" value="yl"/>

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

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

        <!-- 第四种:List注入,value-->
        <property name="hobby">
            <list>
                <value>听歌</value>
                <value>唱歌</value>
                <value>跳舞</value>
            </list>
        </property>

        <!-- 第5种:Map注入,entry:key-value-->
        <property name="card">
            <map>
                <entry key="身份证" value="1111111111123"/>
                <entry key="学号" value="2109456465"/>
            </map>
        </property>

        <!-- 第6种:set注入,set-value-->
        <property name="games">
            <set>
                <value>幻塔</value>
                <value>王者荣耀</value>
            </set>
        </property>

        <!-- 第7种:null注入,null-->
        <property name="wife">
            <null/>
        </property>

        <!-- 第8种:Properties注入,-->
        <property name="info">
            <props>
                <prop key="driver">123</prop>
                <prop key="username">root</prop>
                <prop key="url">456</prop>
                <prop key="password">123546</prop>
            </props>
        </property>
    </bean>
</beans>

测试:

public class MyTest {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        Student student = (Student) context.getBean("student");
        System.out.println(student.toString());
        /*
        Student{
         name='yl', 
         address=Address{address='西华'},
          books=[红楼梦, 西游记, 水浒传, 三国演义], 
          hobby=[听歌, 唱歌, 跳舞], 
          card={身份证=1111111111123, 学号=2109456465},
          games=[幻塔, 王者荣耀], 
          wife='null', 
          info={password=123546, url=456, driver=123, username=root}}
           */
    }
}

6.3、拓展注入方式

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

bean的写法:

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

bean的写法:

需要注意的是使用p,c注入时需要约束即xmlns路径,且c注入是需要有参构造而p注入需要无参构造。

1、单例模式,使用scope=singleton,此时即使创建多个对象也是调用的同一个bean,他们的结果就相同(spring默认机制)

2、原型模式,使用scope=prototype,get同一个bean,创建多个不同的对象

7、bean自动装配

7.1、byName自动装配

byName需要注入bean id需要和set方法后面名字相同,否则会装配失败

<!--
    byName:会自动在容器上下文查找,和自己对象set方法后的值对应的bean id,就比如上面的cat、dog,
    在前面的实体类中存在set方法后面的名字等于cat和dog,所以能够找到。
-->
 <bean id="people" class="com.yl.pojo.People" autowire="byName">
     <property name="name" value="小花"/>
 </bean>

7.2、byType自动装配

<!--    byType:会自动在容器上下文查找和自己对象类型相同的bean,但byType必须保证该类型全局唯一-->
    <bean id="people" class="com.yl.pojo.People" autowire="byType">
        <property name="name" value="小花"/>
    </bean>

7.3、使用注解实现自动装配

自动装配须知:

  1. 添加注解约束:

    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"
    
  2. 添加注解支持

使用@Autowired可以不用编写set方法,前提是这个自动装配的属性在IOC(spring)容器中存在,且符合名字byName。

有多个对象时,可以使用@Qualifier(value=“”)来指定某个bean实现装配。

@Resource更强大,先去通过名字查找,再通过类型查找,都找不到才会报错,且存在@Resource(name=“”)的写法,用于明确某个bean。

8、使用注解开发

8.1、使用属性注解

在spring中使用注解开发须知:

​ 1、需要在配置文件中导入aop的包:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9zMz4lPg-1663316208382)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20220325094620826.png)]

​ 2、添加扫描器,可以去扫描该包下所有的bean并生效:

<!--    扫描包下所有的bean,不能写出具体某个实体类-->
    <context:component-scan base-package="com.yl.pojo"/>
<!--    自动装配驱动-->
    <context:annotation-config/>

实体类pojo:

@Component
public class User {
    //@Value也可以放在set方法上
    @Value("yl2")
    public String name;
}

测试:

     ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
       //在使用注解时,由于配置文件中并没有bean,也就没有属性id,这里是使用该类名字的小写(类一般不重名)
        User user = (User) context.getBean("user");
        System.out.println(user.name);
    }

8.2、衍生注解

@Component有几个衍生注解,,在web开发中就是按照mvc三层结构分。

  • dao层:使用@Repository
  • service层:使用@Service
  • controller层:使用@Controller

这四个注解都是将某个类注册到sprng容器中,装配bean,每个层名字不同用于区分!

8.3、小结

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-n22othhI-1663316208384)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20220325102519720.png)]

9、使用Java的方式配置spring

实体类:

package com.yl.pojo;

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

@Component
public class User {
    private String name;
    public String getName() {
        return name;
    }

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

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

配置类:

package com.yl.config;

import com.yl.pojo.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

//@Configuration代表这是一个配置类,就和我们之前的bean.xml一样
//@ComponentScan("")用于扫描包,扫到的包都会生效
@Configuration
public class MyConfig {
    //注册一个bean,就相当之前我们写的一个bean标签
    //方法的名字就相当于bean标签中的id属性
    //这个方法的返回值就相当于bean标签的class属性,返回类型
    @Bean
    User getUser(){
        return new User();
    }
}

测试类:

import com.yl.config.MyConfig;
import com.yl.pojo.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class MyTest {
    @Test
    public void test(){
        //如果完全使用配置类去做,就只能使用AnnotationConfig 上下文来获取容器,通过配置类的class对象
        ApplicationContext myConfig = new AnnotationConfigApplicationContext(MyConfig.class);
        //这里的getUser就是配置类中的一个需要注入的方法名
        User getUser = myConfig.getBean("getUser",User.class);
        System.out.println(getUser.getName());
    }
}

多个配置类就相当于多个bean,直接在配置类中添加@Import(xxx.class)即可

10、代理模式

代理模式是SpringAOP的底层

代理模式分类:

  • 静态代理
  • 动态代理
image-20220328202009582

10.1、静态代理

角色分析:

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

对应代码:spring-08-proxy的demo01

代码步骤:

  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() {
            host.rent();
            seeHouse();
            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、加深理解

对应代码:spring-08-proxy的demo02

image-20220328211240232

静态代理小结:

  1. 编写接口:接口中是真实角色想干的事情,但是真实角色不想自己亲自去干,太麻烦!

    public interface UserService {
        public void add();
        public void delete();
        public void update();
        public void query();
    }
    
  2. 编写真实角色(接口实现类):是关于真实角色具体要干的事情(一般不会选择更改这里面的代码!!)

    public class UserServiceImpl implements UserService{
        @Override
        public void add() {
            System.out.println("增加了一个用户!");
        }
    
        @Override
        public void delete() {
            System.out.println("删除了一个用户!");
        }
    
        @Override
        public void update() {
            System.out.println("修改了一个用户!");
        }
    
        @Override
        public void query() {
            System.out.println("查询了一个用户!");
        }
    //宗旨就是不改变这个里面的代码,在代理中添加附属操作
    }
    
  3. 编写代理(就好比中介):在代理中使用set方法绑定真实角色(使得有更多的真实角色也可以快捷更改),实现接口中的方法(就是帮真实角色要干的事情),在代理中可以有许多附属操作。

    public class UserServiceProxy implements UserService{
        private UserServiceImpl userService;
        //使用set方法使得客户端可以让代理想获取哪个UserServiceImpl都行
        public void setUserService(UserServiceImpl userService) {
            this.userService = userService;
        }
        @Override
        public void add() {
            log("add");
            userService.add();
        }
        @Override
        public void delete() {
            log("delete");
            userService.delete();
        }
        @Override
        public void update() {
            log("update");
            userService.update();
        }
        @Override
        public void query() {
            log("query");
            userService.query();
        }
        //附属操作:日志等
        public void log(String msg){
            System.out.println("Debug使用了"+msg+"方法");
        }
    }
    
  4. 编写客户端:创建代理对象,创建真实角色对象,代理绑定真实角色,将真实角色的事交给代理角色去办

    public class Client {
        public static void main(String[] args) {
            //创建一个真实角色
            UserServiceImpl userService = new UserServiceImpl();
            //创建代理角色
            UserServiceProxy userServiceProxy = new UserServiceProxy();
            //将真实角色的事交给代理角色去办
            userServiceProxy.setUserService(userService);
            userServiceProxy.query();
    
        }
    }
    

10.3、动态代理

  • 动态代理和静态代理角色一样
  • 动态代理的代理类是动态生成的!
  • 动态代理分为两大类:基于接口的动态代理,基于类的动态代理
  1. 基于接口:JDK动态代理
  2. 基于类:cglib
  3. Java字节码实现:javassist

动态代理的好处:静态代理的好处都有且一个动态代理可以代理多个类,只要实现了同一个接口即可。(例如接口为UserService,而实现类有UserServiceImpl,UserServiceImpl2,他们都是实现的UserService,在客户端中只需要更改绑定的真实角色UserServiceImpl,UserServiceImpl2即可)。

动态代理处理程序:

public class ProxyInvocationHandler implements InvocationHandler {
    //target:要代理的接口(真实角色),set方法就是来绑定要帮哪个真实角色做事
    private Object target;
    public void setTarget(Object target) {
        this.target = target;
    }
    //生成并得到代理类
    public Object getProxy(){
        return Proxy.newProxyInstance(this.getClass().getClassLoader(),
                target.getClass().getInterfaces(),this);
    }
    //处理代理实例,并返回结果(就是相当于静态代理中的代理角色帮真实角色做事),这里是使用invoke方法来实现
    @Override
    public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
        //动态代理的本质就是通过反射机制实现!method:接口中的一些方法
        log(method.getName());
        Object result=method.invoke(target,objects);
        return result;
    }
    //代理程序中的其他附属操作
    public void log(String msg){
        System.out.println("使用了"+msg+"方法");
    }
}

客户端:

public class Client {
    public static void main(String[] args) {
        //真实角色
        UserServiceImpl userService=new UserServiceImpl();
        //代理角色,现在还不存在,需要我们使用代理角色程序生成
        ProxyInvocationHandler pih=new ProxyInvocationHandler();

        //绑定被代理的真实角色
        pih.setTarget(userService);

        //生成代理角色(接口是什么类型就转换成什么类型)
        UserService proxy = (UserService) pih.getProxy();

        //代理角色开始办事
        proxy.query();
    }
}

11、AOP

11.1、什么是AOP

面向切面编程

image-20220329192918312

11.2、AOP在Spring中的作用

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

image-20220329193224279

11.3、使用Spring实现AOP

使用AOP注入,需要导入一个依赖包

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

方式一:使用Spring的API接口

前置和后置方法:

public class log implements MethodBeforeAdvice {
    @Override
    //method:要执行的目标对象的方法
    //args:参数
    //target:目标对象
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println("执行了"+target.getClass().getName()+"的方法:"+method.getName());
    }
}
//后置
public class AfterLog implements AfterReturningAdvice {
    @Override
    //returnValue:返回值
    public void afterReturning(Object returnValue, Method method, Object[] objects, Object target) throws Throwable {
        System.out.println("执行了"+method.getName()+"方法,结果为:"+returnValue);
    }
}

配置文件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">

<!--    注册bean-->
    <bean id="userService" class="com.yl.service.UserServiceImpl"/>
    <bean id="log" class="com.yl.Log.log"/>
    <bean id="afterLog" class="com.yl.Log.AfterLog"/>

<!--方式一:使用Spring原生接口-->
<!--    配置aop:需要导入aop的约束-->
    <aop:config>
<!--        切入点:expression表达式,execution:要执行的位置-->
        <aop:pointcut id="pointcut" expression="execution(* com.yl.service.UserServiceImpl.*(..))"/>
<!--        执行环绕增加-->
        <aop:advisor advice-ref="log" pointcut-ref="pointcut"/>
        <aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>
    </aop:config>
</beans>

测试类:【注意:动态代理 代理的是接口】

public class MyTest {
    @Test
    public void test(){
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        //动态代理代理的是接口
        UserService userService = (UserService) context.getBean("userService");
        userService.add();
    }
}

方式二:自定义切入点类

编写切入类:包含要环绕添加的方法

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

配置文件:

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

方式三:使用注解实现AOP

<!--开启注解支持-->
<aop:aspectj-autoproxy/>

主要使用的几个注解:

@Before("execution(* com.yl.service.UserServiceImpl.*(..))")
@After("execution(* com.yl.service.UserServiceImpl.*(..))")
@Aroud("execution(* com.yl.service.UserServiceImpl.*(..))")

12、Spring整合mybatis

12.1、mybatis-spring

相关项目:spring-10-mybatis

12.2、第一种方式整合mybatis

导入相关的包、依赖

<!--        junit-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
<!--        mysql-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.28</version>
        </dependency>
<!--        mybatis-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.9</version>
        </dependency>
<!--        spring-webMvc-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.3.16</version>
        </dependency>
<!--        Spring操作数据库还需要spring-jdbc-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.3.16</version>
        </dependency>
<!--        aop-->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.7.4</version>
        </dependency>
<!--        spring-mybatis-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>2.0.7</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.10</version>
        </dependency>
    </dependencies>

可能需要注意的:

    <!--    maven的约定大于配置会导致我们自己写的配置无法导入或失效,需要更改配置-->
    <build>
        <resources>
            <!--            系统默认的路径为resources下-->
            <resource>
                <directory>src/main/resources</directory>
                <includes>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
                <filtering>true</filtering>
            </resource>
            <!--            我们自己更改的路径为Java下的properties或者xml-->
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
                <filtering>true</filtering>
            </resource>
        </resources>

配置文件,使用spring整合mybatis,不再使用SqlSessionFactory工具类,而是将它写入配置文件中:

<?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 :数据源  -->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useUnicode=true&amp;characterEncoding=UTF-8&amp;useSSL=false&amp;serverTimezone=GMT"/>
        <property name="username" value="root"/>
        <property name="password" value="5418"/>
    </bean>
<!--sqlSessionFactory-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="configLocation" value="classpath:mybatis-config.xml"/>
        <property name="mapperLocations" value="classpath:com/yl/mapper/*.xml"/>
    </bean>
<!--    sqlSessionTemplate-->
    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<!--        只能使用构造器注入sqlSessionFactory,因为没有set方法-->
        <constructor-arg index="0" ref="sqlSessionFactory"/>
    </bean>
</beans>

测试就可以使用spring的方式进行了:

public class MyTest {
    @Test
    public void test() throws IOException {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserMapper userMapper = context.getBean("userMapper", UserMapper.class);
        for (User selectUser : userMapper.selectUsers()) {
            System.out.println(selectUser);
        }
    }
}

总结步骤:

  1. 编写实体类pojo
  2. 编写实体类方法接口
  3. 编写接口实现类
  4. 编写sql语句的配置文件
  5. 整合mybatis(数据源、SqlSessionFactory、SqlSessionTemplate)
  6. 注入实现类bean
  7. 编写测试类

12.3、第一种方式整合mybatis

整合mybatis第二种方式:使用SqlSessionDaoSupport,直接继承使用,使用它连SqlSessionTemplate都不需要注入:

public class UserMapperImpl2 extends SqlSessionDaoSupport implements UserMapper {
    @Override
    public List<User> selectUsers() {
        return getSqlSession().getMapper(UserMapper.class).selectUsers();
    }
}

编写完实现类之后,只需要在applicationContext.xml中注入该实现类的bean即可,且它没有属性所以不需要注入sqlSession,只需要注入属性SqlSessionFactory即可:

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

13、声明式事务

13.1、事务简介

事务特点:

  • 一组事务遵循要么全部成功,要么全部失败
  • 事务在开发中很重要,涉及到数据的一致性问题
  • 确保完整性和一致性

事务ACID原则:

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

13.2、Spring中的事务管理

  • 声明式事务:AOP
  1. 编写事务配置,引入需要
xmlns:tx="http://www.springframework.org/schema/tx"
https://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx

编写配置文件

<!--    配置声明式事务 dataSource要和jdbc数据库为同一个数据源-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>
<!--    结合AOP配置实现事务的织入-->
<!--   advice: 配置事务通知-->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
<!--        表示给那些方法配置事务-->
<!--        配置事务的传播特性:new  propagation,默认REQUIRED-->
        <tx:attributes>
            <tx:method name="add" propagation="REQUIRED"/>
            <tx:method name="delete" propagation="REQUIRED"/>
            <tx:method name="query" propagation="REQUIRED"/>
            <tx:method name="update" propagation="REQUIRED"/>
            <tx:method name="*" propagation="REQUIRED"/>
        </tx:attributes>
    </tx:advice>
<!--    配置事务切入点-->
    <aop:config>
        <aop:pointcut id="txPointCut" expression="execution(* com.yl.mapper.*.*(..))"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>
    </aop:config>

事务一般是一个组,里面包含了许多方法,事务的作用也就是成功全部成功,失败全部失败:

public List<User> selectUsers() {
    UserMapper mapper = sqlSessionTemplate.getMapper(UserMapper.class);
    mapper.addUser(user);
    mapper.deleteUser(4);
    return mapper.selectUsers();
}
  • 编程式事务:需要在代码中,进行事务的管理