• Spring综述


    Spring框架概述

    Spring是轻量级的开源的JavaEE框架

    Spring可以解决企业应用开发的复杂性

    Spring有两个核心部分:IOC、AOP

    • IOC:控制反转,将创建对象过程交给Spring进行管理
    • Aop:面向切面,不修改源代码进行功能增强

    Spring特点

    • 方便解耦,简化开发
    • Aop编程支持
    • 方便程序测试
    • 方便和其他框架进行整合
    • 方便进行事务操作
    • 降低API开发难度

    IOC容器

    概念和原理

    什么是IOC

    • 控制反转,把对象创建和对象之间的调用过程,交给Spring进行管理
    • 使用IOC目的:为了耦合度降低

    IOC底层原理:xml解析、工程模式、反射

    接口(BeanFactory)

    IOC思想基于IOC容器完成,IOC容器底层就是对象工厂

    Spring提供IOC容器实现的两种方式(两个接口):

    • BeanFactory:IOC容器基本实现,是Spring内部的使用接口,不提供开发人员进行使用

      • 加载配置文件时不会创建对象,在获取对象时去创建对象
    • ApplicationContext:BeanFactory接口的子接口,提供更多更强大的功能,一般由开发人员进行使用

      • 加载配置文件时就会把在配置文件的对象进行创建

    IOC操作Bean

    什么是Bean管理:指两个操作

    • Spring创建对象
    • Spring注入属性

    Bean管理操作有两种方式

    • 基于xml配置文件方式实现
    • 基于注解方式实现

    操作Bean管理(xml)

    1、基于xml方式创建对象

    - 在Spring配置文件中,使用bean标签,标签里面添加对应属性,就可以实现对象创建
    - 在bean标签有很多属性,介绍常用的属性
      - id:唯一标识
      - class:类全路径
    - 创建对象时,默认执行无参构造方法完成对象创建
    
    • 1
    • 2
    • 3
    • 4
    • 5

    2、基于xml方式注入属性

    DI:依赖注入
    
    • 1

    3、第一种注入方式:使用set方法进行注入

    (1)创建类,定义属性和对应的set方法
    public class Book {
        //创建属性
        private String bname;
        private String bauthor;
    
        //创建属性对应的set方法
        public void setBname(String bname) {
            this.bname = bname;
        }
    
        public void setBauthor(String bauthor) {
            this.bauthor = bauthor;
        }
    
        public void testDemo(){
            System.out.println(bname + "::" + bauthor);
        }
    }
    
    (2)在spring配置文件配置对象创建,配置属性注入
        <!--set方法注入属性-->
        <bean id="book" class="com.yingzi.spring5.Book">
    <!--        使用property完成属性注入
                name:类里面属性名称
                value:向属性注入的值
    -->
            <property name="bname" value="易筋经"></property>
            <property name="bauthor" value="达摩老祖"></property>
        </bean>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    第二种注入方式:使用有参数构造进行注入

    (1)创建类,定义属性,创建属性对应用参数构造方法
    public class Orders {
    
        private String oname;
        private String address;
    
        //有参构造
        public Orders(String oname, String address) {
            this.oname = oname;
            this.address = address;
        }
    
        public void orderTest(){
            System.out.println(oname + " :: " + address);
        }
    }
    
    (2)在spring配置文件中进行配置
            <bean id="orders" class="com.yingzi.spring5.Orders">
            <constructor-arg name="oname" value="电脑"></constructor-arg>
            <constructor-arg name="address" value="China"></constructor-arg>
        </bean>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    操作Bean管理(FactoryBean)

    Spring有两种类型bean,一种普通bean,另外一种工厂bean

    • 普通bean:在配置文件中定义bean类型就是返回类型
    • 工厂bean:在配置文件定义bean类型可以和返回类型不一样

    第一步,创建类,让这个类作为工厂bean,实现接口FactoryBean

    第二步,实现接口里面的方法,在实现的方法中定义返回的bean类型

    public class MyBean implements FactoryBean<Course> {
    
        //定义返回bean
        @Override
        public Course getObject() throws Exception {
            Course course = new Course();
            course.setCname("abc");
            return course;
        }
    
        @Override
        public Class<?> getObjectType() {
            return null;
        }
    
        @Override
        public boolean isSingleton() {
            return false;
        }
    }
    
        <bean id="myBean" class="com.yingzi.spring5.factorybean.MyBean">
        </bean>
        
            @Test
        public void testCollection3(){
            ApplicationContext context = new ClassPathXmlApplicationContext("bean3.xml");
            Course course = context.getBean("myBean", Course.class);
            System.out.println(course);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    操作Bean管理(作用域)

    1、在Spring里面,设置创建bean实例时单实例还是多实例

    2、在Spring里面,默认情况下,bean是单实例对象

    3、如何设置单实例还是多实例:在spring配置文件bean标签里有属性(scope)

    • singleton(默认):单实例
      • 加载spring配置文件时就会创建单实例对象
    • prototype:多实例
      • 在调用getBean方法时创建多实例对象
    操作Bean管理(bean生命周期)

    生命周期:从对象创建到对象销毁的过程

    bean生命周期:

    1. 通过构造器创建bean实例
    2. 为bean的属性设置值和对其他bean引用(调用set方法)
    3. 调用bean的初始化方法(需要进行配置初始化的方法)
    4. bean可以使用了(对象获取到了)
    5. 当容器关闭时,调用bean的销毁方法(需要进行配置销毁的方法)
    public class Orders {
        
        public Orders() {
            System.out.println("第一步:执行无参数构造创建Bean实例");
        }
    
        private String oname;
        public void setOname(String oname) {
            this.oname = oname;
            System.out.println("第二步:调用set方法设置属性值");
        }
    
        //创建执行的初始化方法
        public void initMethod(){
            System.out.println("第三步:执行初始化的方法");
        }
    
        //创建执行的销毁方法
        public void destroyMethod(){
            System.out.println("第五步:执行销毁的方法");
        }
    }
    
        <bean id="orders" class="com.yingzi.spring5.bean.Orders" init-method="initMethod" destroy-method="destroyMethod">
            <property name="oname" value="手机"></property>
        </bean>
            
            @Test
        public void testCollection4() {
            ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean4.xml");
    
            Orders orders = context.getBean("orders", Orders.class);
            System.out.println("第四步:获取创建bean实例对象");
            System.out.println(orders);
    
            //手动让bean实例销毁
            context.close();
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    bean的后置处理器,bean生命周期有七步

    1. 通过构造器创建bean实例(无参构造)
    2. 为bean的属性设置值和对其他bean引用(调用set方法)
    3. 把bean实例传递bean后置处理器的方法postProcessBeforeInitialization
    4. 调用bean的初始化方法(需要进行配置初始化的方法)
    5. 把bean的实例传递bean后置处理器的方法postProcessAfterInitialization
    6. bean可以使用了(对象获取到了)
    7. 当容器关闭时,调用bean的销毁方法(需要进行配置销毁的方法)
    public class MyBeanPost implements BeanPostProcessor {
    
        @Override
        public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
            System.out.println("初始化之前执行的方法");
            return bean;
        }
    
        @Override
        public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
            System.out.println("初始化之后执行的方法");
            return bean;
        }
    }
    
    <!--    配置后置处理器-->
        <bean id="myBeanPost" class="com.yingzi.spring5.bean.MyBeanPost"></bean>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

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

    自动装配:根据指定装配规则(属性名称或者属性类型),Spring自动将匹配的属性值进行注入

        <!--实现自动装配,bean标签属性autowire,配置自动装配
        byName:根据属性名称注入,注入值bean的id值和类属性名称一样
        byType:根据属性类型注入
        -->
    
        <bean id="emp" class="com.yingzi.spring5.autowire.Emp" autowire="byName">//此处可换byType
    <!--        <property name="dept" ref="dept"></property>-->
        </bean>
        <bean id="dept" class="com.yingzi.spring5.autowire.Dept"></bean>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    操作Bean管理(外部属性文件)

    1、直接配置数据库信息

    • 配置徳鲁伊连接池
    • 引入徳鲁伊连接池依赖jar包
        <!--直接配置连接池-->
        <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
            <property name="driverClassName" value="com.mysql.cj.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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    2、引入外部属性文件配置数据库连接池

    • 创建外部属性文件,properties格式文件,写数据库信息

      prop.driverClass=com.mysql.cj.jdbc.Driver
      prop.url=jdbc:mysql//localhost:3306/userDb
      prop.userName=root
      prop.password=root
      
      • 1
      • 2
      • 3
      • 4
    • 把外部properties属性文件引入到spring配置文件中

      • 引入context名称空间

        xmlns:context="http://www.springframework.org/schema/context"
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
        
        • 1
        • 2
      • 在spring配置文件使用标签引入外部属性文件

            <!--引入外部属性文件-->
            <context:property-placeholder location="classpath:jdbc.properties"/>
        
            <!--配置连接池-->
            <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>
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10

    操作Bean管理(基于注解)

    1、什么是注解
    • 注解是代码特殊标记,格式:@注解名称(属性名称=属性值,属性名称=属性值…)
    • 使用注解,注解作用在类上面,方法上面,属性上面
    • 使用注解目的:简化xml配置
    2、Sping针对Bean管理中创建对象提供注解
    • @Component
    • @Service
    • @Controller
    • @Repository

    上面四个注解功能一样,都可以用来创建bean实例

    3、基于注解方式实现对象创建
    • 第一步:引入依赖

    • 第二步:开启组件扫描

      <!--开启组件扫描
          1、如果扫描多个包,多个包使用逗号隔开
          2、扫描包上层目录
      -->
          <context:component-scan base-package="com.yingzi.spring5.dao,com.yingzi.spring5.service"></context:component-scan>
      
      • 1
      • 2
      • 3
      • 4
      • 5
    • 第三步 创建类,在类上面添加创建对象注解

      //注解里面value属性值可以省略不写
      //默认值是类名称,首字母小写 UserService -> userService
      @Component(value = "userService")//<bean id="userService" class=".."/>
      public class UserService {
      
          public void add(){
              System.out.println("service add.......");
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
    4、开启组件扫描细节配置
        <!--    示例1
        use-default-filters="false":表示现在不使用默认filter,自己配置filter
        context:include-filter:设置扫描哪些内容
        -->
        <context:component-scan base-package="com.yingzi" 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.yingzi">
            <context:exclude-filter type="annotation"
                                    expression="org.springframework.stereotype.Controller"/>
        </context:component-scan>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    5、基于注解方式实现属性注入
    • @Autowired:根据属性类型进行自动装配

      第一步:把service、dao对象创建,在service、dao类添加创建对象注解

      第二步:把service注入dao对象,在service类添加dao类型属性,在属性上面使用注解

          //定义dao类型属性,不需要添加set方法
          //添加注入属性注解
          @Autowired
          private UserDao userDao;
      
          public void add() {
              System.out.println("service add.......");
              userDao.add();
          }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
    • @Qualifier:根据属性名称进行注入

      和上面的@Autowired一起使用

          //定义dao类型属性,不需要添加set方法
          //添加注入属性注解
          @Autowired//根据类型进行注入
          @Qualifier(value = "userDaoImp11")//根据名称进行注入
          private UserDao userDao;
      
      • 1
      • 2
      • 3
      • 4
      • 5
    • @Resource:可以根据类型注入,也可以根据名称注入

      @Resource//根据类型进行注入
      @Resource(name="userDaoImp11")//根据名称进行注入
      
      • 1
      • 2
    • @Value:注入普通类型属性

      @Value(value="abc")
      private String name;
      
      • 1
      • 2
    6、完全注解开发
    • 创建配置类,替代xml配置文件

      @Configuration//作为配置类,替代xml配置文件
      @ComponentScan(basePackages = {"com.yingzi"})
      public class SpringConfig {
      }
      
      • 1
      • 2
      • 3
      • 4
    • 编写测试类

          @Test
          public void testService2() {
              ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
              UserService userService = context.getBean("userService", UserService.class);
              System.out.println(userService);
              userService.add();
          }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7

    AOP

    概念
    • (Aspect Oriented Programming,AOP)面向切面编程,利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高开发效率

    • 通俗描述:不通过修改源代码方式,在主干功能里面添加新功能

    • 使用登录例子说明AOP

    底层原理

    AOP底层使用动态代理,有两种情况动态代理

    • 有接口情况,使用JDK动态代理:创建接口实现类代理对象,增强类的方法
    • 没有接口情况,使用CGLIB动态代理:创建子类的代理对象,增强类的方法
    JDK动态代理

    使用JDK动态代理,Proxy类里面的方法创建代理对象

    调用newProxyInstance方法

    方法有三个参数:

    • 第一参数,类加载器
    • 第二参数,增强方法所在的类,这个类实现的接口,支持多接口
    • 第三参数,实现这接口InvocationHandler,创建代理对象,写增强的部分

    编写JDK动态代理代码

    (1)创建接口,定义方法
        public interface UserDao {
        public int add(int a, int b);
    
        public String update(String id);
    }
    (2)创建接口实现类,实现方法
        public class UserDaoImpl implements UserDao {
        @Override
        public int add(int a, int b) {
            return a + b;
        }
    
        @Override
        public String update(String id) {
            return id;
        }
    }
    (3)使用Proxy类创建接口代理对象
        public class JDKProxy {
    
        public static void main(String[] args) {
            //创建接口实现类对象
            Class[] interfaces = {UserDao.class};
    //        Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new InvocationHandler() {
    //            @Override
    //            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    //                return null;
    //            }
    //        })
            UserDaoImpl userDao = new UserDaoImpl();
            UserDao dao = (UserDao) Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new UserDaoProxy(userDao));
            int result = dao.add(1, 2);
            System.out.println("result:" + result);
        }
    }
    
    //创建代理对象代码
    class UserDaoProxy implements InvocationHandler {
    
        //1、把创建的是谁的代理对象,把谁传递过来
        //有参数构造传递
        private Object obj;
    
        public UserDaoProxy(Object obj) {
            this.obj = obj;
        }
    
        //增强逻辑
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    
            //方法之前
            System.out.println("方法之前执行...." + method.getName() + ":传递的参数..." + Arrays.toString(args));
            //被增强的方法执行
            Object res = method.invoke(obj, args);
            //方法之后
            System.out.println("方法之后执行..." + obj);
    
            return res;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    术语

    连接点:类里面哪些方法可以被增强,这些方法称为连接点

    切入点:实际被真正增强的方法,称为切入点

    通知(增强):实际增强的逻辑部分称为通知,通知有多种类型

    • 前置通知
    • 后置通知
    • 环绕通知
    • 异常通知
    • 最终通知

    切面:是动作,将通知应用到切入点过程

    AOP操作

    1、Spring框架一般都是基于AspectJ实现AOP操作

    • AspectJ不是Spring组成部分,独立AOP框架,一般把AspectJ和Spring框架一起使用,进行AOP操作

    2、基于AspectJ实现AOP操作

    • 基于xml配置文件实现
    • 基于注解方式实现

    3、在项目工程里面引入AOP相关依赖

    4、切入点表达式

    (1)切入点表达式作用:知道对哪个类里面的哪些方法进行增强

    (2)语法结构:execution([权限修饰符][返回类型][类全路径][方法名称][参数列表])

    举例1:对com.yingzi.dao.BookDao类里面的add进行增强
        execution(* com.yingzi.dao.BookDao.add(..))
    举例2:对com.yingzi.dao.BookDao 类里面的所有的方法进行增强
    	execution(* com.yingzi.dao.BookDao.* (..))
    举例3:对com.yingzi.dao 包里面所有类,类里面所有方法进行增强
    	execution(* com.yingzi.dao.*.* (..))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    AspectJ注解方式

    1、创建类,在类里面定义方法

    public class User {
    
        public void add(){
            System.out.println("add......");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    2、创建增强类

    public class UserProxy {
        public void before(){//前置通知
            System.out.println("before....");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    3、进行通知的配置

    • 在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:context="http://www.springframework.org/schema/context"
             xmlns:aop="http://www.springframework.org/schema/aop"
             xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://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.yingzi.spring5.aopanno">
          </context:component-scan>
      
      </beans>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
    • 使用注解创建User、UserProxy对象

      @Component
      public class User {
          ...
      }
      @Component
      public class UserProxy {
          ...
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
    • 在增强类上面添加注解@Aspect

      @Component
      @Aspect//生成代理对象
      public class UserProxy {
          ...
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
    • 在spring配置文件中开启生成代理对象

      	<!--开启Aspect生成代理对象-->
          <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
      
      • 1
      • 2

    4、配置不同类型的通知

    在增强类里面,作为通知方法上面添加通知类型注解,使用切入点表达式配置

    @Component
    @Aspect//生成代理对象
    public class UserProxy {
    
        //前置通知
        //@Before注解表示作为前置通知
        @Before(value = "execution(* com.yingzi.spring5.aopanno.User.add(..))")
        public void before() {
            System.out.println("before....");
        }
    
        //后置通知
        @AfterReturning(value = "execution(* com.yingzi.spring5.aopanno.User.add(..))")
        public void afterRuturning() {
            System.out.println("afterReturning..............");
        }
    
        //最终通知
        @After(value = "execution(* com.yingzi.spring5.aopanno.User.add(..))")
        public void after() {
            System.out.println("after.....=");
        }
    
        //异常通知
        @AfterThrowing(value = "execution(* com.yingzi.spring5.aopanno.User.add(..))")
        public void afterThrowing() {
            System.out.println("afterThrowing........");
        }
    
        //环绕通知
        @Around(value = "execution(* com.yingzi.spring5.aopanno.User.add(..))")
        public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
            System.out.println("环绕之前.....");
            proceedingJoinPoint.proceed();//被增强的方法执行
            System.out.println("环绕之后.....");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    5、相同的切入点抽取

        //相同切入点抽取
        @Pointcut(value = "execution(* com.yingzi.spring5.aopanno.User.add(..))")
        public void pointdeomo() {
        }
    
        //前置通知
        //@Before注解表示作为前置通知
        @Before(value = "pointdeomo()")
        public void before() {
            System.out.println("before....");
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    6、有多个增强类对同一个方法进行增强,设置增强类优先级

    在增强类上面添加注解@Order(数字类型值),值越小优先级越高

    7、完全使用注解开发

    创建配置类,不需要创建xml配置文件

    @Configuration
    @ComponentScan(basePackages = {"com.yingzi"})
    @EnableAspectJAutoProxy(proxyTargetClass = true)
    public class ConfigAop {
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    AspectJ配置文件

    1、创建两个类,增强类和被增强类,创建方法

    2、在spring配置文件中创建两个类对象

        <bean id="book" class="com.yingzi.spring5.aopxml.Book"></bean>
        <bean id="bookProxy" class="com.yingzi.spring5.aopxml.BookProxy"></bean>
    
    • 1
    • 2

    3、在spring配置文件中配置切入点

        <!--    配置aop增强-->
        <aop:config>
            <!--切入点-->
            <aop:pointcut id="p" expression="execution(* com.yingzi.spring5.aopxml.Book.buy(..))"/>
            <!--配置切面-->
            <aop:aspect ref="bookProxy">
                <!--增强作用在具体的方法上-->
                <aop:before method="before" pointcut-ref="p"/>
            </aop:aspect>
        </aop:config>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    JdbcTemplate

    Spring框架对JDBC进行封装,使用JdbcTemplate方便实现对数据库操作

    准备工作:

    1、引入相关jar包

    2、在spring配置文件配置数据库连接池

        <!--    数据库连接池-->
        <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
              destroy-method="close">
            <property name="url" value="jdbc:mysql:///user_db"/>
            <property name="username" value="root"/>
            <property name="password" value="000000"/>
            <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
        </bean>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    3、配置JdbcTemplate对象,注入DataSource

        <!--    配置JdbcTemplate对象,注入DataSource-->
        <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
            <!--注入 dataSource-->
            <property name="dataSource" ref="dataSource"></property>
        </bean>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    4、创建service、dao类,在dao注入jdbcTemplate对象

        <!--    组件扫描-->
        <context:component-scan base-package="com.yingzi"></context:component-scan>
    
    • 1
    • 2
    -------Service-----------
    
    @Service
    public class BookService {
    
        //注入dao
        @Autowired
        private BookDao bookDao;
    
        //添加的方法
        public void addBook(Book book){
            bookDao.add(book);
        }
    }
    
    ------Dao------------
        @Repository
    public class BookDaoImpl implements BookDao{
    
        //注入JdbcTemplate
        @Autowired
        private JdbcTemplate jdbcTemplate;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    添加

    1、对应数据库创建实体类

    public class Book {
        private String userId;
        private String username;
        private String ustatus;
    
        public String getUserId() {
            return userId;
        }
    
        public void setUserId(String userId) {
            this.userId = userId;
        }
    
        public String getUsername() {
            return username;
        }
    
        public void setUsername(String username) {
            this.username = username;
        }
    
        public String getUstatus() {
            return ustatus;
        }
    
        public void setUstatus(String ustatus) {
            this.ustatus = ustatus;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    2、编写service、dao

    • 在dao进行数据库添加操作
    • 调用JdbcTemplate对象,update方法实现添加操作
    @Repository
    public class BookDaoImpl implements BookDao{
    
        //注入JdbcTemplate
        @Autowired
        private JdbcTemplate jdbcTemplate;
    
        @Override
        public void add(Book book) {//添加的方法
            //1、创建sql语句
            String sql = "insert into t_book values(?,?,?)";
            Object[] args = {book.getUserId(), book.getUsername(), book.getUstatus()};
            int update = jdbcTemplate.update(sql,args);
    
            System.out.println(update);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    3、测试类

        @Test
        public void testJdbcTemplate() {
            ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
            BookService bookService = context.getBean("bookService", BookService.class);
            Book book = new Book();
            book.setUserId("1");
            book.setUsername("java");
            book.setUstatus("a");
            bookService.addBook(book);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    修改、删除
        @Override
        public void updateBook(Book book) {//修改的方法
            String sql = "update t_book set username=?,ustatus=? where user_id=?";
            Object[] args = {book.getUsername(), book.getUstatus(), book.getUserId(),};
            int update = jdbcTemplate.update(sql, args);
            System.out.println(update);
        }
    
        @Override
        public void delete(String id) {//删除的方法
            String sql = "delete from t_book where user_id=?";
            int update = jdbcTemplate.update(sql, id);
            System.out.println(update);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    查询返回某个值
        @Override
        public int selectCount() {//查询表记录数
            String sql = "select count(*) from t_book";
            Integer count = jdbcTemplate.queryForObject(sql, Integer.class);
    
            return count;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    查询返回对象
        @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;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    查询返回集合
        @Override
        public List<Book> findBook() {//查询返回集合
            String sql = "select * from t_book";
            List<Book> bookList = jdbcTemplate.query(sql, new BeanPropertyRowMapper<Book>(Book.class));
            return bookList;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    批量添加

    操作表里面多条记录

        @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));
        }
    
    	    //批量添加
            List<Object[]> batchArgs = new ArrayList<>();
            Object[] o1 = {"3","java","a"};
            Object[] o2 = {"4","c++","b"};
            Object[] o3 = {"5","MySQL","c"};
            batchArgs.add(o1);
            batchArgs.add(o2);
            batchArgs.add(o3);
            //调用批量添加
            bookService.batchAdd(batchArgs);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    批量修改
        @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(ints);
        }
    
            //批量修改
            List<Object[]> batchArgs = new ArrayList<>();
            Object[] o1 = {"java0909","a3","3"};
            Object[] o2 = {"c++1010","b4","4"};
            Object[] o3 = {"MySQL1111","c5","5"};
            batchArgs.add(o1);
            batchArgs.add(o2);
            batchArgs.add(o3);
            //调用方法实现批量修改
            bookService.batchUpdate(batchArgs);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    批量删除
        @Override
        public void batchDelete(List<Object[]> batchArgs) {//批量删除
            String sql = "delete from t_book where user_id=?";
            int[] ints = jdbcTemplate.batchUpdate(sql, batchArgs);
            System.out.println(Arrays.toString(ints));
        }
    
            //批量删除
            ArrayList<Object[]> batchArgs = new ArrayList<>();
            Object[] o1 = {"3"};
            Object[] o2 = {"4"};
            batchArgs.add(o1);
            batchArgs.add(o2);
            //调用方法实现批量删除
            bookService.batchDelete(batchArgs);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    事务操作

    事务是数据库操作最基本单元,逻辑上一组操作,要么都成功,如果有一个失败所有操作都失败

    事务的四个特性(ACID):原子性、一致性、隔离性、持久性

    1、创建数据库表,添加记录

    2、创建service,搭建dao,完成对象创建、注入关系

    • service注入dao,在dao注入jdbcTemplate,在JdbcTemplate注入DataSource

      @Service
      public class UserService {
          //注入dao
          @Autowired
          private UserDao userDao;
      }
      
      @Repository
      public class UserDaoImpl implements UserDao {
      
          @Autowired
          private JdbcTemplate jdbcTemplate;
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13

    3、在dao创建两个方法,多钱少钱

    @Repository
    public class UserDaoImpl implements UserDao {
    
        @Autowired
        private JdbcTemplate jdbcTemplate;
    
        //lucy转帐100给mary
        @Override
        public void reduceMoney() {//少钱
            String sql = "update t_account set money=money-? where username=?";
            jdbcTemplate.update(sql, 100, "lucy");
        }
    
        @Override
        public void addMoney() {//多钱
            String sql = "update t_account set money=money+? where username=?";
            jdbcTemplate.update(sql, 100, "mary");
        }
    }
    
    @Service
    public class UserService {
    
        //注入dao
        @Autowired
        private UserDao userDao;
    
        //转帐的方法
        public void accountMoney() {
            userDao.reduceMoney();//lucy少100
    
            userDao.addMoney();//mary多100
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    Spring事务管理介绍

    1、事务添加到JavaEE三层结构里面Service层(业务逻辑层)

    2、在Spring进行事务管理操作:有两种方式,编程式事务管理、声明式事务管理(使用)

    3、声明式事务管理:

    • 基于注解方式(使用)
    • 基于xml配置文件方式

    4、在Sprng进行声明式事务管理,底层使用AOP原理

    5、Spring事务管理AIP:提供一个接口,代表事务管理器,这个接口针对不同的框架提供不同的实现类

    注解声明式事务管理

    1、在spring配置文件配置事务管理器

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

    2、在spring配置文件,开启事务注解

    引入名称空间tx

    <?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">
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    开启事务注解

        <!--开启事务注解-->
        <tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
    
    • 1
    • 2

    3、在service类上面(或者service类里面方法的上面)添加事务注解

    • @Transactional,这个注解添加到类上面,也可以添加到方法上面
    • 若把这个注解添加到类上,那么这个类里的所有方法都添加事务
    • 若把这个注解添加到方法上,为这个方法添加事务
    @Transactional
    public class UserService {
    }
    
    • 1
    • 2
    • 3
    声明式事务管理参数配置

    1、在service类上面添加注解@Transactional,在这个注解里面可以配置事务相关参数

    2、propagation:事务传播行为

    多事务方法直接进行调用,这个过程中事务是如何进行管理的

    事务的传播行为可以由传播属性指定,Spring定义了7种类传播行为

    3、isolation:隔离事务级别

    • 事务的隔离性,多事务操作之间不会产生影响,不考虑隔离性会产生很多问题

    • 有三个读问题:脏读、不可重复读、虚读

    • 脏读:一个未提交事务读取到另一个未提交事务的数据

    • 不可重复读:一个未提交事务读取到另一个提交事务修改数据

    • 虚读:一个未提交事务读取到另一个提交事务添加数据

    设置事务隔离级别,解决上述出现的问题

    4、timeout:超时时间

    • 事务需要在一定实际内进行提交,若不提交则进行回滚
    • 默认值时-1,设置时间以秒为单位进行计算

    5、readOnly:是否只读

    • 读:查询操作,写:添加修改删除操作
    • readOnly,默认值时false,表示可以查询、添加修改删除操作
    • 设置readOnly为true,只能查询

    6、rollbackFor:回滚

    • 设置出现哪些异常进行事务回滚

    7、noRollbackFor:回滚

    • 设置出现哪些异常不进行事务回滚
    XML声明事务管理

    1、在spring配置文件中进行配置

    • 第一步:配置事务管理器
    • 第二步:配置通知
    • 第三步:配置切入点和切面
        <!--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="accountMoney" propagation="REQUIRED"/>
                <!--<tx:method name="account*/"></tx:method>-->
            </tx:attributes>
        </tx:advice>
    
        <!--3、配置切入点和切面-->
        <aop:config>
            <!--配置切入点-->
            <aop:pointcut id="pt" expression="execution(* com.yingzi.spring5.service.UserService.*(..))"/>
            <!--配置切面-->
            <aop:advisor advice-ref="txadvice" pointcut-ref="pt"></aop:advisor>
        </aop:config>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    完全注解声明式事务管理

    1、创建配置类,使用配置类替代xml配置文件

    @Configuration //配置类
    @EnableTransactionManagement//开启事务
    @ComponentScan(basePackages = "com.yingzi")//组件扫描
    public class TxConfig {
    
        //创建数据库连接池
        @Bean
        public DruidDataSource getDruidDataSource() {
            DruidDataSource dataSource = new DruidDataSource();
            dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
            dataSource.setUrl("jdbc:mysql:///user_db");
            dataSource.setUsername("root");
            dataSource.setPassword("000000");
            return dataSource;
        }
    
        //创建JdbcTemplate对象
        @Bean
        public JdbcTemplate getJdbcTemplate(DataSource dataSource) {
            //到IOC容器中根据类型找到dataSource
            JdbcTemplate jdbcTemplate = new JdbcTemplate();
            //注入dataSource
            jdbcTemplate.setDataSource((dataSource));
            return jdbcTemplate;
        }
    
        //创建事务管理器
        @Bean
        public DataSourceTransactionManager getDataSourceTransactionManager(DataSource dataSource) {
            DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
            transactionManager.setDataSource(dataSource);
            return transactionManager;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    Spring5框架新功能

    整个Spring5框架的代码基于java8,运行时兼容JDK9,许多不建议使用的类和方法在代码库中删除

    Spring5框架自带了通用的日志封装

    • Spring5已经移除Log4jConfigListener,官方建议使用Log4j2
    • Spring5框架整合Log4j2

    第一步,引入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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    Spring5框架核心容器支持@Nullable注解

    Nullable注解可以使用在方法、属性、参数上,表示这些返回可以为空

    • 注解使用在方法上,方法返回值可以为空

      @Nullable
      String getId()
      
      • 1
      • 2
    • 注解使用在方法参数里面,方法参数可以为空

          public <T> void registerBean(@Nullable String beanName, Class<T> beanClass, @Nullable Supplier<T> supplier, BeanDefinitionCustomizer... customizers) {
              this.reader.registerBean(beanClass, beanName, supplier, customizers);
          }
      
      • 1
      • 2
      • 3
    • 注解使用在属性上,属性值可以为空

      @Nullable
      private String bookName
      
      • 1
      • 2

    Spring5核心容器支持函数式风格GenericApplicationContext

    //函数式风格创建对象,交给spring进行管理
        @Test
        public void testAccount4() {
            //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.yingzi.spring5.test.User");
            User user = (User) context.getBean("user1");
            System.out.println(user);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    Spring5支持整合JUnit5

    整合JUnit4

    • 第一步 引入Spring相关针对测试依赖

    • 第二步 创建测试类,使用注解方式完成

      @RunWith(SpringJUnit4ClassRunner.class) //单元测试框架
      @ContextConfiguration("classpath:bean1.xml") //配置文件
      public class JTest4 {
      
          @Autowired
          private UserService userService;
      
          @Test
          public void test1() {
              userService.accountMoney();
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12

    Spring5整合JUnit5

    • 第一步 引入JUnit5的jar包

    • 第二步 创建测试类,使用注解完成

      @ExtendWith(SpringExtension.class) //单元测试框架
      @ContextConfiguration("classpath:bean1.xml") //配置文件
      public class JTest5 {
      
          @Autowired
          private UserService userService;
      
          @Test
          public void test1() {
              userService.accountMoney();
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
    • 使用一个复合主机替代上面两个注解,完成整合

    @SpringJUnitConfig(locations = "classpath:bean1.xml")
    public class JTest5 {
    
        @Autowired
        private UserService userService;
    
        @Test
        public void test1() {
            userService.accountMoney();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
  • 相关阅读:
    CSS水平垂直居中方案
    Conda 命令小表格
    MySQL---MySQL的安装以及SQL的分类
    什么是多线程环境下的伪共享(false sharing)?
    如何解决基因行业海量数据传输难题?镭速传输给出答案
    Sonar生成PDF错误Can‘t get Compute Engine task status.Retry..... HTTP error: 401
    超详细Redis入门教程二
    【Android -- 开发】中级工程师进阶
    怎样优雅地增删查改(六):按任意字段关键字查询
    代码随想录算法训练营第六十三天 |84.柱状图中最大的矩形
  • 原文地址:https://blog.csdn.net/mynameisgt/article/details/125616685