Spring入门(二)

一、Bean的自动装配
自动装配是使用spring满足bean依赖的一种方法,spring会在应用上下文中为某个bean寻找其依赖的bean。
Spring中bean有三种装配机制,分别是:
1.在xml中显式配置;
2.在java中显式配置;
3.隐式的bean发现机制和自动装配 (重点)
Spring的自动装配需要从两个角度来实现,或者说是两个操作:
组件扫描(component scanning):spring会自动发现应用上下文中所创建的bean;
自动装配(autowiring):spring自动满足bean之间的依赖,也就是我们说的IoC/DI;
组件扫描和自动装配组合发挥巨大威力,使得显示的配置降低到最少。

1.autowire byName (按名称自动装配)
由于在手动配置xml过程中,常常发生字母缺漏和大小写等错误,而无法对其进行检查,使得开发效率降低。采用自动装配将避免这些错误,并且使配置简单化。

<bean id="user" class="com.zgf.pojo.User" autowire="byName">
   <property name="str" value="zgf"/>
</bean>

注: 当一个bean节点带有 autowire byName的属性时。
(1)将查找其类中所有的set方法名;
(2)去spring容器中寻找是否有此字符串名称id的对象。
(3) 如果有,就取出注入;如果没有,就报空指针异常。
2.autowire byType (按类型自动装配)
使用autowire byType首先需要保证:同一类型的对象,在spring容器中唯一。如果不唯一,会报不唯一的异常。NoUniqueBeanDefinitionException
二、注解实现自动装配
1.导入约束 context约束
2.配置注解的支持 <context:annotation-config/> (重要)

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/aop 
        http://www.springframework.org/schema/context/spring-aop.xsd">
<!--    开启注解的支持-->
    <context:annotation-config/>
    <bean id="user" class="com.zgf.pojo.User" />
    <bean id="user2" class="com.zgf.pojo.User" />
</beans>

@Autowired: 按类型自动转配,不支持id匹配。需要导入 spring-aop的包
@Qualifier:@Autowired是根据类型自动装配,加上@Qualifier则可以通过byType方式自动装配。
@Resource:1.若有指定的name属性,先按照该属性进行byName方式查找装配;2.其次进行默认的byName方式进行装配;3.若以上方式都不成功,则按照byType的方式自动装配;4.以上都不成功,则报异常。
小结:
@Autowired与@Resource异同:
1.@Autowired与@Resource都可以用来装配bean,都可以写在字段上,或者setter方法上。
2、@Autowired默认按类型装配(属于spring规范),默认情况下必须要求依赖对象必须存在,若允许null值,可以设置它的required属性为false。如:@Autowired(required=false),如果我们想使用名称装配可以结合@Qualifier注解进行使用
3、@Resource(属于J2EE复返),默认按照名称进行装配,名称可以通过name属性进行指定。如果没有指定name属性,当注解写在字段上时,默认取字段名进行按照名称查找,若注解写在setter方法上默认取属性名进行装配,当找不到与名称匹配的bean时才按照类型进行装配。但是需要注意的是,如果name属性一旦指定,就只会按照名称进行装配。
它们的作用相同都是用注解方式注入对象,但执行顺序不同。@Autowired先byType,@Resource先byName。
三、使用注解开发
1.Bean的实现
(1)配置扫描哪些包下的注解

<!--指定注解扫描包-->
<context:component-scan base-package="com.kuang.pojo"/>

(2)在指定包下编写类,增加注解

@Component("user")
// 相当于配置文件中 <bean id="user" class="当前注解的类"/>
public class User {
   public String name = "zgf";
}

(3)测试

@Test
public void test(){
   ApplicationContext applicationContext =
       new ClassPathXmlApplicationContext("beans.xml");
   User user = (User) applicationContext.getBean("user");
   System.out.println(user.name);
}

2.属性注入
使用注解注入属性
1、可以不用提供set方法,直接在直接名上添加@value(“值”)
2、如果提供了set方法,在set方法上添加@value(“值”);
3.衍生注解
@Component三个衍生注解
(1)@Controller:web层
(2)@Service:service层
(3)@Repository:dao层
这四个注解功能都是一样的,都代表将某个类注册到Spring中,装配Bean。
四、XML与注解比较
XML可以适用任何场景 ,结构清晰,维护方便;注解不是自己提供的类使用不了,开发简单方便。
xml与注解整合开发 :
xml管理Bean ,注解完成属性注入,使用过程中, 可以不用扫描,扫描是为了类上的注解

<context:annotation-config/>

作用:
1.进行注解驱动注册,从而使注解生效
2.用于激活那些已经在spring容器里注册过的bean上面的注解,也就是显式的向Spring注册
3.如果不扫描包,就需要手动配置bean
4.如果不加注解驱动,则注入的值为null.
五、静态代理模式
静态代理角色分析:
抽象角色 : 一般使用接口或者抽象类来实现
真实角色 : 被代理的角色
代理角色 : 代理真实角色 ; 代理真实角色后 , 一般会做一些附属的操作 .
客户 : 使用代理角色来进行一些操作 .
代码实现:

package com.zgf.demo01;
// 抽象角色
public interface Rent {
    public void rent();
}
package com.zgf.demo01;
public class Host implements Rent{
    public void rent(){
        System.out.println("房东要租房子!");
    }
}
package com.zgf.demo01;
public class Proxy implements Rent{
    private Host host;
    public Proxy(){
    }
    public Proxy(Host host){
        this.host = host ;
    }
    @Override
    public void rent() {
        seeHouse();
        host.rent();
        fare();
        heTong();
    }
    //看房
    public void seeHouse(){
        System.out.println("中介带你看房");
    }
    //收中介费
    public void fare(){
        System.out.println("中介收中介费");
    }
    //签租合同
    public void heTong(){
        System.out.println("与中介签租合同");
    }
}
package com.zgf.demo01;
public class Client {
    public static void main(String[] args) {
        //房东要租房子
        Host host = new Host();
        host.rent();
        //代理,中介帮助房东租房子,但代理一般会有一些附属操作
        Proxy proxy = new Proxy(host);
        //你不用面对房东直接找中介即可
        proxy.rent();
    }
}

在这个过程中,客户直接接触的就是中介,就如同现实生活中的样子,看不到房东,但是客户依旧通过代理租到了房东的房子,这就是所谓的代理模式,程序源自于生活,所以学编程的人,一般能够更加抽象的看待生活中发生的事情。

静态代理的优点:

可以使得我们的真实角色更加纯粹 . 不再去关注一些公共的事情 .

公共的业务由代理来完成 . 实现了业务的分工 ,

公共业务发生扩展时变得更加集中和方便 .

缺点 :

类多了 , 多了代理类 , 工作量变大了 . 开发效率降低 .

我们想要静态代理的好处,又不想要静态代理的缺点,所以 , 就有了动态代理 。

六、静态代理加深理解:

Spring自动装载模式 spring自动装载方式_Spring自动装载模式

七、动态代理

动态代理的代理类是动态生成的 . 静态代理的代理类是提前写好的

动态代理分为两类 :

一类是基于接口动态代理 ; 另一类是基于类的动态代理

基于接口的动态代理----JDK动态代理

基于类的动态代理–cglib

现在用的比较多的是 javasist 来生成动态代理 .

JDK的动态代理需要了解两个类

核心 : InvocationHandler 和 Proxy

代码实现:

抽象角色和真实角色和之前的一样

package com.zgf.demo02;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
//用这个类自动生成代理类
public class ProxyInvocationHandler implements InvocationHandler {
//    Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
//    new class<?>[] {Foo.class},
//    handler);
    //被代理的接口
    private Rent rent;
    public void setRent(Rent rent){
        this.rent = rent ;
    }
    //生成得到代理类
    public Object getProxy(){
        return Proxy.newProxyInstance(this.getClass().getClassLoader(), rent.getClass().getInterfaces(),this);
    }
    //处理代理实例并返回结果
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //动态代理的本质就是通过反射机制实现
        Object result = method.invoke(rent,args);
        return null;
    }
}
package com.zgf.demo02;
public class Client {
    public static void main(String[] args) {
        //真实角色
        Host host = new Host();
        //代理角色:现在没有
        ProxyInvocationHandler pih = new ProxyInvocationHandler();
        //通过调用程序处理角色来处理要调用的接口对象
        pih.setRent(host);
        Rent proxy = (Rent) pih.getProxy();
        proxy.rent();
    }
}

另一个案例加深理解:

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);
  }
   // proxy : 代理类
   // method : 代理类的调用处理程序的方法对象.
   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 methodName){
       System.out.println("执行了"+methodName+"方法");
  }
}
public class Test {
   public static void main(String[] args) {
       //真实对象
       UserServiceImpl userService = new UserServiceImpl();
       //代理对象的调用处理程序
       ProxyInvocationHandler pih = new ProxyInvocationHandler();
       pih.setTarget(userService); //设置要代理的对象
       UserService proxy = (UserService)pih.getProxy(); //动态生成代理类!
       proxy.delete();
  }
}

动态代理的好处:

可以使得我们的真实角色更加纯粹 . 不再去关注一些公共的事情 .

公共的业务由代理来完成 . 实现了业务的分工 ,

公共业务发生扩展时变得更加集中和方便.

一个动态代理类代理的是一个接口,一般就是对应的一类业务

一个动态代理类可以代理多个类,只要是实现了同一个接口即可!

八、AOP

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

Spring自动装载模式 spring自动装载方式_Spring自动装载模式_02


横切关注点: 跨越应用程序多个模块的方法或功能。即是,与我们业务逻辑无关的,但是我们需要关注的部分,就是横切关注点。如日志 , 安全 , 缓存 , 事务等等

切面(ASPECT): 横切关注点 被模块化 的特殊对象。即,它是一个类。

通知(Advice): 切面必须要完成的工作。即,它是类中的一个方法。

目标(Target): 被通知对象。

代理(Proxy): 向目标对象应用通知之后创建的对象。

切入点(PointCut): 切面通知 执行的 “地点”的定义。

连接点(JointPoint): 与切入点匹配的执行点


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

<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
   <groupId>org.aspectj</groupId>
   <artifactId>aspectjweaver</artifactId>
   <version>1.9.4</version>
</dependency>

第一种方式:通过 Spring API 实现

package com.zgf.service;
public interface UserService {
    public void add();
    public void delete();
    public void update();
    public void select();
}
package com.zgf.service;
public class UserServiceImpl implements UserService{
    @Override
    public void add() {
        System.out.println("增加了一个用户");
    }
    @Override
    public void delete() {
        System.out.println("删除了一个用户");
    }
    @Override
    public void update() {
        System.out.println("更新了一个用户");
    }
    @Override
    public void select() {
        System.out.println("查询了一个用户");
    }
}
package com.zgf.log;
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
public class log implements MethodBeforeAdvice {
    //method:要执行的目标对象的方法
    //object:参数
    //target:目标对象
    @Override
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println(target.getClass().getName()+"的"+method.getName()+"被执行了");
    }
}
package com.zgf.log;
import org.springframework.aop.AfterReturningAdvice;
import java.lang.reflect.Method;
public class AfterLog implements AfterReturningAdvice {
    //returnValue返回值
    @Override
    public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
        System.out.println("执行了"+method.getName()+"方法,返回结果为:"+returnValue);
    }
}
<?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
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd">
       <!--注册bean -->
    <bean id="userService" class="com.zgf.service.UserServiceImpl"/>
    <bean id="log" class="com.zgf.log.log"/>
    <bean id="afterLog" class="com.zgf.log.AfterLog"/>
    <!--配置aop 导入aop的约束-->
    <aop:config>
        <!--切入点:expression:表达式,execution(要执行的位置) -->
        <aop:pointcut id="pointcut" expression="execution(* com.zgf.service.UserServiceImpl.*(..))"/>
        <!--执行环绕增加-->
        <aop:advisor advice-ref="log" pointcut-ref="pointcut"/>
        <aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>
    </aop:config>
</beans>

第二种方式:自定义类来实现Aop

package com.zgf.diy;
public class DiyPointCut {
    public void before(){
        System.out.println("=====方法执行前=====");
    }
    public void after(){
        System.out.println("=====方法执行后=====");
    }
}
<?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
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd">
       <!--注册bean -->
    <bean id="userService" class="com.zgf.service.UserServiceImpl"/>
    <bean id="log" class="com.zgf.log.log"/>
    <bean id="afterLog" class="com.zgf.log.AfterLog"/>
    <!--配置aop 导入aop的约束-->
<!--    方式二:自定义类-->
    <bean id="diy" class="com.zgf.diy.DiyPointCut"/>
    <aop:config>
<!-- 自定义切面,ref要引用的类-->
        <aop:aspect ref="diy">
<!-- 切入点-->
            <aop:pointcut id="point" expression="execution(* com.zgf.service.UserServiceImpl.*(..))"/>
<!-- 通知-->
            <aop:before method="before" pointcut-ref="point"/>
            <aop:after method="after" pointcut-ref="point"/>
        </aop:aspect>
    </aop:config>
</beans>

第三种方式:使用注解实现

package com.zgf.diy;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
//方式三:使用注解方式实现AOP
@Aspect //标注这个类是一个切面
public class AnnotationPointCut {
    @Before("execution(* com.zgf.service.UserServiceImpl.*(..))")
    public void beford(){
        System.out.println("====方法执行前====");
    }
    @After("execution(* com.zgf.service.UserServiceImpl.*(..))")
    public void after(){
        System.out.println("====方法执行后====");
    }
    //在环绕增强中,给定一个参数,代表要获取处理的切入点
    @Around("execution(* com.zgf.service.UserServiceImpl.*(..))")
    public void around(ProceedingJoinPoint jp){
        System.out.println("环绕前");
        //执行方法
        Signature signature = jp.getSignature();//获得签名
        System.out.println("环绕后");
    }
}
<!--    方式三 -->
    <bean id="annotationPointCut" class="com.zgf.diy.AnnotationPointCut"/>
<!--    开启注解支持  JDK(默认 proxy-taget-class="flase") cglib(proxy-target-class="true")-->
    <aop:aspectj-autoproxy />

九、整合Mybatis
1.整合步骤:
(1)导入jar包:junit mybatis mysql数据库 spring相关 aop织入 mybatis-spring【new】http://mybatis.org/spring/zh/index.html

<dependencies>
<!--        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>5.1.45</version>
        </dependency>
<!--        mybatis-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.7</version>
        </dependency>
<!--        spring-webmvc-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.2.5.RELEASE</version>
        </dependency>
<!--        Spring操作数据库还需要spring-jdbc-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.2.5.RELEASE</version>
        </dependency>
<!--        AOP织入包-->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.2</version>
        </dependency>
<!--        mybatis和spring整合包-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>2.0.6</version>
        </dependency>
    </dependencies>

(2)编写配置文件
(3)测试
2.回忆Mybatis
(1)编写实体类

package com.zgf.pojo;
public class User {
    private int id;
    private String name;
    private String pwd;
}

(2)编写核心配置文件
https://mybatis.net.cn/getting-started.html

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

(3)编写接口

package com.zgf.mapper;
import com.zgf.pojo.User;
import java.util.List;
public interface UserMapper {
    public List<User> selectUser();
}

(4)编写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.zgf.mapper.UserMapper">
    <select id="selectUser" resultType="user">
        select * from mybatis.user;
    </select>
</mapper>

(5)测试

import com.zgf.mapper.UserMapper;
import com.zgf.pojo.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;
import org.springframework.jdbc.object.SqlCall;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
public class MyTest {
    @Test
    public void test() throws IOException {
        String resources = "mybatis-config.xml";
        InputStream in =Resources.getResourceAsStream(resources);
        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);
        }
    }
}

3.Mybatis-Spring
(1)编写数据源

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

(2)sqlSessionFactory

<!--    sqlSessionFactory-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
<!--        绑定Mybatis配置文件-->
        <property name="configLocation" value="classpath:mybatis-config.xml"/>
        <property name="mapperLocations" value="classpath:com/zgf/mapper/*.xml"/>
    </bean>

(3)sqlSessionTemplate

<!--SqlSessionTemplate:就是我们使用的sqlSession -->
    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<!--        只能使用构造器注入sqlSessionFactory 因为它没有set方法-->
        <constructor-arg index="0" ref="sqlSessionFactory"/>
    </bean>

(4)需要给接口加实现类
法一:

public class UserMapperImpl implements UserMapper{
    //所有操作都使用sqlSession来执行,现在都使用SqlSessionTemplate;
    private SqlSessionTemplate sqlSession;
    public  void setSqlSession(SqlSessionTemplate sqlSession){
        this.sqlSession = sqlSession;
    }
    @Override
    public List<User> selectUser() {
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        return mapper.selectUser();
    }
}

法二:

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

(5)将自己写的实现类注入到spring中

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--   DataSource:使用Spring的数据源替换Mybatis的配置文件 c3p0 dbcp druid
       这里使用Spring提供的JDBC: org.springframework.jdbc.datasource-->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=UTF-8"/>
        <property name="username" value="root"/>
        <property name="password" value="root"/>
    </bean>
<!--    sqlSessionFactory-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
<!--        绑定Mybatis配置文件-->
        <property name="configLocation" value="classpath:mybatis-config.xml"/>
        <property name="mapperLocations" value="classpath:com/zgf/mapper/*.xml"/>
    </bean>
    <!--SqlSessionTemplate:就是我们使用的sqlSession -->
    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<!--        只能使用构造器注入sqlSessionFactory 因为它没有set方法-->
        <constructor-arg index="0" ref="sqlSessionFactory"/>
    </bean>
    <bean id="userMapper" class="com.zgf.mapper.UserMapperImpl">
        <property name="sqlSession" ref="sqlSession"/>
    </bean>
</beans>

法二配置:

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

(6)测试使用

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

十、声明式事务
事务ACID原则:原子性、一致性、隔离性、持久性
十一、Spring中事务管理

package com.zgf.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private int id;
    private String name;
    private String pwd;
}
package com.zgf.mapper;
import com.zgf.pojo.User;
import java.util.List;
public interface UserMapper {
    public List<User> selectUser();
    //添加一个用户
    public int addUser(User user);
    //删除一个用户
    public int deleteUser(int id);
}
<?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.zgf.mapper.UserMapper">
    <select id="selectUser" resultType="user">
        select * from mybatis.user;
    </select>
    <insert id="addUser" parameterType="user">
        insert into mybatis.user (id,name,pwd) values (#{id},#{name},#{pwd});
    </insert>
    <delete id="deleteUser" parameterType="int">
        delete from mybatis.user where id=#{id}
    </delete>
</mapper>
package com.zgf.mapper;
import com.zgf.pojo.User;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.support.SqlSessionDaoSupport;
import java.util.List;
public class UserMapperImpl extends SqlSessionDaoSupport implements UserMapper{
    @Override
    public List<User> selectUser() {
        User user = new User(2,"zzz","123456");
        UserMapper mapper = getSqlSession().getMapper(UserMapper.class);
        mapper.addUser(user);
        mapper.deleteUser(5);
        return mapper.selectUser();
    }
    @Override
    public int addUser(User user) {
        return getSqlSession().getMapper(UserMapper.class).addUser(user);
    }
    @Override
    public int deleteUser(int id) {
        return getSqlSession().getMapper(UserMapper.class).deleteUser(id);
    }
}
<?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
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd">
    <import resource="spring-dao.xml"/>
<!--    bean-->
    <bean id="userMapper" class="com.zgf.mapper.UserMapperImpl">
        <property name="sqlSessionFactory" ref="sqlSessionFactory"/>
    </bean>
</beans>
<?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.zgf.pojo"/>
    </typeAliases>
</configuration>
<?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/c"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.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">
<!--   DataSource:使用Spring的数据源替换Mybatis的配置文件 c3p0 dbcp druid
       这里使用Spring提供的JDBC: org.springframework.jdbc.datasource-->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=UTF-8"/>
        <property name="username" value="root"/>
        <property name="password" value="root"/>
    </bean>
<!--    sqlSessionFactory-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
<!--        绑定Mybatis配置文件-->
        <property name="configLocation" value="classpath:mybatis-config.xml"/>
        <property name="mapperLocations" value="classpath:com/zgf/mapper/*.xml"/>
    </bean>
    <!--SqlSessionTemplate:就是我们使用的sqlSession -->
    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<!--        只能使用构造器注入sqlSessionFactory 因为它没有set方法-->
        <constructor-arg index="0" ref="sqlSessionFactory"/>
    </bean>
<!--    配置声明式事务-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <constructor-arg ref="dataSource" />
    </bean>
<!--    给AOP实现事务的织入-->
<!--    配置事务的类-->
    <tx:advice id="txAdvice" transaction-manner="transactionManager">
        <tx:attributes>
            <tx:method name="add" propagation="PEQUIRED"/>
            <tx:method name="delete" propagation="PEQUIRED"/>
            <tx:method name="*" propagation="PEQUIRED"/>
        </tx:attributes>
    </tx:advice>
<!--    配置事务切入-->
    <aop:config>
        <aop:pointcut id="txPointCut" expression="execution(* com.zgf.mapper.*.*(..))"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>
    </aop:config>
</beans>
import com.zgf.mapper.UserMapper;
import com.zgf.pojo.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.util.List;
public class MyTest {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserMapper userMapper = context.getBean("userMapper", UserMapper.class);
        List<User> userList = userMapper.selectUser();
        for (User user :
                userList) {
            System.out.println(user);
        }
    }
}
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>maven01</artifactId>
        <groupId>com.zgf</groupId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>spring-08-transaction</artifactId>
    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>
    <dependencies>
        <!--        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>5.1.45</version>
        </dependency>
        <!--        mybatis-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.7</version>
        </dependency>
        <!--        spring-webmvc-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.2.5.RELEASE</version>
        </dependency>
        <!--        Spring操作数据库还需要spring-jdbc-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.2.5.RELEASE</version>
        </dependency>
        <!--        AOP织入包-->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.2</version>
        </dependency>
        <!--        mybatis和spring整合包-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>2.0.6</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.22</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>2.0.6</version>
            <scope>compile</scope>
        </dependency>
    </dependencies>
</project>