Spring5框架学习笔记(详细)

目录

01 Spring框架概述

02 IOC容器

IOC概念和原理

IOC BeanFactory接口

IOC操作 Bean管理(概念)

IOC操作 Bean管理(基于xml方式)

IOC操作 Bean管理(bean作用域)

IOC操作 Bean管理(bean生命周期)

IOC操作 Bean 管理(xml 自动装配)

IOC操作 Bean 管理(外部属性文件)

IOC操作 Bean管理 (基于注解方式)

03 AOP

AOP概念

AOP(底层原理)

AOP操作(准备工作)

AOP操作(AspectJ 注解)

AOP操作(AspectJ 配置xml文件)

04 JdbcTemlate

JdbcTemplate(概念和准备)

JdbcTemplate操作数据库(添加,修改,删除)

JdbcTemplate操作数据库(查询返回某个值,对象,集合)

JdbcTemplate操作数据库(批量添加、修改、删除)

05 事务管理

事务操作(事务概念)

事务操作(Spring事务管理介绍)

事务操作(使用注解配置声明式事务管理)

事务操作(使用xml配置声明式事务管理)

事务操作(完全注解配置声明式事务管理)

06 Spring5新特性

07 Spring5框架新功能(Webflux)


01 Spring框架概述

  • Spring是轻量级的开源的JavaEE框架
  • Spring可以解决企业应用开发的复杂性
  • Spring有两个核心部分:IOC和AOP
    • IOC(Inversion of Control),控制反转,把创建对象过程交给Spring进行管理
    • AOP(Aspect Oriented Programming),面向切面编程,不修改源代码进行功能增强
  • Spring特点:
    • 方便解耦,简化开发
    • AOP编程支持
    • 方便程序测试
    • 方便和其他框架整合
    • 方便进行事务操作
    • 降低API开发难度
  • 使用Spring5最新稳定版5.2.6,https://repo.spring.io/release/org/springframework/spring/
## 入门案例
# 创建一个普通类,有一个普通方法
public class User {
    public void add() {
        System.out.println("add.....");
    }
}

# 创建xml配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--配置User对象创建-->
    <bean id="user" class="com.atguigu.spring5.User"></bean>
</beans>

# 使用spring创建对象
public class TestUser {
    @Test
    public void test1() {
        ApplicationContext context
                = new ClassPathXmlApplicationContext("bean1.xml");
        User user = context.getBean("user", User.class);
        System.out.println(user);
        user.add();
    }
}

02 IOC容器

IOC概念和原理

  • 什么是IOC:控制反转,把对象创建和对象直接的调用过程交给Spring进行管理;使用IOC的目的是为了降低耦合度;入门案例就是IOC的实现
  • IOC底层原理:xml解析、工厂模式、反射,a类中调用b类对象的方法时,a类通过调用工厂类的方法获得b类对象,进而调用方法,在工厂类中,通过xml解析获取到类的class,通过反射创建b类对象,降低了a类和b类的耦合,当b类的类路径改变时,工厂类一样可以正常返回b类对象

IOC BeanFactory接口

  • IOC思想基于IOC容器完成,IOC容器底层就是对象工厂
  • Spring提供IOC容器的两种实现方式(两个接口)
    • BeanFactory,IOC容器基本实现,是Spring内部的使用接口,不提供开发人员进行使用,加载配置文件时候不会创建对象,在获取对象(使用)才去创建对象
    • ApplicationContext,BeanFactory接口的子接口,提供更多更强大的功能,一般由开发人员进行使用,加载配置文件时候就会把在配置文件对象进行创建
  • ApplicationContext有接口实现类
    • FileSystemXmlApplicationContext
    • ClassPathXmlApplicationContext

IOC操作 Bean管理(概念)

  • 什么是Bean管理,指两个操作,Spring创建对象,Spring注入属性
  • Bean管理的两种方式,基于xml配置文件方式实现基于注解方式实现
  • Spring有两种bean,一种普通bean,另外一种工厂bean(FactoryBean)
    • 普通bean:在配置文件中定义bean类型就是返回类型
    • 工厂bean:在配置文件定义bean类型可以和返回类型不一样,实现FactoryBean接口,重写方法,定义返回类型

IOC操作 Bean管理(基于xml方式)

  • 创建对象:在spring配置文件中,使用bean标签,标签里面添加对应属性,就可以实现对象创建,id属性,class属性,name属性(可以有其他字符);默认执行无参构造方法
  • 注入属性,(Dependency Injection,DI)
    • 使用set方法注入,创建类,定义属性和对应的set方法,在spring配置文件中配置对象创建,配置属性注入
    • 使用有参构造方法注入,创建类,定义属性,创建属性对应有参数构造方法,在spring配置文件中进行配置
    • p名称空间注入,set方法注入的简化,需要配置名称空间p
    • 注入null值和特殊符号
    • 注入属性:外部bean,使用ref标签
    • 注入属性:内部bean,在bean内部创建bean
    • 注入属性:级联赋值,需要设置get方法获得对象才能级联赋值
    • 注入属性:集合属性,数组、List、Map、Set
  • 使用util标签提取,需要配置util命名空间
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--配置User对象创建-->
    <bean id="user" class="com.atguigu.spring5.User"></bean>

    <!--基于xml方式set方法注入属性-->
    <bean id="book" class="com.atguigu.spring5.Book">
        <property name="bname" value="书名"></property>
        <property name="bauthor" value="作者"></property>
    </bean>

    <!--基于xml方式有残参构造方法注入属性-->
    <bean id="orders" class="com.atguigu.spring5.Orders">
        <constructor-arg name="oname" value="电脑"></constructor-arg>
        <constructor-arg name="address" value="China"></constructor-arg>
    </bean>

    <!--p名称空间注入属性-->
    <bean id="bookp" class="com.atguigu.spring5.Book" p:bname="书名p" p:bauthor="作者p">

    <!--注入null值和特殊符号-->
    <bean id="booknull" class="com.atguigu.spring5.Book">
        <property name="bname">
            <null/>
        </property>
<!--        <property name="bauthor" value="&lt;&gt;南京"></property>-->
        <property name="bauthor">
            <value><![CDATA[特殊符号]]></value>
        </property>
    </bean>

    <!--注入属性-外部bean-->
    <bean id="userDaoImp" class="com.atguigu.spring5.dao.UserDaoImp"></bean>
    <bean id="userService" class="com.atguigu.spring5.service.UserService">
        <property name="userDao" ref="userDaoImp"></property>
    </bean>

    <!--注入属性-内部bean-->
    <bean id="userService2" class="com.atguigu.spring5.service.UserService">
        <property name="userDao">
            <bean id="userDaoImp2" class="com.atguigu.spring5.dao.UserDaoImp"></bean>
        </property>
    </bean>
    
    <!--级联赋值-需要设置get方法获得对象-->
    <bean id="emp" class="com.atguigu.spring5.bean.Emp">
        <property name="name" value="emp1"></property>
        <property name="dept" ref="dept1"></property>
        <property name="dept.dName" value="Dept1"></property>
    </bean>
    <bean id="dept1" class="com.atguigu.spring5.bean.Dept">
        <property name="dName" value="Dept1"></property>
    </bean>

    <!--注入集合属性-->
    <bean id="courseOut1" class="com.atguigu.spring5.bean.Course">
        <property name="name" value="OutBean"></property>
    </bean>
    <bean id="stu" class="com.atguigu.spring5.bean.Stu">
        <property name="courses">
            <array>
                <value>course1</value>
                <value>course2</value>
            </array>
        </property>
        <property name="list">
            <list>
                <value>list1</value>
                <value>list2</value>
            </list>
        </property>
        <property name="courseList">
            <list>
                <bean id="course1" class="com.atguigu.spring5.bean.Course">
                    <property name="name" value="English"></property>
                </bean>
                <bean id="course2" class="com.atguigu.spring5.bean.Course">
                    <property name="name" value="Chinese"></property>
                </bean>
                <ref bean="courseOut1"></ref>
            </list>
        </property>
        <property name="map">
            <map>
                <entry key="k1" value="v1"></entry>
                <entry key="k2" value="v2"></entry>
            </map>
        </property>
        <property name="set">
            <set>
                <value>set1</value>
                <value>set2</value>
            </set>
        </property>
    </bean>
    
    <!--提取集合属性,以List为例,需要修改命名空间-->
    <util:list id="courseList2">
        <bean id="course1" class="com.atguigu.spring5.bean.Course">
            <property name="name" value="English2"></property>
        </bean>
        <bean id="course2" class="com.atguigu.spring5.bean.Course">
            <property name="name" value="Chinese2"></property>
        </bean>
        <ref bean="courseOut1"></ref>
    </util:list>
    <bean id="stu2" class="com.atguigu.spring5.bean.Stu">
        <property name="courseList" ref="courseList2"></property>
    </bean>

</beans>

IOC操作 Bean管理(bean作用域)

  • 在Spring里面,设置创建bean实例是单实例还是多实例,默认情况下,bean是单实例对象
  • 创建对象时使用scope配置是但例还是多例,singletonprototype,request,session
  • 区别:一个单例,一个多例,单例在加载配置文件时就已经创建好对象了,多例是在getBean时创建

IOC操作 Bean管理(bean生命周期)

  • 通过无参构造器创建bean实例
  • 调用set方法设置bean的属性值和其他bean引用
  • 调用初始化方法,初始化之前会调用后置处理器中的postProcessBeforeInitialization()方法,初始化之后也调用postProcessAfterInitialization()方法
    • bean中使用init-method配置初始化方法
    • 后置处理器需要实现BeanPostProcessor接口,里面有两个默认方法,在xml中配置为一个bean就可以了,会对xml中所有的bea应用后置处理器
  • 获取到对象,可以使用
  • 容器关闭时,调用bean的销毁方法
    • bean中使用destroy-method配置销毁方法,在使用时手动调用context.close()
    <bean id="bookLife" class="com.atguigu.spring5.Book" init-method="initMethod" destroy-method="destoryMethod">
        <property name="bname" value="bname"></property>
        <property name="bauthor" value="bauthor"></property>
    </bean>

    <bean id="myPostProcessor" class="com.atguigu.spring5.MyPostProcessor"></bean>

IOC操作 Bean 管理(xml 自动装配)

  • 根据指定装配规则(名称或者类型),Spring自动将匹配的属性值进行注入
  • byName:属性名与bean id相同,byType:根据bean的类型匹配,必须只有一个同类型的
    <!--自动注入-autowire="byName" - "byType"-->
    <bean id="emp" class="com.atguigu.spring5.autowire.Emp" autowire="byName"></bean>
    <bean id="dept" class="com.atguigu.spring5.autowire.Dept">
        <property name="dname" value="deptA"></property>
    </bean>

IOC操作 Bean 管理(外部属性文件)

  • 引入外部.properties文件,需要配置名称空间context
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       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
                           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <!--直接配置连接池-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
        <property name="url" value="jdbc:mysql://localhost:3306/userDb"></property>
        <property name="username" value="root"></property>
        <property name="password" value="root"></property>
    </bean>

    <!--引入外部属性文件-->
    <context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
    <!--配置连接池-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${prop.driverClass}"></property>
        <property name="url" value="${prop.url}"></property>
        <property name="username" value="${prop.username}"></property>
        <property name="password" value="${prop.password}"></property>
    </bean>
</beans>

## jdbc.properties
prop.driverClass=com.mysql.jdbc.Driver
prop.url=jdbc:mysql://localhost:3306/userDb
prop.username=root
prop.password=root

IOC操作 Bean管理 (基于注解方式)

  • 注解是代码特殊标记,格式:@注解名称(属性名称=属性值, 属性名称=属性值..)
  • 使用注解的目的:简化xml配置
  • Spring中针对Bean管理创建对象提供4个注解:@Component,@Service,@Controller,@Repository,功能一样,都可以创建注解
  • 创建对象
    • 导入依赖aop.jar
    • 开启组件扫描,多个包逗号隔开,或者使用包的上层目录,需要配置context命名空间
    • 创建类,在类上面添加创建类的注解,默认的bean名是类首字母小写
    • 只扫描某一部分,或排除扫描某一部分
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       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
                           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <context:component-scan base-package="com.atguigu.spring5"></context:component-scan>

    <!--示例1 
    use-default-filters="false" 表示不扫描所有,
    自己配置扫描的内容filter context:include-filter -->
    <context:component-scan base-package="com.atguigu" use-default-filters="false">
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan> 
    
    <!--示例2 
    扫描包所有内容 context:exclude-filter
    自己配置哪些内容不进行扫描 -->
    <context:component-scan base-package="com.atguigu">
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>
</beans>

@Component("userService")
public class UserService {
    public void add() {
        System.out.println("service add...");
    }
}
  • 属性注入
    • @Autowired,根据类型自动装配,多个同类型的则匹配name
    • @Qualifier:根据名称进行注入,需要跟@Autowired一起使用
    • @Resource:可以根据类型注入,可以根据名称注入
    • @Value:注入普通类型属性
  • 完全注解开发,使用配置类替代xml的组件扫描
public interface UserDao {
    public void add();
}

@Repository //默认名称类首字母小写
public class UserDaoImp implements UserDao {
    @Override
    public void add() {
        System.out.println("add...");
    }
}

@Service("userService")
public class UserService {
    @Autowired //自动根据类型注入
    @Qualifier("userDaoImp") //根据名称注入
    private UserDao userDao;

//    @Resource //根据类型注入
    @Resource(name = "userDaoImp") //根据名称注入
    private UserDao userDao;
    
    @Value(value = "hello") //注入普通类型
    private String a;

    public void add() {
        System.out.println("service add..." + a);
        userDao.add();
    }
}

## 完全注解开发
@Configuration //作为配置类,提到xml配置文件
@ComponentScan(basePackages = {"com.atguigu.spring5"})
public class SpringConf {
}

# 测试类
public class TestDemo {

    @Test
    public void test1() {
        ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
        UserService userService = context.getBean("userService", UserService.class);
        userService.add();
    }

    @Test
    public void test2() {
        ApplicationContext context = new AnnotationConfigApplicationContext(SpringConf.class);
        UserService userService = context.getBean("userService", UserService.class);
        userService.add();
    }
}

03 AOP

AOP概念

  • 面向切面编程,利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
  • 通俗描述:不通过修改源代码方式,在主干功能里面添加新功能
  • 术语:
    • 连接点,类里面可以被增强的方法称为连接点
    • 切入点,实际被增强的方法称为切入点
    • 通知(增强),实际增强的逻辑部分称为通知,前置通知,后置通知,环绕通知,异常通知,最终通知
    • 切面,将通知应用到切入点的过程称为切面

AOP(底层原理)

  • AOP底层使用动态代理
    • 第一种 有接口情况,使用JDK动态代理,创建接口实现类代理对象,增强类的方法
    • 第二种 没有接口情况,使用CGLIB(Code Generation Library)动态代理,创建子类的代理对象,增强类的方法
  • JDK动态代理
## 接口
public interface UserDao {
    public int add(int a, int b);
    public void update(String s);
}

## 实现类
public class UserDaoImp implements UserDao {
    public String[] sa = {"1", "2"};

    @Override
    public int add(int a, int b) {
        System.out.println("add()...");
        return a + b;
    }

    @Override
    public void update(String s) {
        System.out.println(s);
    }

    public String[] getSa() {
        return sa;
    }
}

## 代理类
public class JDKProxy {
    public static void main(String[] args) {
        //创建接口实现类代理对象
        Class[] interfaces = {UserDao.class};
        UserDaoImp userDaoImp = new UserDaoImp();
        UserDao userDao = (UserDao) Proxy.newProxyInstance(UserDaoImp.class.getClassLoader(), interfaces,
                new UserDaoProxy(userDaoImp));

        //测试
        int add = userDao.add(1, 2);//使用代理类对象调用,会传给InvocationHandler,调用被代理类对象的方法
        userDao.update("hello");
//        userDao.getSa(); //无法调用,只代理接口中的方法

    }
}

class UserDaoProxy implements InvocationHandler {
    private Object object;

    public UserDaoProxy(Object object) {
        this.object = object;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        System.out.println("before invocation...");
        Object res = method.invoke(object, args); //被代理类对象及其参数
        System.out.println("after invocation... + res: " + res); //没有返回值返回null
        return res;
    }
}

AOP操作(准备工作)

  • Spring框架一般都是基于AspectJ实现AOP操作,)AspectJ不是Spring组成部分,独立AOP框架,一般把AspectJ和Spirng框架一起使用,进行AOP操作
  • 基于AspectJ实现AOP操作:基于xml配置文件方式基于注解方式
  • 切入点表达式
    • 作用:知道对哪个类里面的哪个方法进行增强
    • 语法结构: execution([权限修饰符] [返回类型] [类全路径] [方法名称]([参数列表]) )
举例1:对com.atguigu.dao.BookDao类里面的add进行增强
execution(* com.atguigu.dao.BookDao.add(..))
举例2:对com.atguigu.dao.BookDao类里面的所有的方法进行增强
execution(* com.atguigu.dao.BookDao.* (..))
举例3:对com.atguigu.dao包里面所有类,类里面所有方法进行增强
execution(* com.atguigu.dao.*.* (..))

AOP操作(AspectJ 注解)

  • 导入相关依赖
    • com.springsource.net.sf.cglib-2.2.0.jar
    • com.springsource.org.aopalliance-1.0.0.jar
    • com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
    • spring-aspects-5.2.6.RELEASE.jar
//被增强的类
@Component //使用注解创建对象
public class User {
    public void add() {
        System.out.println("add...");
//        throw new RuntimeException();
    }
}

//增强的类
@Component //使用注解创建对象
@Aspect //生成代理对象
@Order(1) //有多个增强类对同一个方法进行增强,设置增强类优先级,数字越小优先级越高
public class UserProxy {

    //相同切入点抽取
    @Pointcut("execution(* com.atguigu.spring5.aopAnnotation.User.add(..))")
    public void pointDemo() {}
    
    //@Before表示前置通知,增强User.add()方法
    @Before(value = "pointDemo()") //使用相同切入点抽取的方法pointDemo()
    public void before() {
        System.out.println("before...");
    }

    //@AfterReturning表示后置通知,增强User.add()方法
    @AfterReturning(value = "execution(* com.atguigu.spring5.aopAnnotation.User.add(..))")
    public void afterReturning() {
        System.out.println("afterReturning...");
    }

    //@After表示最终通知,增强User.add()方法
    @After(value = "execution(* com.atguigu.spring5.aopAnnotation.User.add(..))")
    public void after() {
        System.out.println("after...");
    }

    //@AfterThrowing表示异常通知,增强User.add()方法
    @AfterThrowing(value = "execution(* com.atguigu.spring5.aopAnnotation.User.add(..))")
    public void afterThrowing() {
        System.out.println("afterThrowing...");
    }

    //@Around表示环绕通知,增强User.add()方法
    @Around(value = "execution(* com.atguigu.spring5.aopAnnotation.User.add(..))")
    public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("环绕之前");
        proceedingJoinPoint.proceed();
        System.out.println("环绕之后");
    }
}

//多个增强类设置优先级
@Component //使用注解创建对象
@Aspect //生成代理对象
@Order(2) //有多个增强类多同一个方法进行增强,设置增强类优先级,数字越小优先级越高
public class UserProxy2 {
    //@Before表示前置通知,增强User.add()方法
    @Before(value = "com.atguigu.spring5.aopAnnotation.UserProxy.pointDemo()") //使用相同切入点抽取的方法pointDemo()
    public void before() {
        System.out.println("before2...");
    }
}

## 完全注解开发
@Configuration
@ComponentScan(basePackages = "com.atguigu.spring5.aopAnnotation")
@EnableAspectJAutoProxy(proxyTargetClass = true) //默认为false也能执行,为什么?
public class AOPConfig {
}

## 测试类
public class TestDemo {

    @Test
    public void test1() {
        ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
        User user = context.getBean("user", User.class);
        user.add();
    }

    @Test
    public void test2() { //完全注解开发
        ApplicationContext context = new AnnotationConfigApplicationContext(AOPConfig.class);
        User user = context.getBean("user", User.class);
        user.add();
    }
}
<?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:component-scan base-package="com.atguigu.spring5.aopAnnotation"></context:component-scan>

    <!--开启生成代理对象-->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>

AOP操作(AspectJ 配置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">

    <!--创建对象-->
    <bean id="book" class="com.atguigu.spring5.aopXML.Book"></bean>
    <bean id="bookProxy" class="com.atguigu.spring5.aopXML.BookProxy"></bean>

    <!--配置aop-->
    <aop:config>
        <!--配置切入点-->
        <aop:pointcut id="p" expression="execution(* com.atguigu.spring5.aopXML.Book.buy(..))"/>
        <!--配置切面-->
        <aop:aspect ref="bookProxy" order="1">
            <!--配置增强方法作用在具体方法上-->
            <aop:before method="before" pointcut-ref="p"></aop:before>
        </aop:aspect>
    </aop:config>
</beans>

04 JdbcTemlate

JdbcTemplate(概念和准备)

  • 什么是JdbcTemplate:Spring框架对JDBC进行封装,使用JdbcTemplate方便实现对数据库操作
  • 准备:引入相关jar包
    • spring-tx-5.2.6.RELEASE.jar
      spring-orm-5.2.6.RELEASE.jar
      spring-jdbc-5.2.6.RELEASE.jar
      mysql-connector-java-5.1.7-bin.jar
      druid-1.1.9.jar
    • 配置数据库连接池
    • 配置JdbcTemplate对象,注入dataSource
    • 创建service类,创建dao类,在dao类中注入jdbcTemplate对象
<?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">

    <!-- 数据库连接池 -->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
        <property name="url" value="jdbc:mysql:///user_db_spring"/>
        <property name="username" value="root"/>
        <property name="password" value="999999"/>
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
    </bean>

    <!-- JdbcTemplate对象 -->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> 
        <!--注入dataSource-->
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    
    <!--开启组件扫描-->
    <context:component-scan base-package="com.atguigu.spring5"></context:component-scan>
</beans>
@Service
public class BookService {
    @Autowired
    private BookDao bookDao;
}

public interface BookDao {
}

@Repository
public class BookDaoImp implements BookDao {
    @Autowired
    private JdbcTemplate jdbcTemplate;
}

JdbcTemplate操作数据库(添加,修改,删除)

  • 创建数据库表对应的实体类
  • 在service中添加add功能,对应的在BookDao接口中添加,在Dao实现类中使用JdbcTemplate的update方法实现具体功能
@Service
public class BookService {
    @Autowired
    private BookDao bookDao;

    public void addBook(Book book) {
        bookDao.add(book);
    }
}

public interface BookDao {
    void add(Book book);
}

@Repository
public class BookDaoImp implements BookDao {
    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Override
    public void add(Book book) {
        String sql = "insert into book values(?,?,?)";
        Object[] args = {book.getId(), book.getName(), book.getStatus()};
        int update = jdbcTemplate.update(sql, args);
        System.out.println(update);
    }
}

// 实体类
public class Book {
    private String id;
    private String name;
    private String status;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

    public String getStatus() {
        return status;
    }

    public void setStatus(String status) {
        this.status = status;
    }
}

// 测试
public class TestDemo {
    @Test
    public void testJdbcTemplate () {
        ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
        BookService bookService = context.getBean("bookService", BookService.class);
        Book book = new Book();
        book.setId("id1");
        book.setName("name1");
        book.setStatus("status1");
        bookService.addBook(book); //测试添加功能
    }
}

JdbcTemplate操作数据库(查询返回某个值,对象,集合)

//返回值
Override public int selectCount() {
    String sql = "select count(*) from t_book"; Integer count =         
    jdbcTemplate.queryForObject(sql, Integer.class); 
    return count; 
}

//返回对象
@Override public Book findBookInfo(String id) { 
    String sql = "select * from t_book where user_id=?"; //调用方法 
    Book book = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<Book> Book.class), id); 
return book; 
}

//返回集合
@Override public List<Book> findAllBook() { 
    String sql = "select * from t_book"; //调用方法 
    List<Book> bookList = jdbcTemplate.query(sql, new BeanPropertyRowMapper<Book>(Book.class)); 
return bookList; 
}

JdbcTemplate操作数据库(批量添加、修改、删除)

//批量添加 
@Override public void batchAddBook(List<Object[]> batchArgs) { 
    String sql = "insert into t_book values(?,?,?)"; 
    int[] ints = jdbcTemplate.batchUpdate(sql, batchArgs);         
    System.out.println(Arrays.toString(ints)); 
}

//批量修改 
@Override public void batchUpdateBook(List<Object[]> batchArgs) { 
    String sql = "update t_book set username=?,ustatus=? where user_id=?"; int[] ints =     
    jdbcTemplate.batchUpdate(sql, batchArgs); 
    System.out.println(Arrays.toString(ints)); 
}

//批量删除 
@Override public void batchDeleteBook(List<Object[]> batchArgs) { 
    String sql = "delete from t_book where user_id=?"; 
    int[] ints = jdbcTemplate.batchUpdate(sql, batchArgs);     
    System.out.println(Arrays.toString(ints)); 
}

05 事务管理

事务操作(事务概念)

  • 什么是事务:事务是数据库操作最基本单元,逻辑上一组操作,要么都成功,如果有一个失败所有操作都失败
  • 四个特性(ACID):(1)原子性(2)一致性(3)隔离性(4)持久性

事务操作(Spring事务管理介绍)

  • 事务添加到JavaEE三层结构里面Service层(业务逻辑层)
  • 两种方式:编程式事务管理声明式事务管理(使用)
  • 声明式事务管理:(1)基于注解方式(使用)(2)基于xml配置文件方式,底层使用AOP原理
  • Spring事务管理API,提供一个接口,代表事务管理器,针对不同的框架提供不同的实现类

事务操作(使用注解配置声明式事务管理)

  • xml中配置事务管理器,开启事务注解
  • 使用注解@Transactional,可以加在类上面,也可以加在方法上面
  • 其中的参数配置:
    • propagation,有7种,常用的有两种REQUIRED和REQUIRED_NEW,考虑a方面调用b方法,对于前者,如果a有事务,调用b后使用a里面的事务,如果a没有事务,创建新事务;对于后者,不管a有没有事务都创建新事务
    • isolation,事务隔离级别,有4中,对应三个读问题,脏读,不可重复读,幻读
    • timeout,超时时间,规定事务提交时间,未提交则回滚
    • readOnly,是否只读,默认false,可以读可以写
    • rollbackFor,回滚,设置出现哪些异常进行回滚
    • noRollbackFor,不回滚,设置出现那里写异常不回滚
<?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"
       xmlns:tx="http://www.springframework.org/schema/tx"
       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">

    <!-- 数据库连接池 -->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
        <property name="url" value="jdbc:mysql:///user_db_spring"/>
        <property name="username" value="root"/>
        <property name="password" value="999999"/>
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
    </bean>

    <!-- JdbcTemplate对象 -->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <!--注入dataSource-->
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!--开启组件扫描-->
    <context:component-scan base-package="com.atguigu.spring5"></context:component-scan>

    <!--创建事务管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> 
        <!--注入数据源-->
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    
    <!--开启事务注解--> 
    <tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
</beans>
public interface UserDao {
    void reduceMoney();
    void addMoney();
}

@Repository
public class UserDaoImp implements UserDao {
    @Autowired
    private JdbcTemplate jdbcTemplate;

    //Lucy转账100给Mary
    @Override
    public void reduceMoney() {
        String sql = "update account set money = money - ? where name = ?";
        jdbcTemplate.update(sql,100,"lucy");
    }

    //Mary收到100
    @Override
    public void addMoney() {
        String sql = "update account set money = money + ? where name = ?";
        jdbcTemplate.update(sql,100,"mary");
    }
}

@Service
@Transactional
public class UserService {
    @Autowired
    private UserDao userDao;

    public void operation() {
        userDao.reduceMoney();
//        int id = 1/0;
        userDao.addMoney();
    }
}

事务操作(使用xml配置声明式事务管理)

  • 配置事务管理器,配置通知,配置切入点和切面,(基于AOP实现的)
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       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">

    <!-- 数据库连接池 -->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
        <property name="url" value="jdbc:mysql:///user_db_spring"/>
        <property name="username" value="root"/>
        <property name="password" value="999999"/>
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
    </bean>

    <!-- JdbcTemplate对象 -->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <!--注入dataSource-->
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!--开启组件扫描-->
    <context:component-scan base-package="com.atguigu.spring5"></context:component-scan>

    <!--1创建事务管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!--注入数据源-->
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!--2配置通知-->
    <tx:advice id = "txadvice">
        <!--配置事务参数-->
        <tx:attributes>
            <!--指定哪种规则在哪个方法上面添加事务-->
            <tx:method name="operation" propagation="REQUIRED"/>
<!--            <tx:method name="acount*" propagation="REQUIRED"/>-->
        </tx:attributes>
    </tx:advice>

    <!--3配置切入点和切面-->
    <aop:config>
        <!--配置切入点 需要增强的部分-->
        <aop:pointcut id="pt" expression="execution(* com.atguigu.spring5.service.UserService.*(..))"/>
        <!--配置切面-->
        <aop:advisor advice-ref="txadvice" pointcut-ref="pt"></aop:advisor>
    </aop:config>
</beans>

事务操作(完全注解配置声明式事务管理)

  • 创建配置类,使用@Configuration
  • 开启组件扫描,使用@ComponentScan(basePackages = "com.atguigu.spring5")
  • 开启事务管理,使用@EnableTransactionManagement
  • 创建数据库连接池,使用@Bean
  • 创建JdbcTemplate对象,使用@Bean
  • 创建事务管理器,使用@Bean
@Configuration //配置类
@ComponentScan(basePackages = "com.atguigu.spring5") //开启组件扫描
@EnableTransactionManagement //开启事务管理
public class TxConfig {
    //创建数据库连接池
    @Bean
    public DruidDataSource getDruidDataSource() {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql:///user_db_spring");
        dataSource.setUsername("root");
        dataSource.setPassword("999999");
        return dataSource;
    }
    //创建JdbcTemplate对象, 注入dataSource
    @Bean
    public JdbcTemplate getJdbctemplate(DruidDataSource dataSource) {
        //到IOC容器中找dataSource
        JdbcTemplate jdbcTemplate = new JdbcTemplate();
        jdbcTemplate.setDataSource(dataSource); //注入DataSource
        return jdbcTemplate;
    }
    //创建事务管理器
    @Bean
    DataSourceTransactionManager getDataSourceTransactionManager(DruidDataSource dataSource) {
        DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
        transactionManager.setDataSource(dataSource);
        return transactionManager;
    }
}

06 Spring5新特性

  • 整个Spring5框架的代码基于Java8,运行时兼容JDK9,许多不建议使用的类和方法在代码库中删除
  • Spring5框架自带了通用的日志封装,移除Log4jConfigListener,官方建议使用Log4j2
    • 引入相关jar包:
      log4j-api-2.11.2.jar
      log4j-core-2.11.2.jar
      log4j-slf4j-impl-2.11.2.jar
      slf4j-api-1.7.30.jar
    • 配置log4j2.xml
<?xml version="1.0" encoding="UTF-8"?>
<!--日志级别以及优先级排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL -->
<!--Configuration后面的status用于设置log4j2自身内部的信息输出,可以不设置,当设置成trace时,可以看到log4j2内部各种详细输出-->
<configuration status="INFO">
    <!--先定义所有的appender-->
    <appenders>
        <!--输出日志信息到控制台-->
        <console name="Console" target="SYSTEM_OUT">
            <!--控制日志输出的格式-->
            <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
        </console>
    </appenders>
    <!--然后定义logger,只有定义了logger并引入的appender,appender才会生效-->
    <!--root:用于指定项目的根日志,如果没有单独指定Logger,则会使用root作为默认的日志输出-->
    <loggers>
        <root level="info">
            <appender-ref ref="Console"/>
        </root>
    </loggers>
</configuration>
  • Spring5框架核心容器支持@Nullable注解,可以使用在方法、属性、参数上面,表示可以为空
  • Spring5核心容器支持函数式风格GenericApplicationContext
//函数式风格创建对象,交给spring进行管理 
@Test 
public void testGenericApplicationContext() { //1 创建GenericApplicationContext对象         
    GenericApplicationContext context = new GenericApplicationContext(); //2 调用context的方法对象注册 
    context.refresh(); 
    context.registerBean("user1",User.class,() -> new User()); //3 获取在spring注册的对象 // User user = (User)context.getBean("com.atguigu.spring5.test.User"); User     
    user = (User)context.getBean("user1"); 
    System.out.println(user); 
}
  • Spring5支持整合JUnit5
@RunWith(SpringJUnit4ClassRunner.class) //单元测试框架 @ContextConfiguration("classpath:bean1.xml") //加载配置文件
public class JTest4 { 
    @Autowired 
    private UserService userService;

    @Test 
    public void test1() { 
        userService.accountMoney(); 
    } 
}

//使用JUnit5
@ExtendWith(SpringExtension.class) 
@ContextConfiguration("classpath:bean1.xml")
//@SpringJUnitConfig(locations = "classpath:bean1.xml") //使用复合注解代替上面两个注解
public class JTest5 { 
    @Autowired 
    private UserService userService; 

    @Test public void test1() { 
        userService.accountMoney(); 
    } 
}

07 Spring5框架新功能(Webflux)

  • 需要基础知识:SpringMVC,SpringBoot,Maven,Java8新特性

 

 

 

 

 

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值