[TOC]


Sping框架的概述

基本概述

    • javaSpring是轻量级的开源的JavbaEE框架

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

    • Spring有两大核心部分:

      1. IOC:控制反转,把创建对象交给Spirng进行管理
      2. Aop:面向切面,不修改源代码的情况下进行功能的增强
    • 方便耦合,简化开发
    • Aop编程支持
    • 方便程序测试
    • 方便和其他框架进行整合
    • 降低API开发难度

spring认识

通过spring创建对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class test1 {
@Test
public void test(){
// 加载spring配置文件
ApplicationContext context =
new ClassPathXmlApplicationContext("springTest1//bean1.xml");

//创建对象
User user = context.getBean("user",User.class);
System.out.println(user);
user.test();
}

}
  1. 创建spring的配置文件(床创建类的xml文件):

    • ```xml
      1
      2
      3
      4
      5
      6

      2. 将spring的配置文件引入java文件

      - ```java
      ApplicationContext context =
      new ClassPathXmlApplicationContext("springTest1//bean1.xml");
  1. 类的创建

    • ```java User user = context.getBean("user",User.class);
      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



      ### IOC模块

      - [ ] IOC底层原理
      - [ ] IOC接口(BeanFactory)
      - [ ] IOC操作(基于XML / 注解)

      #### 概念和原理

      - [ ] 什么是IOC
      - 控制反转,把对象的创建和对象之间的调用过程,交给Sring进行处理
      - 使用IOC的目的,为了耦合度的降低
      - [ ] IOC的底层原理
      - xml解析,工厂模式,java反射



      #### IOC接口

      - [ ] BeanFactory:
      - IOC容器实现的基本接口,不提供给开发人员使用
      - 在加载配置文件时不会创建对象
      - [ ] ApplicationContext:
      - BeanFactory接口的子接口,提供更强大的功能
      - 在加载配置文件时就会创建对象
      - 两个基本的实现类:
      1. ClassPathXmlApplicationContext():相对路径(使用ClassLoader加载)
      2. FileSystemPathXmlApplicationContext():绝对路径(使用InputStream加载)





      #### IOC操作Bean管理操作
      ##### 什么是Bean管理

      - Bean管理指的是两个操作:
      1. Spring创建对象
      2. Spring注入属性

      ##### 基于xml方式

      - [ ] 基于xml的对象构造:



      ```xml
      <bean id="user" class="springTest1.User"></bean> <!-- 默认调用无参构造函数 -->
- 在sprng的配置文件中使用bean标签,标签里添加对应的属性,就可以实现对象的创建
- 在bean中有很多属性,介绍常用的属性:
  1. id属性:唯一标识
  2. class属性:类的全路径<package-class>
  3. name属性:可以完成和id属性相同的作用,和id属性唯一的区别为在name属性中可以添加特殊符号,而在id属性中不可以添加特殊符号
- 默认执行无参构造方法
    1. DI:依赖注入,注入属性

      • 第一种注入方式:使用Set方法进行注入

        1
        2
        3
        4
        <bean id="book" class="springTest1.Book">  <!-- 先有对象才有属性 -->
        <property name="bAuthor" value="YCH"></property>
        <property name="bName" value="diao"></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
        public class Book {

        public Book(){

        }

        private String bName;
        private String bAuthor;

        public void setbName(String bName) {
        this.bName = bName;
        }

        public void setbAuthor(String bAuthor) {
        this.bAuthor = bAuthor;
        }

        public String getbName() {
        return bName;
        }

        public String getbAuthor() {
        return bAuthor;
        }
        }

        1
        2
        3
        4
        5
        6
        @Test
        public void test2(){
        ApplicationContext context = new ClassPathXmlApplicationContext("springTest1//bean1.xml");
        Book book = context.getBean("book",Book.class);
        System.out.println(book.getbAuthor() + " " + book.getbName());
        }
      • 第二中注入方式:使用有参构造方法进行注入

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      <!-- 属性注入 (有参构造方式方式)  -->
      <bean id="book1" class="springTest1.Book">
      <constructor-arg name="bAuthor" value="ych"></constructor-arg>
      <constructor-arg name="bName" value="ddd"></constructor-arg>
      <!--
      <constructor-arg index="0" value="ddd"></constructor-arg> 也可以进行属性注入,此时index为有参构造的顺序

      -->

      </bean>
      1
      2
      3
      4
      5
      6
      7
      @Test
      public void test3(){
      ApplicationContext context =
      new ClassPathXmlApplicationContext("springTest1//bean1.xml");
      Book book = context.getBean("book1",Book.class);
      System.out.println(book.getbAuthor());
      }
      • Tips:若在一个xml配置文件中既是用了Set方式又使用了有参构造方式,配置文件的id需要为不同的ID
    2. P名称空间注入:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      <!-- 添加xml相关约束(p约束) -->
      <beans xmlns="http://www.springframework.org/schema/beans"

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

      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:util="http://www.springframework.org/schema/util"
      xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util https://www.springframework.org/schema/util/spring-util.xsd">
      <!-- 配置对象的创建 -->
      <bean id="user" class="springTest1.User"></bean>
      1
      2
      3
      4
      5
      6
      7
      8
      @Test
      public void test4(){
      ApplicationContext context =
      new ClassPathXmlApplicationContext("springTest1//bean1.xml");
      Book book = context.getBean("book2",Book.class);
      System.out.println(book.getbAuthor());

      }

    3. 基于xml的其他类型属性注入

      • 属性值为空值:

        1
        2
        3
        4
        5
        <bean id="book3" class="springTest1.Book">
        <property name="bName">
        <null/>
        </property>
        </bean>
      • 属性值中有特殊符号:

        1. 使用转义符:&gt,&lt

        2. 使用CDATA

          1
          2
          3
          4
          5
          <bean id="book4" class="springTest1.Book">
          <property name="bName" >
          <value><![CDATA[<<北京>>]]></value>
          </property>
          </bean>
      • 外部注入(属性为类的注入 / 外部bean):

        1
        2
        3
        4
        5
        6
               
        <bean id="service" class="springTest2.UserService.Service">
        <property name="user" ref="user"></property>
        </bean>

        <bean id="user" class="springTest2.UserDao.UserDaoImp"></bean>
        1
        2
        3
        4
        5
        6
        7
        8
        @Test
        public void test1(){
        ApplicationContext context =
        new ClassPathXmlApplicationContext("springTest2//inject.xml");
        UserDao user= context.getBean("service", Service.class).getUser();
        System.out.println(user);

        }
      • 内部注入:

        1
        2
        3
        4
        5
        6
        7
        8
        <bean id="emp" class="springTest2.Emp.Emp">
        <property name="name" value="ych"></property>
        <property name="dept">
        <bean id="dept" class="springTest2.Dept.Dept">
        <property name="name" value="666"></property>
        </bean>

        </property>
        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
        public class Dept {
        private String name;

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

        public String getName() {
        return name;
        }
        }

        public class Emp {
        Dept dept;
        String name;


        public void setDept(Dept dept) {
        this.dept = dept;
        }

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

        public Dept getDept() {
        return dept;
        }
        }


      • 级联注入:

        1. 第一种方式和外部注入相似

        2. 给类属性的属性赋值:

          • 前提:需要对属性的主类设置相应属性的get方法
          1
          2
          3
          4
          5
          <bean id="emp2" class="springTest2.Emp.Emp">
          <property name="dept" ref="dept"></property>
          <property name="dept.name" value="cs"></property>
          </bean>
          <bean id="dept" class="springTest2.Dept.Dept"></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
           @Test
          public void test3(){
          ApplicationContext context =
          new ClassPathXmlApplicationContext("springTest2//inject.xml");
          Emp emp = context.getBean("emp2",Emp.class);
          System.out.println(emp.getDept().getName());
          }


          public class Emp {
          Dept dept;
          String name;


          public void setDept(Dept dept) {
          this.dept = dept;
          }

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

          public Dept getDept() {
          return dept;
          }
          }

      • 集合注入:

        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 id="stu" class="springTest3.Stu">
        <property name="list">
        <list>
        <ref bean="course1"></ref>
        <ref bean="course2"></ref>
        </list>
        </property>
        <property name="set">
        <set>
        <value>666</value>
        <value>555</value>

        </set>

        </property>

        <property name="map">
        <map>
        <entry key="java" value="spring"></entry>
        <entry key="math" value="666"></entry>
        </map>
        </property>
        </bean>

        <bean id="course1" class="springTest3.Course">
        <property name="name" value="ml"></property>
        </bean>
        <bean id="course2" class="springTest3.Course">
        <property name="name" value="db"></property>
        </bean>
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        @Test
        public void test1(){
        ApplicationContext context =
        new ClassPathXmlApplicationContext("springTest3//inject.xml");
        Stu stu = context.getBean("stu",Stu.class);
        for(Course c : stu.list)
        System.out.println(c.name);

        for(String str : stu.map.keySet())
        System.out.println(str + " " + stu.map.get(str));
        }

        Attention:

        • 在类内使用collections的子类时,只能使用最抽象的类(list,set,map)只有这些类在xml有对应的标签

        • 在xml文件中使用对应的标签(list,set,map(entry))

        • 对于一般的字符串型value使用value标签即可进行注入

        • 对于对象型value使用ref,利用类似外部注入的方式进行注入

      • 将类(这里以list为例)公有化:

        1
        2
        3
        4
        xmlns:util="http://www.springframework.org/schema/util"
        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">

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        <util:list id="List">
        <value>666</value>
        <value>777</value>
        <value>888</value>

        </util:list>

        <bean id="collect" class="springTest3.ListInjecter">
        <property name="list" ref="List"></property>
        </bean>

        Attention:

        • 需要导入util对应的包:

          xmlns:util="http://www.springframework.org/schema/util"

          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的标签内,直接添加value(若为String类型的数据)添加id属性

        • 若为对象类的value则利用ref标签引入

        • 在property的标签内,使用ref将公有化的标签的id进行引入

      • 工厂Bean:

        • 使创建的工厂类实现FactoryBean接口(not BeanFactoy)

        • 实现接口内的函数

        • 在getObject的函数内返回要实现的类对象

          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          14
          15
          16
          17
          18
          19
          public class UserFactory implements FactoryBean<User> {
          @Override
          public User getObject() throws Exception {
          return new User();
          }

          @Override
          public Class<?> getObjectType() {
          return null;
          }

          @Override
          public boolean isSingleton() {
          return false;
          }
          }
          public class User {
          }

          1
          <bean id="user" class="springTest4.UserFactory"></bean>
      • bean的默认单例性:

        在spring中bean的管理默认为单例模式,即在任何位置使用的bean为同一个bean

        对于bean的单例性的调节:

        • 在xml的配置文件内进行调节
        1
        2
        3
        <bean id="user" class="springTest4.UserFactory" scope="singleton"></bean> <!-- 默认单例 -->
        <bean id="user" class="springTest4.UserFactory" scope="prototype"></bean> <!-- 设置多例 -->

        • singleton和prototype的区别:
          • 对于默认scope或者指定singleton为在加载xml配置文件时就创建对象
          • 对于指定prototype为在调用getBean函数时才创建对象
      • bean的生命周期

          1. 通过构造器创建bean实例(无参构造)

          2. 为bean的属性设置值和对其他bean的引用(调用set方法)

          3. 调用bean的初始化方法(需要配置初始化方法)

          4. bean的使用

          5. 当关闭容器时,需要对bean进行销毁(需要配置销毁方法)

            演示代码:

            1
            2
            3
            4
            <bean id="order" class="springTest5.Order" init-method="initMethod" destroy- method="destroyMethod">
            <property name="name" value="ych"></property>
            </bean>

            1
            2
            3
            4
            5
            6
            7
            8
            9
            10
            11
            12
            13
            14
            15
            public class Order {
            private String name;

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

            private void initMethod(){
            System.out.println("order has createn!");
            }

            private void destroyMethod(){
            System.out.println("order has destroied!");
            }
            }
            1
            2
            3
            4
            5
            6
            7
            8
            9
            10
            @Test
            public void test(){
            ApplicationContext context =
            new ClassPathXmlApplicationContext("springTest5//inject.xml");
            Order order = context.getBean("order",Order.class);
            System.out.println("using!");

            // 销毁创建的bean
            ((ClassPathXmlApplicationContext)context).close(); //只有ApplicationContext的实现类有close方法
            }

            Attention:

            • 当在单例模式下可以用spring进行销毁
            • 当在多例模式下不可用spring进行销毁
          • 声明一个实现了BeanPostProcessor的类,并添加值配置文件

          • 在同一个配置文件中的所有bean文件均可调用后置处理器方法:

            1
            2
            3
            4
            5
            6
            7
            8
            9
            10
            11
            12
            13
            14
            15
            16
            public class BeanPostPro implements BeanPostProcessor {
            @Override
            public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
            // 在构造对象之前调用
            System.out.println("before construct!");
            return bean;
            }

            @Override
            public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {

            //在构造对象之后调用
            System.out.println("after construct!");
            return bean;
            }
            }
            1
            2
            3
            4
            5
            6
            <bean id="order" class="springTest5.Order" init-method="initMethod" destroy-method="destroyMethod" scope="singleton">
            <property name="name" value="ych"></property>
            </bean>


            <bean id="construct" class="springTest5.BeanPostPro"></bean>
          • byName:需要bean的ID和待构造的Bean的属性名相同
          • byType:只能满足“一对一”类型的自动装配
        • 1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          14
          15
          16
          17
          18
          19
          20
          21
          22
          23
          <!-- 引入命名空间 -->
          <?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="jdbc.properties"></context:property-placeholder>

          <!-- 进行属性注入 -->
          <bean id="jdbc" 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>
          • 引入命名空间(context)
          • 引入配置文件
          • 进行属性注入
基于注解方式
    1. @Component
    2. @Service
    3. @Controller
    4. @Respository

    ​ * 这四个注解的功能是一样的,都可以用来创建对象

    1. 引入aop的jar包,注解的使用需要aop,jar的解释

    2. 在xml中声明需要扫描注解的类(开启组件扫描):

      • 若需要多个类的解决方法:
        1. base-package参数后的类用逗号隔开
        2. 若这多个类在统一目录下,将其父目录加载到base-package中
    3. 在指定类的上方添加注解(Component,Conyroller,Service,Respository之一):

      • 若不添加value属性,则默认value为类名,且类的的一个字母小写,否则为指定的value值
    4. 在创建bean对象时和使用xml创建方法相同

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      <?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="springTest7"></context:component-scan>

      </beans>
      1
      2
      3
      4
      5
      6
      @Component(value = "user")
      public class User {
      public void start(){
      System.out.println("hello world!");
      }
      }
      1
      2
      3
      4
      5
      6
      7
      @Test
      public void test(){
      ApplicationContext context =
      new ClassPathXmlApplicationContext("springTest7//scan.xml");
      User user = context.getBean("user",User.class);
      user.start();
      }
    • 默认filter:对指定文件中的所有关键词注解进行扫描

    • 指定filter:仅对指定的filter进行扫描 / 不扫描:

      1
      2
      3
      4
      5
      6
      7
      8
         <!-- 指定扫描 -->
      <context:component-scan base-package="springTest7">
      <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
      </context:component-scan>
      <!-- 指定不扫描 -->
      <context:component-scan base-package="springTest7" use-default-filters="false">
      <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
      </context:component-scan>
      * **当为指定扫描时,需要将默认扫描(use-default-filters)改为false**
      * **当为指定不扫描时,无需设置**
      1. @AutoWire:根据属性的类型进行自动注入
      2. @Qualifier:根据属性的名称进行注入
      3. @Resource:既可以根据类型注入也可以根据名称进行注入
      4. @Value:普通类型的注入
      • 按照类型进行注入,直接在指定属性上添加该注解即可(只能当指定的类型只存在一个时,当存在多个候选的类型时不能使用该方法进行属性注入)
      • 按照名称进行注入

      • 使用Qualifier时必须在其上添加AutoWire注解,即两个注解同时使用

        1
        2
        3
        @Autowired  // 必须先添加AutoWire注解,若无该注解则无法使用Qualifier
        @Qualifier(value = "user")
        private UserDao user;
      • 既可以根据类型进行注入,也可以根据指定的名称进行注入。
      • 不是Spring包中的功能,是javax中的annoation的
      • Spring不推荐
      • 注入普通类型(非特殊对象类注入)
    • 完全使用注解进行开发,完全不使用xml

    • 步骤:

      1. 创建配置类并添加配置注解

      2. 加载配置类

      3. 创建bean对象

        1
        2
        3
        4
        5
        6
        // 注解类
        @Configuration
        @ComponentScan(basePackages = {"springTest9"})
        public class Config {
        }

        1
        2
        3
        4
        5
        6
        7
        8
        @Repository
        public class User implements UserDao{
        @Override
        public void show() {
        System.out.println("666");
        }
        }

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        @Service
        public class UserService {

        @Autowired
        private UserDao user;

        public void show(){
        user.show();
        System.out.println("777");
        }
        }
        1
        2
        3
        4
        5
        6
        7
        8
               
        @Test
        public void test(){
        ApplicationContext context =
        new AnnotationConfigApplicationContext(Config.class); // 此处改为Annotation的子实现类
        UserService user = context.getBean("userService",UserService.class);
        user.show();
        }

AOP模块

AOP基本概念

    • 两种情况的动态代理:
      1. 有接口的情况,使用JDK的动态代理
      2. 无接口的情况,使用CGLIB的动态代理
    • 连接点:

      类中哪些方法可以被增强,哪些方法就称为连接点(候选方法)

    • 切入点

      类内实际被增强的方法称为切入点(实际增强方法)

    • 通知(增强)

      1. 实际增强的逻辑部分被称为通知(增强)
      2. 通知有很多类型:
        • 前置通知
        • 后置通知
        • 环绕通知
        • 异常通知(exception)
        • 最终通知(finally)
    • 切面

      把通知应用到切入点的过程称为切面

JDK动态代理

##### Class Proxy

    • static Obcejct newProxyInstance(ClassLoader loader,类<?>[] interfaces ,InvocaionHandler h):

      parameters:

      1. loader:类加载器
      2. interfaces:增强方法所在的类,这个类实现的接口,该接口可以为多个接口
      3. h(InvocationHandler):实现Invocatiion的接口,创建代理的对象,实现对象增强的部分
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      public class JDKProxy {
      public static void main(String[] args) {
      Class []interfaces = {UserDao.class};

      UserDao user = new UserDaoImpl();

      UserDao user1 = (UserDao) Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new InvocationHandler() {
      private Object obj = user;

      public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
      System.out.println("hello");
      Object res = method.invoke(obj,args);
      System.out.println("world");
      return new Integer(6);

      }
      });

      System.out.println(user1.intInter(1,2));

      }
      }

AOP操作(准备)
    • 什么是AspectJ:

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

    • 基于AspectJ实现AOP操作

    • 切入点表达式的作用:知到对类内的哪个方法进行增强

    • 语法结构:

      execution(【权限修饰符】【返回类型】【类全路径】【方法名称】(【参数列表】))

    • 举例说明:

      说明:

      • *代表所有的权限
      • 返回类型可以省略
      • .*代表其中的所有
      • 参数列表用..进行代替
      1. 对指定类的指定方法做增强:

        excution(* spirngTest8.User,add(..))

      2. 对指定类的所有方法做增强:

        excution(* sprintTest8.User.*(..))

      3. 对指定包的所有类的所有方法做增强:

        excution(* springTest8..(..))

基于注解的AspectJ的AOP操作(推荐使用方法)
  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    <?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="sprintTest12"></context:component-scan>
    <aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>

    </beans>
  • 1
    2
    3
    4
    5
    6
    7

    @Configuration
    @ComponentScan(basePackageClasses = {Order.class, OrderPorxy.class})
    @EnableAspectJAutoProxy(proxyTargetClass = true) // 进行AOP配置
    public class Config {
    }

  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    @Component
    @Aspect //声明为AOP切口代理
    public class OrderProxy {

    @Before(value = "execution(* sprintTest12.Order.add(..))")
    void before(){
    System.out.println("world");
    }
    }
  • 在进行aop的引入时,需要将proxy-target-class声明为TRUE

    <tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/>   注意:proxy-target-class属性值决定是基于接口的还是基于类的代理被创建。如果proxy-target-class 属性值被设置为false,那么基于类的代理将起作用(这时需要cglib库)。如果proxy-target-class属值被设置为true,那么标准的JDK 基于接口的代理将起作用。

    即使你未声明 proxy-target-class="true" ,但运行类没有继承接口,spring也会自动使用CGLIB代理。

    高版本spring自动根据运行类选择 JDK 或 CGLIB 代理

  • 无异常情况:

    ​ around before..

    ​ before ​ Method ​ around after ​ after.. ​ after returning..

    有异常情况:

    ​ around before..

    ​ before ​ after.. ​ throwing

    • @before 前置通知
    • @after 最终通知
    • @afterReturning 后置通知
    • @around 环绕通知
    • @afterThrowing 异常通知
    • 对相同的execution进行抽取,并合并使用

    • 方法:

      1. 构建切入点函数

      2. 填充

        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
        	@Pointcut(value = "execution(* springTest13.Order.show(..))") // 构切入点函数
        void pointCutDemo(){}

        // 利用切入点函数进行填充

        @Before(value = "pointCutDemo()")
        void before(){
        System.out.println("before");
        }


        @After(value = "pointCutDemo()")
        void after(){
        System.out.println("after..");
        }

        @AfterReturning(value = "pointCutDemo()")
        void afterReturning(){
        System.out.println("after returning..");
        }

        @Around(value = "pointCutDemo()")
        void round(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("around before..");
        proceedingJoinPoint.proceed();
        System.out.println("around after");
        }

        @AfterThrowing(value = "pointCutDemo()")
        void afterThrow(){
        System.out.println("throwing");
        }

    • 若value的值越小则优先级越高
  • 1
    2
    3
    4
    5
    6
    7
    8


    @Configuration
    @ComponentScan(basePackageClasses = {Order.class, OrderPorxy.class})
    @EnableAspectJAutoProxy(proxyTargetClass = true)
    public class Config {
    }

基于xml文件的AspectJ的配置方式
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
<?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
">

<bean id="user" class="springTest12.UserDaoImpl"></bean>
<bean id="userProxy" class="springTest12.UserProxy"></bean>

<aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>

<aop:config>
<aop:pointcut id="p" expression="execution(* springTest12.UserDao.show(..))"/>

<aop:aspect ref="userProxy" order="1">
<aop:before method="before" pointcut-ref="p" ></aop:before>

</aop:aspect>


</aop:config>

</beans>

JDBCTemplate模块

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
24
25
26
27
28
29
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:context="http://www.springframework.org/schema/aop"
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
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd

">

<context:component-scan base-package="springTest14"></context:component-scan>

<util:properties id="prop" location="jdbc.properties" local-override="true"></util:properties>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
<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>

<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>

</bean>

</beans>
  • 对于其余部分为:

    JDBCTemplate -> Dao -> Service

  • tips:针对MYSQL的URL形式

    jdbc:mysql://localhost:/

利用JDBCTemplate进行(增删改)操作
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Component
public class CustoemrDaoImpl implements CustomerDao{


@Autowired
private JdbcTemplate jdbcTemplate;


@Override
public void add(Customer cus) {
String sql = "insert into customers (id,name,email) values (?,?,?);";
int update = jdbcTemplate.update(sql,cus.getId(),cus.getName(),cus.getEmail());
System.out.println(update);
}
}

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
63
64
65
66
//`id``name``email``birth``photo``test`
public class Customer {
private int id;
private String name;
private String email;
private String birth;
private String photo;
private String test;

public Customer(int id, String name, String email) {
this.id = id;
this.name = name;
this.email = email;
}

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

public int getId() {
return id;
}

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



public String getName() {
return name;
}

public String getEmail() {
return email;
}

public String getBirth() {
return birth;
}

public String getPhoto() {
return photo;
}

public String getTest() {
return test;
}

public void setEmail(String email) {
this.email = email;
}

public void setBirth(String birth) {
this.birth = birth;
}

public void setPhoto(String photo) {
this.photo = photo;
}

public void setTest(String test) {
this.test = test;
}
}

1
2
3
4
5
public interface CustomerDao {

void add(Customer cus);
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

@Component
public class Service {

@Autowired
private CustomerDao customer;

public void addCustomer(Customer cus){
customer.add(cus);
}




}

1
2
3
4
5
6
7
8
@Test
public void test(){
ApplicationContext context =
new ClassPathXmlApplicationContext("springTest14//config.xml");
Service s = context.getBean("service",Service.class);
s.addCustomer(new Customer(1234,"ych","132@"));

}
利用JDBCTemplated对数据库进行查询操作
  • 利用JDBCTemplate封装的queyForObject函数,返回单个值

      • 第一个参数:sql语句
      • 第二个参数:返回的对象类型的class
    1
    2
    3
    4
    5
    6
    @Override
    public void selectSet(Customer cus) {
    String sql = "select count(*) from customers";
    Integer res = jdbcTemplate.queryForObject(sql,Integer.class);
    System.out.println(res);
    }
      • 第一个参数:sql语句
      • 第二个参数:
        • 实现类RowMapper的接口的类(ex:BeanPropertyRowMapper)
        • 模板类别为数据库返回类型的类别
      • 第三个参数:填充参数
    1
    2
    3
    4
    5
    6
    @Override
    public void getTuple(String name) {
    String sql = "select * from customers where name=?;";
    Customer cus = jdbcTemplate.queryForObject(sql,new BeanPropertyRowMapper<Customer>(Customer.class),name);
    System.out.println(cus.getName());
    }
      • 第一个参数:sql语句
      • 第二个参数:RowMapper的接口实现类
      • 第三个参数:填充字符
    1
    2
    3
    4
    5
    6
    7
    @Override
    public void findTuples() {
    String sql = "select * from customers;";
    List<Customer> customerList = jdbcTemplate.query(sql,new BeanPropertyRowMapper<Customer>(Customer.class));
    for(Customer cus : customerList)
    System.out.println(cus.getName());
    }
利用JDBCTemplate实现批量操作
  • 一个Object数组对象为一个元组,一个Objecr对象为一个属性

    1
    2
    3
    4
    5
    6
    @Override
    public void addBatch(List<Object[]> list) {
    String sql = "insert into customers (id) values (?);";
    int res[] = jdbcTemplate.batchUpdate(sql,list);
    System.out.println(Arrays.toString(res));
    }
利用JBDCTemplate实现事物管理
  • 事物是数据库操作的基本单元,逻辑上的一组操作

    • 原子性
    • 一致性
    • 分离性
    • 持久性
    • 事物一般添加到Service层(WEB层,Service层,Dao层)
    • 编程式事物管理(不推荐)
    • 声明式事物管理(底层使用了AOP的模式)
      1. xml方式
      2. 注解方式
基于注解的事务管理
    • 引入tx的命名空间

    • 声明事物控制器的bean模块,并注入dataSource

    • 通过事物控制器打开注解驱动

    • 在事物类上或事物的方法上添加事物注解

      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
      <?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:tx="http://www.springframework.org/schema/tx"
      xmlns:util="http://www.springframework.org/schema/util"
      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/util http://www.springframework.org/schema/util/spring-util.xsd
      http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd

      ">
      <context:component-scan base-package="springTest15"></context:component-scan>
      <util:properties id="prop" local-override="true" location="jdbc.properties"></util:properties>
      <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
      <property name="url" value="#{prop.url}"></property>
      <property name="username" value="#{prop.username}"></property>
      <property name="password" value="#{prop.password}"></property>
      <property name="driverClassName" value="#{prop.driverClassName}"></property>
      </bean>

      <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
      <property name="dataSource" ref="dataSource"></property>
      </bean>
      /////////////////////////////////////////////////////////////////////////////////////////////////////////
      <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>
      <!--


      url=jdbc:mysql://localhost:3307/test
      username=root
      password=ych3362632
      driverClassName=com.mysql.jdbc.Driver


      -->
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      @Component
      @Transactional
      public class UserService {
      @Autowired
      private UserDao customer;

      private void addMoney(String name,int m){
      customer.addMoney(name,m);
      }

      private void relasMoney(String name,int m){
      customer.relasMoney(name,m);

      }

      public void getPostMoney(String name1,String name2,int m){
      addMoney(name2,m);
      int e = 10 / 0;
      relasMoney(name1,m);

      }

      }

    • propgation:传播行为

    • ioslation:事物的隔离级别:

      1. 【错误】脏读:一个未提交的事物读取了另一个未提交的事物(当被读的事物发生了rollback则导致数据不正确)

      2. 【现象非问题】幻读:一个未提交的事物读取了另一个事物添加的数据

      3. 【现象非问题】不可重复读:一个未提交的事物读取了另一个事物已经提交的数据

      设置隔离级别:

      脏读 不可重复读 幻读
      READ UNCOMMITTED(读未提交)
      READ COMMITTED(读已提交) ×
      REPEATABLE READ(可重复读)【MySQL默认】 × ×
      SERILIZABLE(串行化) × × ×
    • timeout:超时时间:

      1. 事物需要在一定的时间内进行提交,如果不提交则进行回滚
      2. 默认值-1(不超时),设置时间以秒为单位
    • readOnly:是否只读:

      1. readOnly默认值为false,可进行增删改查
      2. 若设置为true,则只能查询
    • rollbackFor:设置出现哪些异常进行回滚

    • noRollbackFor:设置出现哪些异常不进行回滚

基于xml的事物管理
  • 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
    <?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:tx="http://www.springframework.org/schema/tx"
    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/aop http://www.springframework.org/schema/aop/spring-aop.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
    http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd
    http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd


    ">
    <util:properties id="prop" location="jdbc.properties" local-override="true"></util:properties>
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
    <property name="url" value="#{prop.url}"></property>
    <property name="driverClassName" value="#{prop.driverClassName}"></property>
    <property name="password" value="#{prop.password}"></property>
    <property name="username" value="#{prop.username}"></property>
    </bean>

    <context:component-scan base-package="springTest16"></context:component-scan>

    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    <property name="dataSource" ref="dataSource"></property>
    </bean>

    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"></property>
    </bean>

    <tx:advice id="txadvice">
    <tx:attributes>
    <tx:method name="getPostMoney" propagation="REQUIRED"/>
    </tx:attributes>

    </tx:advice>

    <aop:config>
    <aop:pointcut id="pt" expression="execution(* springTest16.UserService.getPostMoney(..))"/>
    <aop:advisor advice-ref="txadvice" pointcut-ref="pt"></aop:advisor>
    </aop:config>

    </beans>
完全注解开发
    • 创建配置类
    • 填充配置函数
    • 完成配置
    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

    @Configuration
    @ComponentScan(basePackages = {"springTest17"})
    @EnableTransactionManagement
    public class Config {

    @Bean
    public DruidDataSource getDataSource(){
    DruidDataSource dataSource = new DruidDataSource();
    Properties prop = new Properties();
    FileInputStream fis = null;
    try {
    fis = new FileInputStream("src//jdbc.properties");
    prop.load(fis);
    dataSource.setUrl(prop.getProperty("url"));
    dataSource.setUsername(prop.getProperty("username"));
    dataSource.setPassword(prop.getProperty("password"));
    dataSource.setDriverClassName(prop.getProperty("driverClassName"));




    } catch (IOException e) {
    e.printStackTrace();
    }finally {
    try {
    fis.close();
    } catch (IOException e) {
    e.printStackTrace();
    }
    return dataSource;
    }


    }


    @Bean
    public JdbcTemplate getJdbcTemplate(){
    JdbcTemplate jdbcTemplate = new JdbcTemplate();
    jdbcTemplate.setDataSource(getDataSource());
    return jdbcTemplate;
    }

    @Bean
    public DataSourceTransactionManager getDataSourceTransactionManager(){
    DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
    dataSourceTransactionManager.setDataSource(getDataSource());
    return dataSourceTransactionManager;
    }

    }

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16

    @Component
    public class UserDaoImpl implements UserDao{

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Override
    public void show() {
    String sql = "select * from customers;";
    List<User> list = jdbcTemplate.query(sql,new BeanPropertyRowMapper<User>(User.class));
    for(User user : list)
    System.out.println(user.getName());
    }
    }


补充

工厂模式

普通模式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class UserService{
public void execute(){
User user = new User();
user.add();
}
}
class UserDao{
public void add(){
System.out.println("hello world!");
}
}
/*
该模式缺点:
UserService和User类的耦合度太高
需要利用工厂模式进行解耦合

*/

工厂模式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class UserService{
public void execute(){
User user = UserFactory.getUserDao();
user.add();
}
}
//UserFatory使用工厂模式降低UserService和UserDao的耦合度
class UserFactory{
public static getUserDao(){
return new UserDao();
}
}

class UserDao{
public void add(){
System.out.println("hello world!");
}
}

/*
通过工厂模式,使得UserService和User的耦合度进一步降低(但是并未降到最低)
另外UserFactory和User的耦合度依然很高

*/

在工厂模式的情况下进一步解耦合

1
2
3
4
5
6
7
8
//利用反射进一步解耦合
class UserFactory{
public static UserDao getUserDao(){
String classValue = class属性值; //通过xml解析得到
Class clazz = Clazz.forName(classValue);
return (UserDao)clazz.newInstance();
}
}

注解

动态代理

  1. 有接口的动态代理(JDK动态代理)

    • 通过实现接口类的方法来增强类的对象

  2. 无接口的动态代理(CGLIB动态代理)

    • 通过实现子类的方法来增强类