Spring框架

GA666666 2021-11-21 PM 9℃ 0条

Spring开源框架

(一)Spring简介

1.轻量化开源框架

2.解决企业应用开发的复杂性,降低难度

3.Spring的两个核心部分:IOC 和 Aop

1. IOC:控制反转

把创建对象的过程交给spring管理

2. Aop:面向切面

不修改源代码进行功能增强

3.Spring特点

(1)方便解耦,简化开发

(2)Aop编程支持

(3)方便程序的测试

(4)方便和其他框架整合

(5)方便进行事务操作

(6)降低API开发难度

(二)入门小案例

1.下载Spring资源文件

最新5.29大概80多mb,链接:

选 spring-5.2.9.RELEASE-dist.zip 这个文件,下载比较慢的话可以复制链接用迅雷下载,下载好解压:

2.选取需要的jar包

小案例需要四个基础的jar包

都可以在解压好的libs中找到,commons-logging需要自行下载

3.打开IDEA创建Java 项目

打开idea创建普通的项目,将上面5个jar包导入到项目并添加环境变量

创建一个简单的User类:

package com.bgu.edu;

public class User {
    public void add(){
        System.out.println("add-------");
    }
}

在src目录下,创建spring配置文件,new ---------> XML Configuration File -------> Spring config 起个名字叫bean1

<?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.bgu.edu.User"></bean>

</beans>

添加标签,按照图示 设置id和class的地址

4.创建测试类

新建pakage:test 在包内创建测试类TestSpring.class

package test;

import com.bgu.edu.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TeatSpring {
    @Test
    public void testAdd(){
        //加载Spring配置文件
        ApplicationContext context=
                 new ClassPathXmlApplicationContext("bean1.xml");
        User user  = context.getBean("user", User.class);
        //运行User的构造方法
        System.out.println(user);
        user.add();
    }
}

这里使用@Test会报错,点右面感叹号选第一个推荐方式,会自动导入:org.junit.Test 这个包,右键运行即可:

运行结果:
com.bgu.edu.User@27808f31
add-------

Process finished with exit code 0

(三)IOC

0.IOC 概念和原理

  1. 什么是IOC:控制反转,最常见的方式叫依赖注入。把创建对象和对象之间的调用过程交给Spring进行管理
  2. 使用IOC的目的:为了耦合度降低
  3. 做入门案例就是IOC实现

1.IOC 底层原理

  1. xml解析技术、工厂模式、反射

    class UserFactory {
        public static UserDao getDao(){
            String classVlaue = class属性值;//1.xml解析得到class
            Class clazz = Class.forName(classValue);//2.通过反射创建对象
            
            return (UserDao) clazz.newInstance();
        }
    }

2.IOC 接口(BeanFactory)

  1. IOC 思想基于 IOC容器底层就是对象工厂
  2. Spring 提供了IOC容器的实现方式(两个接口)

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

    特点:加载配置文件时不会创建对象,在获取对象(使用)才会创建对象 User user = context.getBean("user",User.class)

    (2)ApplicationContext:BeanFactory的子接口,提供更多更强大的接口。一般由开发人员使用

    特点:加载配置文件的时候就会把配置文件里的对象进行创建

3.IOC 操作Bean管理

  1. 什么是Bean 管理

    (0)Bean管理是指两个操作

    (1)Spring 创建对象

    (2)Spring 注入属性

4.IOC 操作Bean管理(基于xml)

  1. <bean id="user" class="com.bgu.edu.User"></bean>

    在Spring配置文件中,使用bean标签,标签里面添加对应属性,就可以实现对象创建

    (1)bean 标签里有很多属性

    • id属性:唯一标识
    • class属性:类全路径(包类路径)
    • name属性:与id类似,name可以使用特殊字符,早期为strues1提供

    (2)创建对象时,默认执行无参构造方法

  2. 基于xml方式注入属性

    • DI:依赖注入,就是注入属性

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

      首先,创建一个对象

      package com.bgu.edu;
      /**
       * 演示使用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;
          }
      }

      然后配置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"
             xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
      
          <!--配置Book对象-->
          <bean id="book" class="com.bgu.edu.Book">
              <!--使用property完成属性注入
                  name:类里的属性名称
                  value:向属性注入的值
              -->
              <property name="bname" value="已经近"></property>
              <property name="bauthor" value="哈哈哈"></property>
          </bean>
      </beans>

      第二种方式:有参构造方法进行注入

      首先,创建一个对象

      package com.bgu.edu;
      
      /**
       * 使用有参数方法构造注入
       */
      public class Orders {
          //属性
          private String oname;
          private String address;
          //有参构造方法
          public Orders(String oname, String address) {
              this.oname = oname;
              this.address = address;
          }
      
          @Override
          public String toString() {
              return "Orders{" +
                      "oname='" + oname + '\'' +
                      ", address='" + address + '\'' +
                      '}';
          }
      }
      

      然后配置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"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
 
     <bean id="orders" class="com.bgu.edu.Orders">
         <constructor-arg name="oname" value="电脑"/>
         <constructor-arg name="address" value="中国"/>
     </bean>
 </beans>
 ```

 spring配置简化:使用p名称空间注入

 ```xml
 xmlns:p = "http://www.springframework.org/schema/p"
 ```

 ```xml
     <bean id="orders" class="com.bgu.edu.Orders" p:bname="高等数学" p:bauthor="高同学"> </bean>
 ```

 

5.IOC 操作Bean管理(基于注入其他属性)

  1. 字面量

    • null值
    <property name="bname" >
    <null/>
    </property>
    • 属性值包含特殊夫符号(转义 < >)
    <property name="bname" >
        <value>
            <![CDATA[这里写带特殊的字符]]>
        </value>
    </property>

2.注入属性 - 外部bean

  • <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
            <!-- service和到对象的创建-->
        <bean id="userService" class="server.UserService">
            <!--注入userDao对象
                name属性,类里面属性名称
                ref属性:创建userDao对象bean标签的id值
            -->
            <property name="userDao" ref="userDaoImpl"></property>
        </bean>
            <!-- 注意 UserDao是接口,这里要写接口的实现类 也就是UserDaoImpl -->
        <bean id="userDaoImpl" class="dao.UserDaoImpl"></bean>
    </beans>

    ​ 3.注入属性 - 内部bean和级联赋值

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    
      <!--内部 Bean-->
      <bean id="emp" class="bean.Emp">
       <property name="ename" value="李逵"></property>
       <property name="gender" value=" 男"></property>
       <property name="dept" >
           <bean id="dept" class="bean.Dept">
               <property name="dname" value="行政部"></property>
           </bean>
       </property>
    </bean>




###         6.IOC 操作Bean管理(xml注入集合属性)

1. 注入数组类型属性

2. 注入List集合类型属性

3. 注入Map集合类型属性

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"

      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

   <bean name="stu" class="edu.Stu">
       <property name="courses">
           <array>
               <value>java</value>
               <value>数据库</value>
           </array>
       </property>
       <property name="list" >

           <list>
               <value>张三</value>
               <value>小三</value>
           </list>
       </property>
       <property name="maps" >
           <map>
               <entry key="JAVA" value="java"/>
               <entry key="PHP" value="php"/>
           </map>
       </property>
       <property name="sets" >

           <set>
               <value>MySQL</value>
               <value>Redis</value>
           </set>
       </property>
   </bean>


4. 在集合里面设置对象

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"

      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

   <bean name="stu" class="edu.Stu">
       <property name="courseList">
           <list>
               <ref bean="course1"></ref>
               <ref bean="course2"></ref>
           </list>
       </property>

   </bean>
   <bean id="course1" class="edu.Course">
       <property name="cname" value="Spring 5"></property>
   </bean>
   <bean id="course2" class="edu.Course">
       <property name="cname" value="MyBites"></property>
   </bean>




5. 把集合注入提取到公共部分

- 在spring配置文件添加命名空间
 <?xml version="1.0" encoding="UTF-8"?>
 <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:util = "http://www.springframework.org/schema/util"
        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/util  http://www.springframework.org/schema/util/spring-util.xsd">
 
    <util:list id="booklist">
        <value>已经经</value>
        <value>是大家还是</value>
        <value>以哦他</value>
    </util:list>
 
     <bean id="book" class="edu.Book">
         <property name="list" ref="booklist"></property>
     </bean>
 </beans>
 ```

 

7.IOC 操作 Bean 管理(FactoryBean)

  1. Spring 有两种 bean ,一种普通bean,一种factorybean
  2. 普通bean:在配置文件中定义的bean类型就是返回类型
  3. 工厂bean:在配置文件中定义的bean类型可以不是返回的bean类型

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

  1. 在spring里面,设置创建bean实例是单实例还是多实例
  2. 在spring里面,默认情况下是单实例对象
  3. 如何设置单实例还是多实例:scope
  4. scope是属性值:singleton(单实例)、prototype(多实例)
  5. singleton(单实例):加载spring时,就会创建多实例对象
  6. prototype(多实例):不是在加载spring创建对象,在调用getBean时才会创建的对象

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

  1. 生命周期:从对象创建和销毁的过程
  2. bean生命周期:

    • 通过构造器创建Bean实例(无参构造方法)
    • 为bean的属性设置属性值和对其他bean引用(调用set方法)
    • 调用bean的初始化方法(需要进行配置初始化的方法)
    • bean可以使用了
    • 当容器关闭时,调用bean的销毁方法(需要进行配置销毁方法)

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

  1. 什么是自动装配

    • 根据指定装配规则(属性名称或属性类型),Spring自动将匹配的属性值填入

      • 实现方式:bean标签属性:autowire,配置自动装配 autowire有两个属性:byName 根据属性名注入,注入值bean的id值和类属性名称一样 byType:根据属性类型注入
      <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
          <!--自动装配-->
          <bean id="emp" class="autowire.Emp" autowire="byName"></bean>
          <bean id="dept" class="autowire.Dept"></bean>
      </beans>

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

  1. 直接配置数据库信息

    • 配置德鲁伊连接池
    • 引入德鲁伊连接池

      <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.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=""></property>
          </bean>
      </beans>
  1. 引入外部属性文件配置数据库连接池

    • 创建外部属性文件,properties格式文件,写数据库信息
    prop.driverClassName = com.mysql.jdbc.Driver
    prop.url = jdbc:mysql://localhost:3306/userdb
    prop.username = root
    prop.password = 
    • 把外部 properties 属性文件引入到spring配置文件中

      • 引入context名称空间
      • 在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"
           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:property-placeholder location="classpath:jdbc.properties"/>
        <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
            <property name="driverClassName" value="${prop.driverClassName}"></property>
            <property name="url" value="${prop.url}"></property>
            <property name="username" value="${prop.username}"></property>
            <property name="password" value="${prop.password}"></property>
        </bean>
    </beans>

12.IOC 操作 Bean 管理(基于注解)

  1. 什么是注解

    • 代码里面特殊的格式,格式:@注解名称(属性名称=属性值,属性名称=属性值)
    • 使用注解 :注解的作用在类的上面,方法上面,属性上面
    • 使用注解目的:简化xml配置
  2. Spring针对Bean管理中创建对象提供注解

    • @Component
    • @Service
    • @Controller
    • @Repository

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

  3. 基于注解方式创建对象

    • 第一步引入依赖:spring-aop-5.2.9.RELEASE.jar
    • 第二步开启组件扫描:

      <?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.bgu.edu"></context:component-scan>
      
      </beans>
      • 第三步

        package com.bgu.edu;
        
        import org.springframework.stereotype.Component;
        
        //在注解里面value属性值可以省略不写
        //如果不写 value 默认值是类的名称的首字母小写
        //UserService----->userService
        
        @Component(value = "userService")
        public class UserService {
            public void add(){
                System.out.println("add-----");
            }
        }
  4. 基于注解方式实现属性注入

    • @AutoWired:根据属性类型进行自动装配

      第一步:把service和dao对象创建,在servic和dao里添加创建对象注解

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

      package com.bgu.edu;
      
      import com.bgu.edu.dao.UserDao;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.stereotype.Component;
      
      //在注解里面value属性值可以省略不写
      //如果不写 value 默认值是类的名称的首字母小写
      //UserService----->userService
      
      @Component(value = "userService")
      public class UserService {
          @Autowired
          private UserDao userDao;
      
          public void add(){
              System.out.println("add-----");
          }
      }
  • @Qualifier:根据属性名称进行注入

    这个 @Qualifier注解的使用,需要和上面的@AutoWired配合使用:一个接口可能有多个实现类,@AutoWired无法准确找到我们需要的实现类,通过 @Qualifier指定我们具体实现众多实现类的哪一个

    package com.bgu.edu.service;
    
    import com.bgu.edu.dao.UserDao;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.stereotype.Component;
    
    //在注解里面value属性值可以省略不写
    //如果不写 value 默认值是类的名称的首字母小写
    //UserService----->userService
    
    @Component(value = "userService")
    public class UserService {
        @Autowired
        @Qualifier(value = "userDaoImpl")
        private UserDao userDao;
    
        public void add(){
            System.out.println("Service_add");
            userDao.add();
        }
    }
  • @Resource:可以根据类型注入,可以根据名称注入

    package com.bgu.edu.service;
    
    import com.bgu.edu.dao.UserDao;
    import org.springframework.stereotype.Component;
    
    import javax.annotation.Resource;
    
    //在注解里面value属性值可以省略不写
    //如果不写 value 默认值是类的名称的首字母小写
    //UserService----->userService
    
    @Component(value = "userService")
    public class UserService {
    //    private UserDao userDao;
    
      //@Resource //根据类型注入
        @Resource(name = "userDaoImpl")//根据类名称注入
        private UserDao userDao;
    
        public void add(){
            System.out.println("Service_add");
            userDao.add();
        }
    }
    
  • @Value:注入普通数据类型属性

        @Value(value = "abc")
        private String name;

5.完全注解开发

  • ​ 创建配置类:替代xml配置文件、
  • ​ 编写测试类

     @Test
        public  void test2(){
            //加载配置类
            ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
            UserService userService = context.getBean("userService",UserService.class);
            userService.add();
        }

(四)AOP

0.AOP概念

  1. 什么是AOP?

    • AOP:面向切面编程
    • 利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑之间的耦合度降低,提高程序的可重用性,同时提高开发效率
    • 通俗描述:不通过修改源代码的方式,在主干功能里面添加功能

1.AOP底层原理

  1. AOP底层使用动态代理

    • 有两种情况的动态代理
    • 第一种情况有接口,使用JDK动态代理

      • 创建接口实现类的代理对象,实现功能增强
    • 第二种情况没有接口,使用CGLIB动态代理

      • 创建当前类的子类代理对象,实现功能增强

2.AOP(JDK动态代理)

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

    • java.lang.Object

      • java.lang.reflect.Proxy
    • 调用 newProxyInstans方法,方法有三个参数

      • 第一个参数:ClassLoader loder
      • 第二个参数:增强方法所在的类,这个类实现的接口(可以写多个)
      • 第三个参数:实现里面的接口 InvocationHandler,创建代理对象,写增强方法
  2. JDK动态代理

    • 创建接口,定义方法
    • 创建接口实现类,实现方法
    • 使用Proxy类,创建接口的代理对象

      package com.bgu.edu;
      
      import java.lang.reflect.Array;
      import java.lang.reflect.InvocationHandler;
      import java.lang.reflect.Method;
      import java.lang.reflect.Proxy;
      import java.util.Arrays;
      
      public class JDKProxy {
          public static void main(String[] args) {
              //创建接口实现类代理对象
              Class[] interfaces = {UserDao.class};
              UserDaoImlp userDao = new UserDaoImlp();
              UserDao dao = (UserDao) Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new UserDaoProxy(userDao));
              int result = dao.add(1,2);
              System.out.println(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;
          }
      }
      

3.AOP(术语)

  1. 连接点

    • 类里面的拿些方法能被增强,这个方法就叫连接点
  2. 切入点

    • 实际被真正增强的方法就是切入点
  3. 通知(增强)

    • 实际增强的逻辑代码部分就是通知(增强)
    • 有多种类型

      • 1.前置通知
      • 2.后置通知
      • 3.环绕通知
      • 4.异常通知
      • 5.最终通知 :finally
  4. 切面

    • 是动作
    • 把通知应用加到切入点的过程

4.AOP操作(准备)

  1. Spring框架中一般基于AspectJ 实现AOP操作

    • 什么是AspectJ并不是Spring的组成部分,他是一个独立的AOP框架,一般把AspectJ和Spring一起使用,进行AOP操作
  2. 基于AspectJ 实现AOP操作

    • 基于xml配置文件实现
    • 基于注解方式实现(使用)
  3. 在项目的工程里引入依赖AspectJ

    • spring-aspects-5.2.9.RELEASE.jar
    • com.springsource.net.sf.cglib-2.2.0.jar
    • com.springsource.org.aopalliance-1.0.0.jar
    • com.springsource.org.aspectj.weaver-1.6.4.RELEASE.jar
  4. 切入点的表达式

    • 切入点表达式的作用:知道对哪个类的哪个方法进行加强
    • 语法结构

      • execution( [权限修饰符] [返回类型] [类全路径] [方法名称]([参数列表]))
    • 举例1:

      • 对 com.bgu.edu.UserDao 类里面的add方法进行增强
      • execution(* com.bgu.edu.UserDao.add(..))
    • 举例2:对 com.bgu.edu.UserDao 类里面的所有方法进行增强

      • execution( com.bgu.edu.UserDao.(..))
    • 举例3:对 com.bgu.edu包 里面的所有类的所有方法进行增强

      • execution( com.bgu.edu.UserDao*.(..))

5.AOP操作(AspectJ注解)

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

    package com.bgu.edu.aopanno;
    //被增强的类
    public class User {
        public void add(){
            System.out.println("User_add");
        }
    }
    
  2. 创建增强类(编写增强逻辑)

    • 在增强类里面,创建方法,让不同的方法代表不同的通知类型

      package com.bgu.edu.aopanno;
      
      public class UserProxy {
      
          //前置通知
          public void before(){
              System.out.println("before.....");
          }
      }
  3. 进行通知配置

    • 在spring配置文件中,开启注解扫描
    • 使用注解创建两个对象
    • 增强的类上面添加注解:@Aspect

      package com.bgu.edu.aopanno;
      import org.aspectj.lang.annotation.Aspect;
      import org.springframework.stereotype.Component;
      
      @Component
      @Aspect
      public class UserProxy {
          //前置通知
          public void before(){
              System.out.println("before.....");
          }
      }
  • 在spring配置文件生成代理

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:context="http://www.springframework.org/schema/context"
           xmlns:aop="http://www.springframework.org/schema/aop"
           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
                               http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
        <!--开启注解扫描-->
        <context:component-scan base-package="com.bgu.edu.aopanno"></context:component-scan>
    
        <!--开启Aspect生成代理对象-->
        <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
    
    </beans>
  1. 配置不同类型的通知

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

      package com.bgu.edu.aopanno;
      
      import org.aspectj.lang.ProceedingJoinPoint;
      import org.aspectj.lang.annotation.*;
      import org.springframework.stereotype.Component;
      
      @Component
      @Aspect
      public class UserProxy {
          //前置通知
          //@Before注解表示作为前置通知
          @Before(value = "execution(* com.bgu.edu.aopanno.User.add(..))")
          public void before(){
              System.out.println("before.....");
          }
          //最终通知
          @After(value = "execution(* com.bgu.edu.aopanno.User.add(..))")
          public void afer(){
              System.out.println("after......");
          }
          //后置通知
          @AfterReturning(value = "execution(* com.bgu.edu.aopanno.User.add(..))")
          public void aferReturning(){
              System.out.println("AfterReturning......");
          }
          @AfterThrowing(value = "execution(* com.bgu.edu.aopanno.User.add(..))")
          public void aferThrowing(){
              System.out.println("AfterThrowing......");
          }
      
          @Around(value = "execution(* com.bgu.edu.aopanno.User.add(..))")
          public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
              System.out.println("环绕之前......");
              proceedingJoinPoint.proceed();
              System.out.println("环绕之后......");
          }
      
      }
      
    • TestAopanno测试调用

      package com.bgu.edu.test;
      
      import com.bgu.edu.aopanno.User;
      import org.junit.Test;
      import org.springframework.context.ApplicationContext;
      import org.springframework.context.support.ClassPathXmlApplicationContext;
      
      public class TestAop {
          @Test
          public void testAopanno(){
              ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
              User user = context.getBean("user", User.class);
              user.add();
          }
      }
  2. 相同切入点抽取

    package com.bgu.edu.aopanno;
    
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.*;
    import org.springframework.stereotype.Component;
    
    @Component
    @Aspect
    public class UserProxy {
    
        @Pointcut(value = "execution(* com.bgu.edu.aopanno.User.add(..))")
        public void pointdemo(){
    
        }
    
        //前置通知
        //@Before注解表示作为前置通知
        @Before(value = "pointdemo()")
        public void before(){
            System.out.println("before.....");
        }
        //最终通知
        @After(value = "pointdemo()")
        public void afer(){
            System.out.println("after......");
        }
        //后置通知
        @AfterReturning(value = "pointdemo()")
        public void aferReturning(){
            System.out.println("AfterReturning......");
        }
        @AfterThrowing(value = "pointdemo()")
        public void aferThrowing(){
            System.out.println("AfterThrowing......");
        }
    
        @Around(value = "pointdemo()")
        public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
            System.out.println("环绕之前......");
            proceedingJoinPoint.proceed();
            System.out.println("环绕之后......");
        }
    
    }
    
  3. 多个增强类可以设置优先级

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

      package com.bgu.edu.aopanno;
      
      import org.aspectj.lang.annotation.Aspect;
      import org.aspectj.lang.annotation.Before;
      import org.springframework.core.annotation.Order;
      import org.springframework.stereotype.Component;
      
      @Component
      @Aspect
      @Order(value = 1)
      public class PersonProxy {
          @Before(value = "execution(* com.bgu.edu.aopanno.User.add(..))")
          public void before(){
              System.out.println("PersonProxy_before.....");
          }
      }

(五) JDBCTemplate

0.什么是JdbcTemplate(概念理论)

  1. Spring框架对JDBC进行了封装,使用JdbcTemplate方便实现对数据库操作
  2. 准备工作

    • 在原来的基础上引入相关jar

    • 在spring配置中配置数据库连接池

      <!--配置德鲁伊数据库连接池-->
          <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=""></property>
          </bean>
    • 配置JdbcTemplate对象,注入

      <!--JdbcTeplate对象-->
          <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
              <!--注入DataSource-->
              <property name="dataSource" ref="dataSource"></property>
          </bean>
    • 创建service类,创建dao类,在dao注入JdbdTemplate对象

      • xml
      <!--开启组件注解扫描-->
          <context:component-scan base-package="com.bgu.edu"></context:component-scan>
      • Service
      package com.bgu.edu;
      
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.stereotype.Service;
      
      @Service
      public class Srevice{
          //注入dao
          @Autowired
          private Dao dao;
      }
      • Dao实现类
      package com.bgu.edu;
      
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.jdbc.core.JdbcTemplate;
      import org.springframework.stereotype.Repository;
      
      @Repository
      public class DaoImpl implements Dao{
      
          //注入jdbcTemplate
          @Autowired
          JdbcTemplate jdbcTemplate;
      
      }
      

1.JdbcTemplate 操作数据库(基本类)

  1. 对应数据库表创建实体类

  2. ​ 编写service和dao

    • 在dao里进行数据库的添加操作
    • 调用jdbcTemplate对象里面的 update 方法实现添加操作

       jdbcTemplate.update(String sql,Object ...args);
      • 有两个参数
      • 第一个参数:sql语句
      • 第二个参数值:可变参数,设置sql语句中的值
      package com.bgu.edu;
      
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.jdbc.core.JdbcTemplate;
      import org.springframework.stereotype.Repository;
      
      @Repository
      public class DaoImpl implements Dao{
      
          //注入jdbcTemplate
          @Autowired
          JdbcTemplate jdbcTemplate;
      
          //添加的方法
          @Override
          public void add(User user) {
              //创建sql语句
              String sql = "INSERT INTO t_user VALUES(?,?,?)";
              //调用方法实现
              Object[] args = {user.getUserId(),user.getUsername(),user.getUstatus()};
      //      int update = jdbcTemplate.update(sql,user.getUserId(),user.getUsername(),user.getUstatus());
              int update = jdbcTemplate.update(sql,args);
              System.out.println(update);
          }
      }
      
    • 测试类

      package com.bgu.edu;
      
      import org.junit.Test;
      import org.springframework.context.ApplicationContext;
      import org.springframework.context.support.ClassPathXmlApplicationContext;
      
      public class TestDao {
          @Test
          public void testDao(){
              ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
              UserService srevice = context.getBean("userService", UserService.class);
      
              User user = new User("001","张三","正常");
              srevice.addUser(user);
          }
      }
      

2.JdbcTemplate 操作数据库(增删改查)

  1. 增加

        //添加的方法
        @Override
        public void add(User user) {
            //创建sql语句
            String sql = "INSERT INTO t_user VALUES(?,?,?)";
            //调用方法实现
            Object[] args = {user.getUserId(),user.getUsername(),user.getUstatus()};
    //      int update = jdbcTemplate.update(sql,user.getUserId(),user.getUsername(),user.getUstatus());
            int update = jdbcTemplate.update(sql,args);
            System.out.println(update);
        }
  2. 删除

        //删除方法
        @Override
        public void delete(User user) {
            //DELETE FROM 表名称 WHERE 列名称 = 值,
            String sql = "DELETE FROM t_user WHERE user_id=?";
            int delete = jdbcTemplate.update(sql,user.getUserId());
            System.out.println(delete);
        }
  3. 查询返回某个值

    • 查询表里有多少条记录,返回的是某个值
    • 使用 JdbcTemplate 实现查询返回某个值的代码

      jdbcTemplate.queryForObject(String sql,Class<T> requiredType)
      • 有两个参数
      • 第一个参数:sql语句
      • 第二个参数:返回类型的Class
       @Override
          public int selectCount() {
              String sql = "SELECT COUNT(*) FROM t_user";
              //如果返回值为String,第二个参数就是 String.class
              Integer count = jdbcTemplate.queryForObject(sql,Integer.class);
              return count;
          }
  4. 查询返回对象

    • 场景:查询图书详情
    • JdbcTemplate 实现查询返回对象

       jdbcTemplate.queryForObject(String sql,RowMapper<T> rowMapper, Object ...args)
      • 有三个参数
      • 第一个参数:sql语句
      • 第二个参数:RowMapper,是接口,返回不同类型的数据,使用这个接口里面的实现类进行数据封装
      • 第三个参数:可变参数,设置sql语句中的值
      @Override
          public User findUserInfo(String id) {
              String sql = "SELECT * FROM t_user WHERE user_id=?";
              User user = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<User>(User.class), id);
              return user;
          }
  5. 查询返回集合

    • 场景:查询图书列表分页
    • 调用 JdbcTemplate 方法实现

      jdbcTemplate.query(String sql,Class<T> requiredType)
      • 有三个参数
      • 第一个参数:sql语句
      • 第二个参数:RowMapper,是接口,返回不同类型的数据,使用这个接口里面的实现类进行数据封装
      • 第三个参数:可变参数,设置sql语句中的值
       @Override
          public List<User> findAllUser() {
              String sql = "SELECT * FROM t_user";
              List<User> userList = jdbcTemplate.query(sql,new BeanPropertyRowMapper<User>(User.class));
              return userList;
          }
  6. 数据库批量操作

    • 批量操作:操作表里多条记录
    • JdbcTemplate 实现批量添加操作

      jdbcTemplate.batchUpdate(String sql,List<Object[]> batchArgs)
      • 两个参数
      • 第一个参数:sql语句
      • 第二个参数:List数组,添加多条记录数据
      @Override
          public void batchAdd(List<Object[]> batchArgs) {
              String sql = "INSERT INTO t_user VALUES(?,?,?)";
              int[] ints =  jdbcTemplate.batchUpdate(sql,batchArgs);
              System.out.println(Arrays.toString(ints));
          }
      • 测试方法:
      List<Object[]> batchArgs = new ArrayList<>();
              Object[] o1 = {"8","java","正常"};
              Object[] o2 = {"9","mysql","异常"};
              Object[] o3 = {"10","php","正常"};
              batchArgs.add(o1);
              batchArgs.add(o2);
              batchArgs.add(o3);
              userService.batchAdd(batchArgs);

(六)事务操作

0.事务概念

1.事务操作(搭建环境)

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

  2. 创建service,搭建dao ,完成对象创建和注入

    • service注入dao,dao注入jdbcTemplate,在jdbcTemplate注入DataSource
    • <beans xmlns="http://www.springframework.org/schema/beans"
             xmlns:context="http://www.springframework.org/schema/context"
             xmlns:aop="http://www.springframework.org/schema/aop"
             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
                                 http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
      
      <context:component-scan base-package="com.bgu.edu"></context:component-scan>
          <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=""></property>
          </bean>
 
     <!--JdbcTeplate对象-->
     <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
         <!--注入DataSource-->
         <property name="dataSource" ref="dataSource"></property>
     </bean>
 </beans>
 ```

 
  • //DAO类
    @Repository
    public interface Dao {
        public void add();
        public void reduce();
    }
  • //Dao实现类
    @Repository
    public class DaoImpl implements Dao{
        @Autowired
        private JdbcTemplate jdbcTemplate;
    
        public void add() {
            String sql = "UPDATE t_account SET money = money-? WHERE username=?";
            jdbcTemplate.update(sql,100,"lucy");
        }
    
        public void reduce() {
            String sql = "UPDATE t_account SET money = money+? WHERE username=?";
            jdbcTemplate.update(sql,100,"mary");
        }
    }
  • //Service类
    @Service
    public class DaoService {
        @Autowired
        private Dao dao;
        //转账操作
        public void acountmoney(){
            dao.reduce();
            dao.add();
        }
    }
  • public class TestDao {
        @Test
        public void money(){
            ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
            DaoService daoService = context.getBean("daoService",DaoService.class);
            daoService.acountmoney();
        }
    }
  • 上面的转账代码正常执行无问题,倒是如果在执行过程中出现异常
  1. 事务操作基本

     public void acountmoney(){
            try{
                
            //开启事务
    
            //进行业务操作
                dao.reduce();
                dao.add();
            //模拟异常
            int a = 0/100;
    
            //没有异常,提交事务
            }catch (Exception e){
                //出现异常,事务回滚
            }
        }

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

  1. 事务添加到JavaEE的三成结构里的Service层(业务逻辑层)
  2. 在Spring进行事务管理操作

    • 有两种方式,编程式事务管理和声明式事务管理(使用)
  3. 声明式事务管理

    • 基于注解方式
    • 基于xml配置文件
  4. 在Spring进行声明式事务管理,底层使用AOP管理
  5. Spring 事务管理API

    • 提供一个接口,代表事务管理器,这个接口针对不同框架

3.事务操作(基于XML)

  1. 在配置文件中创建事务管理器

    <!--创建事务管理器-->
        <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <property name="dataSource" ref="dataSource"></property>
        </bean>
  2. 开启事务注解

    • 引入第三方命名空间

      xmlns:tx="http://www.springframework.org/schema/tx"
      
      http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
    • 开启事务注解

      <!--开启事务注解-->
          <tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
  3. 在Service类上面或方法上面添加注解

    • @Transactional,这个注解既可以添加到类上面,也可以添加到方法上面
    • 如果把注解添加到类上面,这个类里面的所有方法都添加了事务
    • 如果把注解添加到方法上面,为这个方法添加了事务

4.事务操作(声明式事务管理参数管理)

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

标签: none

非特殊说明,本博所有文章均为博主原创。

评论啦~